[Ocfs2-tools-commits] zab commits r289 - in trunk: fsck.ocfs2
fsck.ocfs2/include libocfs2
svn-commits at oss.oracle.com
svn-commits at oss.oracle.com
Wed Sep 29 18:57:01 CDT 2004
Author: zab
Date: 2004-09-29 18:56:59 -0500 (Wed, 29 Sep 2004)
New Revision: 289
Added:
trunk/fsck.ocfs2/dirparents.c
trunk/fsck.ocfs2/include/dirparents.h
Modified:
trunk/fsck.ocfs2/Makefile
trunk/fsck.ocfs2/dirblocks.c
trunk/fsck.ocfs2/fsck.c
trunk/fsck.ocfs2/include/fsck.h
trunk/fsck.ocfs2/pass1.c
trunk/fsck.ocfs2/pass2.c
trunk/libocfs2/ocfs2_err.et.in
Log:
o add tracking of directory linkage to pass 1 and 2
o detect and fix multiple dirs thinking they are the parent of a dir inode
o get rid of the unused ABORT handling
o add an INTERNAL_FAILURE et error for when our logic goes south
Modified: trunk/fsck.ocfs2/Makefile
===================================================================
--- trunk/fsck.ocfs2/Makefile 2004-09-29 23:55:02 UTC (rev 288)
+++ trunk/fsck.ocfs2/Makefile 2004-09-29 23:56:59 UTC (rev 289)
@@ -22,10 +22,24 @@
DEFINES += -D__ILP32__
endif
-CFILES = fsck.c dirblocks.c icount.c pass1.c pass2.c problem.c util.c
-HFILES = include/fsck.h include/dirblocks.h include/icount.h include/pass1.h \
- include/pass2.h include/problem.h include/util.h
+CFILES = fsck.c \
+ dirblocks.c \
+ dirparents.c \
+ icount.c \
+ pass1.c \
+ pass2.c \
+ problem.c \
+ util.c
+HFILES = include/fsck.h \
+ include/dirblocks.h \
+ include/dirparents.h \
+ include/icount.h \
+ include/pass1.h \
+ include/pass2.h \
+ include/problem.h \
+ include/util.h
+
OBJS = $(subst .c,.o,$(CFILES))
VERSION_FILES = $(CFILES) $(HFILES)
Modified: trunk/fsck.ocfs2/dirblocks.c
===================================================================
--- trunk/fsck.ocfs2/dirblocks.c 2004-09-29 23:55:02 UTC (rev 288)
+++ trunk/fsck.ocfs2/dirblocks.c 2004-09-29 23:56:59 UTC (rev 289)
@@ -42,7 +42,7 @@
{
struct rb_node ** p = &db->db_root.rb_node;
struct rb_node * parent = NULL;
- o2fsck_dirblock_entry *dbe, *tmp_dbe;;
+ o2fsck_dirblock_entry *dbe, *tmp_dbe;
dbe = calloc(1, sizeof(*dbe));
if (dbe == NULL)
Added: trunk/fsck.ocfs2/dirparents.c
===================================================================
--- trunk/fsck.ocfs2/dirparents.c 2004-09-29 23:55:02 UTC (rev 288)
+++ trunk/fsck.ocfs2/dirparents.c 2004-09-29 23:56:59 UTC (rev 289)
@@ -0,0 +1,93 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * dirparents.c
+ *
+ * As always, we let e2fsck lead the way. A bitmap for
+ * inodes with a single i_count (the vast majority), and a
+ * tree of inode numbers with a greater count.
+ *
+ * Copyright (C) 2004 Oracle. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License, version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ *
+ * Authors: Zach Brown
+ */
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "ocfs2.h"
+
+#include "fsck.h"
+#include "dirparents.h"
+#include "util.h"
+
+/* XXX callers are supposed to make sure they don't call with dup inodes.
+ * we'll see. */
+void o2fsck_add_dir_parent(struct rb_root *root, uint64_t ino, uint64_t dot_dot,
+ uint64_t dirent)
+{
+ struct rb_node ** p = &root->rb_node;
+ struct rb_node * parent = NULL;
+ o2fsck_dir_parent *dp, *tmp_dp;
+
+ dp = calloc(1, sizeof(*dp));
+ if (dp == NULL)
+ fatal_error(OCFS2_ET_NO_MEMORY,
+ "while allocating directory entries");
+
+ dp->dp_ino = ino;
+ dp->dp_dot_dot = dot_dot;
+ dp->dp_dirent = dirent;
+
+ while (*p)
+ {
+ parent = *p;
+ tmp_dp = rb_entry(parent, o2fsck_dir_parent, dp_node);
+
+ if (dp->dp_ino < tmp_dp->dp_ino)
+ p = &(*p)->rb_left;
+ else if (dp->dp_ino > tmp_dp->dp_ino)
+ p = &(*p)->rb_right;
+ else
+ fatal_error(OCFS2_ET_INTERNAL_FAILURE, "while adding "
+ "unique dir parent tracking for dir inode "
+ "%"PRIu64, ino);
+ }
+
+ rb_link_node(&dp->dp_node, parent, p);
+ rb_insert_color(&dp->dp_node, root);
+}
+
+o2fsck_dir_parent *o2fsck_dir_parent_lookup(struct rb_root *root, uint64_t ino)
+{
+ struct rb_node *node = root->rb_node;
+ o2fsck_dir_parent *dp;
+
+ while (node) {
+ dp = rb_entry(node, o2fsck_dir_parent, dp_node);
+
+ if (ino < dp->dp_ino)
+ node = node->rb_left;
+ else if (ino > dp->dp_ino)
+ node = node->rb_right;
+ else
+ return dp;
+ }
+ return NULL;
+}
+
Modified: trunk/fsck.ocfs2/fsck.c
===================================================================
--- trunk/fsck.ocfs2/fsck.c 2004-09-29 23:55:02 UTC (rev 288)
+++ trunk/fsck.ocfs2/fsck.c 2004-09-29 23:56:59 UTC (rev 289)
@@ -142,6 +142,7 @@
memset(ost, 0, sizeof(o2fsck_state));
ost->ost_ask = 1;
ost->ost_dirblocks.db_root = RB_ROOT;
+ ost->ost_dir_parents = RB_ROOT;
/* These mean "autodetect" */
blksize = 0;
Added: trunk/fsck.ocfs2/include/dirparents.h
===================================================================
--- trunk/fsck.ocfs2/include/dirparents.h 2004-09-29 23:55:02 UTC (rev 288)
+++ trunk/fsck.ocfs2/include/dirparents.h 2004-09-29 23:56:59 UTC (rev 289)
@@ -0,0 +1,44 @@
+/*
+ * dirparents.h
+ *
+ * Copyright (C) 2002 Oracle Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ *
+ * Author: Zach Brown
+ */
+
+#ifndef __O2FSCK_DIRPARENTS_H__
+#define __O2FSCK_DIRPARENTS_H__
+
+typedef struct _o2fsck_dir_parent {
+ struct rb_node dp_node;
+ uint64_t dp_ino; /* The dir inode in question. */
+
+ uint64_t dp_dot_dot; /* The parent according to the dir's own
+ * '..' entry */
+
+ uint64_t dp_dirent; /* The inode that has a dirent which points
+ * to this directory. */
+} o2fsck_dir_parent;
+
+void o2fsck_add_dir_parent(struct rb_root *root, uint64_t ino,
+ uint64_t dot_dot, uint64_t dirent);
+
+o2fsck_dir_parent *o2fsck_dir_parent_lookup(struct rb_root *root,
+ uint64_t ino);
+#endif /* __O2FSCK_DIRPARENTS_H__ */
+
Modified: trunk/fsck.ocfs2/include/fsck.h
===================================================================
--- trunk/fsck.ocfs2/include/fsck.h 2004-09-29 23:55:02 UTC (rev 288)
+++ trunk/fsck.ocfs2/include/fsck.h 2004-09-29 23:56:59 UTC (rev 289)
@@ -43,6 +43,8 @@
o2fsck_dirblocks ost_dirblocks;
+ struct rb_root ost_dir_parents;
+
/* flags */
unsigned ost_ask:1, /* confirm with the user */
ost_answer:1, /* answer if we don't ask the user */
Modified: trunk/fsck.ocfs2/pass1.c
===================================================================
--- trunk/fsck.ocfs2/pass1.c 2004-09-29 23:55:02 UTC (rev 288)
+++ trunk/fsck.ocfs2/pass1.c 2004-09-29 23:56:59 UTC (rev 289)
@@ -30,6 +30,7 @@
#include "ocfs2.h"
#include "dirblocks.h"
+#include "dirparents.h"
#include "icount.h"
#include "fsck.h"
#include "pass1.h"
@@ -108,6 +109,7 @@
if (S_ISDIR(di->i_mode)) {
/* XXX record dir for dir block walk */
ocfs2_bitmap_set(ost->ost_dir_inodes, blkno, NULL);
+ o2fsck_add_dir_parent(&ost->ost_dir_parents, blkno, 0, 0);
} else if (S_ISREG(di->i_mode)) {
ocfs2_bitmap_set(ost->ost_reg_inodes, blkno, NULL);
} else if (S_ISLNK(di->i_mode)) {
Modified: trunk/fsck.ocfs2/pass2.c
===================================================================
--- trunk/fsck.ocfs2/pass2.c 2004-09-29 23:55:02 UTC (rev 288)
+++ trunk/fsck.ocfs2/pass2.c 2004-09-29 23:56:59 UTC (rev 289)
@@ -29,6 +29,7 @@
#include "ocfs2.h"
+#include "dirparents.h"
#include "icount.h"
#include "fsck.h"
#include "pass2.h"
@@ -52,23 +53,28 @@
return dirent->name[0] == '.';
}
+static int expected_dots(o2fsck_dirblock_entry *dbe, int offset)
+{
+ if (dbe->e_blkcount == 0) {
+ if (offset == 0)
+ return 1;
+ if (offset == OCFS2_DIR_REC_LEN(1))
+ return 2;
+ }
+
+ return 0;
+}
+
/* XXX this needs much stronger messages */
static int fix_dirent_dots(o2fsck_state *ost, o2fsck_dirblock_entry *dbe,
struct ocfs2_dir_entry *dirent, int offset,
int left)
{
- int expect_dots = 0;
+ int expect_dots = expected_dots(dbe, offset);
int ret_flags = 0, changed_len = 0;
struct ocfs2_dir_entry *next;
uint16_t new_len;
- if (dbe->e_blkcount == 0) {
- if (offset == 0)
- expect_dots = 1;
- if (offset == OCFS2_DIR_REC_LEN(1))
- expect_dots = 2;
- }
-
if (!expect_dots) {
if (!dirent_has_dots(dirent, 1) && !dirent_has_dots(dirent, 2))
return 0;
@@ -90,13 +96,21 @@
ret_flags = OCFS2_DIRENT_CHANGED;
}
- /*
- * We don't have the parent inode for .. so we don't check it yet.
- * It is reasonable for ..'s rec_len to go to the end of the
- * block for an empty directory, .'s can't because .. is next.
- */
- if (expect_dots == 2)
+ /* we only record where .. points for now and that ends the
+ * checks for .. */
+ if (expect_dots == 2) {
+ o2fsck_dir_parent *dp;
+ dp = o2fsck_dir_parent_lookup(&ost->ost_dir_parents,
+ dbe->e_ino);
+ if (dp == NULL)
+ fatal_error(OCFS2_ET_INTERNAL_FAILURE,
+ "no dir parents for '..' entry for "
+ "inode %"PRIu64, dbe->e_ino);
+
+ dp->dp_dot_dot = dirent->inode;
+
return ret_flags;
+ }
if ((dirent->inode != dbe->e_ino) &&
should_fix(ost, FIX_DEFYES, "invalid . directory, replace?")) {
@@ -201,6 +215,52 @@
return ret_flags;
}
+static int fix_dirent_linkage(o2fsck_state *ost, o2fsck_dirblock_entry *dbe,
+ struct ocfs2_dir_entry *dirent, int offset)
+{
+ int expect_dots = expected_dots(dbe, offset);
+ o2fsck_dir_parent *dp;
+ errcode_t err;
+ int is_dir;
+
+ /* we already took care of special-casing the dots */
+ if (expect_dots)
+ return 0;
+
+ /* we're only checking the linkage if we already found the dir
+ * this inode claims to be pointing to */
+ err = ocfs2_bitmap_test(ost->ost_dir_inodes, dirent->inode, &is_dir);
+ if (err)
+ fatal_error(err, "while checking for inode %"PRIu64" in the "
+ "dir bitmap", dirent->inode);
+ if (!is_dir)
+ return 0;
+
+ dp = o2fsck_dir_parent_lookup(&ost->ost_dir_parents, dirent->inode);
+ if (dp == NULL)
+ fatal_error(OCFS2_ET_INTERNAL_FAILURE, "no dir parents for "
+ "'..' entry for inode %"PRIu64, dbe->e_ino);
+
+ /* if no dirents have pointed to this inode yet we record ours
+ * as the first and move on */
+ if (dp->dp_dirent == 0) {
+ dp->dp_dirent = dbe->e_ino;
+ return 0;
+ }
+
+ if (should_fix(ost, 0, "directory inode %"PRIu64" is not the first to "
+ "claim to be the parent of subdir '%*s' (%"PRIu64"). Forget "
+ "this linkage and leave the previous parent of '%*s' intact?",
+ dbe->e_ino, dirent->name_len, dirent->name, dirent->inode,
+ dirent->name_len, dirent->name)) {
+
+ dirent->inode = 0;
+ return OCFS2_DIRENT_CHANGED;
+ }
+
+ return 0;
+}
+
/* this could certainly be more clever to issue reads in groups */
static unsigned pass2_dir_block_iterate(o2fsck_dirblock_entry *dbe,
void *priv_data)
@@ -240,18 +300,13 @@
if (this_flags & OCFS2_DIRENT_CHANGED)
continue;
- if (ret_flags & OCFS2_DIRENT_ABORT)
- break;
-
ret_flags |= fix_dirent_dots(dd->ost, dbe, dirent, offset,
dd->fs->fs_blocksize - offset);
- if (ret_flags & OCFS2_DIRENT_ABORT)
- break;
ret_flags |= fix_dirent_name(dd->ost, dbe, dirent, offset);
- if (ret_flags & OCFS2_DIRENT_ABORT)
- break;
+ ret_flags |= fix_dirent_linkage(dd->ost, dbe, dirent, offset);
+
offset += dirent->rec_len;
prev = dirent;
}
@@ -262,6 +317,7 @@
errcode_t o2fsck_pass2(o2fsck_state *ost)
{
errcode_t retval;
+ o2fsck_dir_parent *dp;
struct dirblock_data dd = {
.ost = ost,
.fs = ost->ost_fs,
@@ -271,6 +327,17 @@
if (retval)
return retval;
+ /*
+ * Mark the root directory's dirent parent as itself if we found the
+ * inode during inode scanning. The dir will be created in pass3
+ * if it didn't exist already. XXX we should do this for our other
+ * magical directories.
+ */
+ dp = o2fsck_dir_parent_lookup(&ost->ost_dir_parents,
+ ost->ost_fs->fs_root_blkno);
+ if (dp)
+ dp->dp_dirent = ost->ost_fs->fs_root_blkno;
+
o2fsck_dir_block_iterate(&ost->ost_dirblocks, pass2_dir_block_iterate,
&dd);
ocfs2_free(&dd.buf);
Modified: trunk/libocfs2/ocfs2_err.et.in
===================================================================
--- trunk/libocfs2/ocfs2_err.et.in 2004-09-29 23:55:02 UTC (rev 288)
+++ trunk/libocfs2/ocfs2_err.et.in 2004-09-29 23:56:59 UTC (rev 289)
@@ -83,4 +83,7 @@
ec OCFS2_ET_INVALID_BIT,
"Bit does not exist in bitmap range"
+ec OCFS2_ET_INTERNAL_FAILURE,
+ "Internal logic faliure"
+
end
More information about the Ocfs2-tools-commits
mailing list