[Ocfs2-tools-commits] zab commits r463 - in trunk/fsck.ocfs2: . include

svn-commits at oss.oracle.com svn-commits at oss.oracle.com
Sat Dec 4 19:28:06 CST 2004


Author: zab
Date: 2004-12-04 19:28:04 -0600 (Sat, 04 Dec 2004)
New Revision: 463

Modified:
   trunk/fsck.ocfs2/dirblocks.c
   trunk/fsck.ocfs2/dirparents.c
   trunk/fsck.ocfs2/fsck.c
   trunk/fsck.ocfs2/icount.c
   trunk/fsck.ocfs2/include/dirblocks.h
   trunk/fsck.ocfs2/include/dirparents.h
   trunk/fsck.ocfs2/include/icount.h
   trunk/fsck.ocfs2/include/util.h
   trunk/fsck.ocfs2/pass1.c
   trunk/fsck.ocfs2/pass2.c
   trunk/fsck.ocfs2/pass3.c
Log:
o kill fatal_error and bubble up errcode_ts instead.  this nicely lead to
  checking some errors that weren't going unchecked, fixing up some awkward
  constructs in pass2, and now passes 2 and 3 return real errors to fsck.c


Modified: trunk/fsck.ocfs2/dirblocks.c
===================================================================
--- trunk/fsck.ocfs2/dirblocks.c	2004-12-04 20:38:44 UTC (rev 462)
+++ trunk/fsck.ocfs2/dirblocks.c	2004-12-05 01:28:04 UTC (rev 463)
@@ -34,17 +34,19 @@
 #include "dirblocks.h"
 #include "util.h"
 
-void o2fsck_add_dir_block(o2fsck_dirblocks *db, uint64_t ino, uint64_t blkno, 
-			uint64_t blkcount)
+errcode_t o2fsck_add_dir_block(o2fsck_dirblocks *db, uint64_t ino,
+			       uint64_t blkno, uint64_t blkcount)
 {
 	struct rb_node ** p = &db->db_root.rb_node;
 	struct rb_node * parent = NULL;
 	o2fsck_dirblock_entry *dbe, *tmp_dbe;
+	errcode_t ret = 0;
 
 	dbe = calloc(1, sizeof(*dbe));
-	if (dbe == NULL)
-		fatal_error(OCFS2_ET_NO_MEMORY, 
-				"while allocating directory entries");
+	if (dbe == NULL) {
+		ret = OCFS2_ET_NO_MEMORY;
+		goto out;
+	}
 
 	dbe->e_ino = ino;
 	dbe->e_blkno = blkno;
@@ -63,6 +65,9 @@
 
 	rb_link_node(&dbe->e_node, parent, p);
 	rb_insert_color(&dbe->e_node, &db->db_root);
+
+out:
+	return ret;
 }
 
 void o2fsck_dir_block_iterate(o2fsck_dirblocks *db, dirblock_iterator func,

Modified: trunk/fsck.ocfs2/dirparents.c
===================================================================
--- trunk/fsck.ocfs2/dirparents.c	2004-12-04 20:38:44 UTC (rev 462)
+++ trunk/fsck.ocfs2/dirparents.c	2004-12-05 01:28:04 UTC (rev 463)
@@ -37,17 +37,21 @@
 
 /* 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)
+errcode_t 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;
+	errcode_t ret = 0;
 
 	dp = calloc(1, sizeof(*dp));
-	if (dp == NULL)
-		fatal_error(OCFS2_ET_NO_MEMORY, 
-				"while allocating directory entries");
+	if (dp == NULL) {
+		ret = OCFS2_ET_NO_MEMORY;
+		goto out;
+	}
 
 	dp->dp_ino = ino;
 	dp->dp_dot_dot = dot_dot;
@@ -64,14 +68,16 @@
 			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);
+		else {
+			ret = OCFS2_ET_INTERNAL_FAILURE;
+			goto out;
+		}
 	}
 
 	rb_link_node(&dp->dp_node, parent, p);
 	rb_insert_color(&dp->dp_node, root);
+out:
+	return ret;
 }
 
 o2fsck_dir_parent *o2fsck_dir_parent_lookup(struct rb_root *root, uint64_t ino)

Modified: trunk/fsck.ocfs2/fsck.c
===================================================================
--- trunk/fsck.ocfs2/fsck.c	2004-12-04 20:38:44 UTC (rev 462)
+++ trunk/fsck.ocfs2/fsck.c	2004-12-05 01:28:04 UTC (rev 463)
@@ -36,9 +36,14 @@
  *   _should not_ write to the file system unless it has asked prompt() to do
  *   so.  It should also not exit if prompt() returns 0.  prompt() should give
  *   as much detail as possible as it becomes an error log.
- * - to make life simpler, memory allocation is a fatal error.  We should
- *   have reasonable memory demands in relation to the size of the fs.
- * - I'm still of mixed opinions about IO errors.  thoughts?
+ * - to make life simpler, memory allocation is a fatal error.  It would be
+ *   very exciting to have allocation failure trick fsck -y into tearing
+ *   apart the fs because it didn't have memorty to track what was in use.  
+ *   We should have reasonable memory demands in relation to the size of 
+ *   the fs.
+ * - I'm still of mixed opinions about IO errors.  For now they're fatal.
+ *   One needs to dd a volume off a busted device before fixing it.
+ *   thoughts?
  */
 #include <getopt.h>
 #include <limits.h>

Modified: trunk/fsck.ocfs2/icount.c
===================================================================
--- trunk/fsck.ocfs2/icount.c	2004-12-04 20:38:44 UTC (rev 462)
+++ trunk/fsck.ocfs2/icount.c	2004-12-05 01:28:04 UTC (rev 463)
@@ -87,10 +87,11 @@
 }
 
 /* keep it simple for now by always updating both data structures */
-void o2fsck_icount_set(o2fsck_icount *icount, uint64_t blkno, 
-			uint16_t count)
+errcode_t o2fsck_icount_set(o2fsck_icount *icount, uint64_t blkno, 
+			    uint16_t count)
 {
 	icount_node *in;
+	errcode_t ret = 0;
 
 	if (count == 1)
 		ocfs2_bitmap_set(icount->ic_single_bm, blkno, NULL);
@@ -107,14 +108,18 @@
 		}
 	} else if (count > 1) {
 		in = calloc(1, sizeof(*in));
-		if (in == NULL)
-			fatal_error(OCFS2_ET_NO_MEMORY, 
-				    "while allocating to track icount");
+		if (in == NULL) {
+			ret = OCFS2_ET_NO_MEMORY;
+			goto out;
+		}
 
 		in->in_blkno = blkno;
 		in->in_icount = count;
 		icount_insert(icount, in);
 	}
+
+out:
+	return ret;
 }
 
 uint16_t o2fsck_icount_get(o2fsck_icount *icount, uint64_t blkno)
@@ -162,9 +167,9 @@
 	}
 
 	if (prev_count + delta < 0) 
-		fatal_error(OCFS2_ET_INTERNAL_FAILURE, "while droping icount "
-			    "from %"PRIu16" bt %d for inode %"PRIu64, 
-			    prev_count, delta, blkno);
+		com_err(__FUNCTION__, OCFS2_ET_INTERNAL_FAILURE,
+		        "while droping icount from %"PRIu16" bt %d for "
+			"inode %"PRIu64, prev_count, delta, blkno);
 
 	o2fsck_icount_set(icount, blkno, prev_count + delta);
 }

Modified: trunk/fsck.ocfs2/include/dirblocks.h
===================================================================
--- trunk/fsck.ocfs2/include/dirblocks.h	2004-12-04 20:38:44 UTC (rev 462)
+++ trunk/fsck.ocfs2/include/dirblocks.h	2004-12-05 01:28:04 UTC (rev 463)
@@ -40,8 +40,8 @@
 typedef unsigned (*dirblock_iterator)(o2fsck_dirblock_entry *,
 					void *priv_data);
 
-void o2fsck_add_dir_block(o2fsck_dirblocks *db, uint64_t ino, uint64_t blkno, 
-			uint64_t blkcount);
+errcode_t o2fsck_add_dir_block(o2fsck_dirblocks *db, uint64_t ino,
+			       uint64_t blkno, uint64_t blkcount);
 
 void o2fsck_dir_block_iterate(o2fsck_dirblocks *db, dirblock_iterator func,
 				void *priv_data);

Modified: trunk/fsck.ocfs2/include/dirparents.h
===================================================================
--- trunk/fsck.ocfs2/include/dirparents.h	2004-12-04 20:38:44 UTC (rev 462)
+++ trunk/fsck.ocfs2/include/dirparents.h	2004-12-05 01:28:04 UTC (rev 463)
@@ -40,8 +40,10 @@
 	int		dp_connected;
 } o2fsck_dir_parent;
 
-void o2fsck_add_dir_parent(struct rb_root *root, uint64_t ino, 
-			uint64_t dot_dot, uint64_t dirent);
+errcode_t 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);

Modified: trunk/fsck.ocfs2/include/icount.h
===================================================================
--- trunk/fsck.ocfs2/include/icount.h	2004-12-04 20:38:44 UTC (rev 462)
+++ trunk/fsck.ocfs2/include/icount.h	2004-12-05 01:28:04 UTC (rev 463)
@@ -31,8 +31,8 @@
 	struct rb_root	ic_multiple_tree;
 } o2fsck_icount;
 
-void o2fsck_icount_set(o2fsck_icount *icount, uint64_t blkno, 
-			uint16_t count);
+errcode_t o2fsck_icount_set(o2fsck_icount *icount, uint64_t blkno, 
+			    uint16_t count);
 uint16_t o2fsck_icount_get(o2fsck_icount *icount, uint64_t blkno);
 errcode_t o2fsck_icount_new(ocfs2_filesys *fs, o2fsck_icount **ret);
 void o2fsck_icount_free(o2fsck_icount *icount);

Modified: trunk/fsck.ocfs2/include/util.h
===================================================================
--- trunk/fsck.ocfs2/include/util.h	2004-12-04 20:38:44 UTC (rev 462)
+++ trunk/fsck.ocfs2/include/util.h	2004-12-05 01:28:04 UTC (rev 463)
@@ -37,12 +37,6 @@
 #define FSCK_CANCELED    32     /* Aborted with a signal or ^C */
 #define FSCK_LIBRARY     128    /* Shared library error */
 
-/* no va_list variant of com_err */
-#define fatal_error(errcode, fmt...) do {				\
-	com_err("o2fsck", errcode, fmt);				\
-	exit(FSCK_ERROR);						\
-} while (0)
-
 void o2fsck_write_inode(o2fsck_state *ost, uint64_t blkno, ocfs2_dinode *di);
 void o2fsck_mark_cluster_allocated(o2fsck_state *ost, uint32_t cluster);
 void o2fsck_mark_clusters_allocated(o2fsck_state *ost, uint32_t cluster,

Modified: trunk/fsck.ocfs2/pass1.c
===================================================================
--- trunk/fsck.ocfs2/pass1.c	2004-12-04 20:38:44 UTC (rev 462)
+++ trunk/fsck.ocfs2/pass1.c	2004-12-05 01:28:04 UTC (rev 463)
@@ -418,6 +418,7 @@
        int		vb_errors;
        o2fsck_state 	*vb_ost;
        ocfs2_dinode	*vb_di;
+       errcode_t	vb_ret;
 };
 
 /* last_block and num_blocks would be different in a sparse file */
@@ -428,25 +429,27 @@
 		vb->vb_last_block = bcount;
 }
 
-static void process_link_block(struct verifying_blocks *vb, uint64_t blkno)
+static errcode_t process_link_block(struct verifying_blocks *vb,
+				    uint64_t blkno)
 {
 	char *buf, *null;
-	errcode_t ret;
+	errcode_t ret = 0;
 	unsigned int blocksize = vb->vb_ost->ost_fs->fs_blocksize;
 
 	if (vb->vb_saw_link_null)
-		return;
+		goto out;
 
 	ret = ocfs2_malloc_blocks(vb->vb_ost->ost_fs->fs_io, 1, &buf);
-	if (ret)
-		fatal_error(ret, "while allocating room to read a block of "
-				 "link data");
-
-	ret = io_read_block(vb->vb_ost->ost_fs->fs_io, blkno, 1, buf);
 	if (ret) {
+		com_err(whoami, ret, "while allocating room to read a block "
+			"of link data");
 		goto out;
 	}
 
+	ret = io_read_block(vb->vb_ost->ost_fs->fs_io, blkno, 1, buf);
+	if (ret)
+		goto out;
+
 	null = memchr(buf, 0, blocksize);
 	if (null != NULL) {
 		vb->vb_link_len += null - buf;
@@ -457,6 +460,7 @@
 
 out:
 	ocfs2_free(&buf);
+	return ret;
 }
 
 static void check_link_data(struct verifying_blocks *vb)
@@ -524,6 +528,7 @@
 	struct verifying_blocks *vb = priv_data;
 	ocfs2_dinode *di = vb->vb_di;
 	o2fsck_state *ost = vb->vb_ost;
+	errcode_t ret = 0;
 	
 	/* someday we may want to worry about holes in files here */
 
@@ -551,13 +556,20 @@
 
 	if (S_ISDIR(di->i_mode)) {
 		verbosef("adding dir block %"PRIu64"\n", blkno);
-		o2fsck_add_dir_block(&ost->ost_dirblocks, di->i_blkno, blkno,
-					bcount);
+		ret = o2fsck_add_dir_block(&ost->ost_dirblocks, di->i_blkno,
+					   blkno, bcount);
+		if (ret) {
+			com_err(whoami, ret, "while trying to track block in "
+				"directory inode %"PRIu64, di->i_blkno);
+		}
+	} else if (S_ISLNK(di->i_mode))
+		ret = process_link_block(vb, blkno);
+
+	if (ret) {
+		vb->vb_ret = ret;
+		return OCFS2_BLOCK_ABORT;
 	}
 
-	if (S_ISLNK(di->i_mode))
-		process_link_block(vb, blkno);
-
 	vb_saw_block(vb, bcount);
 
 	return 0;
@@ -579,16 +591,16 @@
 }
 
 
-static void o2fsck_check_blocks(ocfs2_filesys *fs, o2fsck_state *ost,
-				uint64_t blkno, ocfs2_dinode *di)
+static errcode_t o2fsck_check_blocks(ocfs2_filesys *fs, o2fsck_state *ost,
+				     uint64_t blkno, ocfs2_dinode *di)
 {
-	struct verifying_blocks vb = {0, };
 	uint64_t expected = 0;
 	errcode_t ret;
+	struct verifying_blocks vb = {
+		.vb_ost = ost,
+		.vb_di = di,
+	};
 
-	vb.vb_ost = ost;
-	vb.vb_di = di;
-
 	if (di->i_flags & OCFS2_LOCAL_ALLOC_FL)
 		ret = 0;
 	else if (di->i_flags & OCFS2_CHAIN_FL)
@@ -598,11 +610,14 @@
 		if (ret == 0)
 			ret = ocfs2_block_iterate_inode(fs, di, 0,
 							verify_block, &vb);
+		if (vb.vb_ret)
+			ret = vb.vb_ret;
 	}
 
 	if (ret) {
-		fatal_error(ret, "while iterating over the blocks for inode "
-			         "%"PRIu64, di->i_blkno);	
+		com_err(whoami, ret, "while iterating over the blocks for "
+			"inode %"PRIu64, di->i_blkno);	
+		goto out;
 	}
 
 	if (S_ISLNK(di->i_mode))
@@ -654,6 +669,8 @@
 		di->i_clusters = expected;
 		o2fsck_write_inode(ost, blkno, di);
 	}
+out:
+	return ret;
 }
 
 static void sync_local_bitmap(o2fsck_state *ost, ocfs2_dinode *di,
@@ -991,8 +1008,7 @@
 
 	ret = ocfs2_malloc_block(fs->fs_io, &buf);
 	if (ret) {
-		com_err(whoami, ret,
-			"while allocating inode buffer");
+		com_err(whoami, ret, "while allocating inode buffer");
 		goto out;
 	}
 
@@ -1000,8 +1016,7 @@
 
 	ret = ocfs2_open_inode_scan(fs, &scan);
 	if (ret) {
-		com_err(whoami, ret,
-			"while opening inode scan");
+		com_err(whoami, ret, "while opening inode scan");
 		goto out_free;
 	}
 
@@ -1032,8 +1047,11 @@
 			if (di->i_flags & OCFS2_VALID_FL)
 				o2fsck_verify_inode_fields(fs, ost, blkno, di);
 
-			if (di->i_flags & OCFS2_VALID_FL)
-				o2fsck_check_blocks(fs, ost, blkno, di);
+			if (di->i_flags & OCFS2_VALID_FL) {
+				ret = o2fsck_check_blocks(fs, ost, blkno, di);
+				if (ret)
+					goto out;
+			}
 
 			valid = di->i_flags & OCFS2_VALID_FL;
 		}
@@ -1051,5 +1069,5 @@
 	ocfs2_free(&buf);
 
 out:
-	return 0;
+	return ret;
 }

Modified: trunk/fsck.ocfs2/pass2.c
===================================================================
--- trunk/fsck.ocfs2/pass2.c	2004-12-04 20:38:44 UTC (rev 462)
+++ trunk/fsck.ocfs2/pass2.c	2004-12-05 01:28:04 UTC (rev 463)
@@ -69,6 +69,7 @@
 	o2fsck_state *ost;
 	ocfs2_filesys *fs;
 	char *buf;
+	errcode_t	ret;
 };
 
 static int dirent_has_dots(struct ocfs2_dir_entry *dirent, int num_dots)
@@ -94,22 +95,25 @@
 	return 0;
 }
 
-static int fix_dirent_dots(o2fsck_state *ost, o2fsck_dirblock_entry *dbe,
-			   struct ocfs2_dir_entry *dirent, int offset, 
-			   int left)
+static errcode_t fix_dirent_dots(o2fsck_state *ost, o2fsck_dirblock_entry *dbe,
+				 struct ocfs2_dir_entry *dirent, int offset, 
+				 int left, int *flags)
 {
 	int expect_dots = expected_dots(dbe, offset);
-	int ret_flags = 0, changed_len = 0;
+	int changed_len = 0;
 	struct ocfs2_dir_entry *next;
 	uint16_t new_len;
+	errcode_t ret = 0;
 
 	if (!expect_dots) {
 	       	if (!dirent_has_dots(dirent, 1) && !dirent_has_dots(dirent, 2))
+			goto out;
 			return 0;
 		if (prompt(ost, PY, 0, "Duplicate '%.*s' directory entry found, "
 			   "remove it?", dirent->name_len, dirent->name)) {
 			dirent->inode = 0;
-			return OCFS2_DIRENT_CHANGED;
+			*flags |= OCFS2_DIRENT_CHANGED;
+			goto out;
 		}
 	}
 
@@ -123,7 +127,7 @@
 		dirent->name_len = expect_dots;
 		memset(dirent->name, '.', expect_dots);
 		changed_len = 1;
-		ret_flags = OCFS2_DIRENT_CHANGED;
+		*flags |= OCFS2_DIRENT_CHANGED;
 	}
 
 	/* we only record where .. points for now and that ends the
@@ -132,14 +136,14 @@
 		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);
+		if (dp == NULL) {
+			ret = OCFS2_ET_INTERNAL_FAILURE;
+			com_err(whoami, ret, "no dir parents for '..' entry "
+				"for inode %"PRIu64, dbe->e_ino);
+		} else 
+			dp->dp_dot_dot = dirent->inode;
 
-		dp->dp_dot_dot = dirent->inode;
-					
-		return ret_flags;
+		goto out;
 	}
 
 	if ((dirent->inode != dbe->e_ino) &&
@@ -147,7 +151,7 @@
 		   "points to inode %"PRIu64" instead of itself.  Fix "
 		   "the '.' entry?", dbe->e_ino, dirent->inode)) {
 		dirent->inode = dbe->e_ino;
-		ret_flags = OCFS2_DIRENT_CHANGED;
+		*flags |= OCFS2_DIRENT_CHANGED;
 	}
 
 	/* 
@@ -168,29 +172,19 @@
 		next->inode = 0;
 		next->name_len = 0;
 		next->rec_len = OCFS2_DIR_REC_LEN(next->rec_len);
-		ret_flags = OCFS2_DIRENT_CHANGED;
+		*flags |= OCFS2_DIRENT_CHANGED;
 	}
-	return ret_flags;
+
+out:
+	return ret;
 }
 
 /* we just copy ext2's fixing behaviour here.  'left' is the number of bytes
  * from the start of the dirent struct to the end of the block. */
-static int fix_dirent_lengths(o2fsck_state *ost, o2fsck_dirblock_entry *dbe,
-				struct ocfs2_dir_entry *dirent, int offset,
-				int left, struct ocfs2_dir_entry *prev)
+static void fix_dirent_lengths(struct ocfs2_dir_entry *dirent,
+			       int left, struct ocfs2_dir_entry *prev,
+			       int *flags)
 {
-	if ((dirent->rec_len >= OCFS2_DIR_REC_LEN(1)) &&
-	    ((dirent->rec_len & OCFS2_DIR_ROUND) == 0) &&
-	    (dirent->rec_len <= left) &&
-	    (OCFS2_DIR_REC_LEN(dirent->name_len) <= dirent->rec_len))
-		return 0;
-
-	if (!prompt(ost, PY, 0, "Directory inode %"PRIu64" corrupted in logical "
-		    "block %"PRIu64" physical block %"PRIu64" offset %d. "
-		    "Attempt to repair this block's directory entries?",
-		    dbe->e_ino, dbe->e_blkcount, dbe->e_blkno, offset))
-		fatal_error(OCFS2_ET_DIR_CORRUPTED, "in pass2");
-
 	/* special casing an empty dirent that doesn't include the
 	 * extra rec_len alignment */
 	if ((left >= OCFS2_DIR_MEMBER_LEN) && 
@@ -199,14 +193,14 @@
 		left -= dirent->rec_len;
 		memmove(cp, cp + dirent->rec_len, left);
 		memset(cp + left, 0, dirent->rec_len);
-		return OCFS2_DIRENT_CHANGED;
+		goto out;
 	}
 
 	/* clamp rec_len to the remainder of the block if name_len
 	 * is within the block */
 	if (dirent->rec_len > left && dirent->name_len <= left) {
 		dirent->rec_len = left;
-		return OCFS2_DIRENT_CHANGED;
+		goto out;
 	}
 
 	/* from here on in we're losing directory entries by adding their
@@ -223,20 +217,22 @@
 		dirent->file_type = OCFS2_FT_UNKNOWN;
 	}
 
-	return OCFS2_DIRENT_CHANGED;
+out:
+	*flags |= OCFS2_DIRENT_CHANGED;
 }
 
-static int fix_dirent_name(o2fsck_state *ost, o2fsck_dirblock_entry *dbe,
-			   struct ocfs2_dir_entry *dirent, int offset)
+static void fix_dirent_name(o2fsck_state *ost, o2fsck_dirblock_entry *dbe,
+			    struct ocfs2_dir_entry *dirent, int offset,
+			    int *flags)
 {
 	char *chr = dirent->name;
-	int len = dirent->name_len, fix = 0, ret_flags = 0;
+	int len = dirent->name_len, fix = 0;
 
 	if (len == 0) {
 		if (prompt(ost, PY, 0, "Directory entry has a zero-length name, "
 				    "clear it?")) {
 			dirent->inode = 0;
-			ret_flags = OCFS2_DIRENT_CHANGED;
+			*flags |= OCFS2_DIRENT_CHANGED;
 		}
 	}
 
@@ -248,26 +244,25 @@
 				     "them with dots?", dirent->name_len, 
 				     dirent->name);
 			if (!fix)
-				return 0;
+				break;
 		}
 		*chr = '.';
-		ret_flags = OCFS2_DIRENT_CHANGED;
+		*flags |= OCFS2_DIRENT_CHANGED;
 	}
-
-	return ret_flags;
 }
 
-static int fix_dirent_inode(o2fsck_state *ost, o2fsck_dirblock_entry *dbe,
-				struct ocfs2_dir_entry *dirent, int offset)
+static void fix_dirent_inode(o2fsck_state *ost, o2fsck_dirblock_entry *dbe,
+			     struct ocfs2_dir_entry *dirent, int offset,
+			     int *flags)
 {
-	if (ocfs2_block_out_of_range(ost->ost_fs, dirent->inode)) {
-		if (prompt(ost, PY, 0, "Directory entry '%.*s' refers to inode "
-			   "number %"PRIu64" which is out of range, "
-			   "clear the entry?", dirent->name_len, dirent->name, 
-			   dirent->inode)) {
-			dirent->inode = 0;
-			return OCFS2_DIRENT_CHANGED;
-		}
+	if (ocfs2_block_out_of_range(ost->ost_fs, dirent->inode) &&
+	    prompt(ost, PY, 0, "Directory entry '%.*s' refers to inode "
+		   "number %"PRIu64" which is out of range, clear the entry?",
+		   dirent->name_len, dirent->name, dirent->inode)) {
+
+		dirent->inode = 0;
+		*flags |= OCFS2_DIRENT_CHANGED;
+		goto out;
 	}
 
 	if (!o2fsck_test_inode_allocated(ost, dbe->e_ino) &&
@@ -275,9 +270,10 @@
 		   "%"PRIu64" which isn't allocated, clear the entry?", 
 		   dirent->name_len, dirent->name, dirent->inode)) {
 		dirent->inode = 0;
-		return OCFS2_DIRENT_CHANGED;
+		*flags |= OCFS2_DIRENT_CHANGED;
 	}
-	return 0;
+out:
+	return;
 }
 
 #define type_entry(type) [type] = #type
@@ -301,35 +297,42 @@
 	return file_types[type];
 }
 
-static int fix_dirent_filetype(o2fsck_state *ost, o2fsck_dirblock_entry *dbe,
-				struct ocfs2_dir_entry *dirent, int offset)
+static errcode_t fix_dirent_filetype(o2fsck_state *ost,
+				     o2fsck_dirblock_entry *dbe,
+				     struct ocfs2_dir_entry *dirent,
+				     int offset,
+				     int *flags)
 {
 	uint8_t expected_type;
-	errcode_t err;
+	errcode_t ret;
 	int was_set;
 
-	/* XXX Do I care about possible bitmap_test errors here? */
-
-	ocfs2_bitmap_test(ost->ost_dir_inodes, dirent->inode, &was_set);
+	ret = ocfs2_bitmap_test(ost->ost_dir_inodes, dirent->inode, &was_set);
+	if (ret)
+		goto out;
 	if (was_set) {
 		expected_type = OCFS2_FT_DIR;
 		goto check;
 	}
 
-	ocfs2_bitmap_test(ost->ost_reg_inodes, dirent->inode, &was_set);
+	ret = ocfs2_bitmap_test(ost->ost_reg_inodes, dirent->inode, &was_set);
+	if (ret)
+		goto out;
 	if (was_set) {
 		expected_type = OCFS2_FT_REG_FILE;
 		goto check;
 	}
 
-	ocfs2_bitmap_test(ost->ost_bad_inodes, dirent->inode, &was_set);
+	ret = ocfs2_bitmap_test(ost->ost_bad_inodes, dirent->inode, &was_set);
+	if (ret)
+		goto out;
 	if (was_set) {
 		expected_type = OCFS2_FT_UNKNOWN;
 		goto check;
 	}
 
-	err = o2fsck_type_from_dinode(ost, dirent->inode, &expected_type);
-	if (err) /* XXX propogate this? */
+	ret = o2fsck_type_from_dinode(ost, dirent->inode, &expected_type);
+	if (ret)
 		goto out;
 
 check:
@@ -343,44 +346,55 @@
 		file_type_string(expected_type), expected_type)) {
 
 		dirent->file_type = expected_type;
-		return OCFS2_DIRENT_CHANGED;
+		*flags |= OCFS2_DIRENT_CHANGED;
 	}
 
 out:
-	return 0;
+	if (ret)
+		com_err(whoami, ret, "while trying to verify the file type "
+			"of directory entry %.*s", dirent->name_len,
+			dirent->name);
+
+	return ret;
 }
 
-static int fix_dirent_linkage(o2fsck_state *ost, o2fsck_dirblock_entry *dbe,
-			      struct ocfs2_dir_entry *dirent, int offset)
+static errcode_t fix_dirent_linkage(o2fsck_state *ost,
+				    o2fsck_dirblock_entry *dbe,
+				    struct ocfs2_dir_entry *dirent,
+				    int offset,
+				    int *flags)
 {
 	int expect_dots = expected_dots(dbe, offset);
 	o2fsck_dir_parent *dp;
-	errcode_t err;
+	errcode_t ret = 0;
 	int is_dir;
 
 	/* we already took care of special-casing the dots */
 	if (expect_dots)
-		return 0;
+		goto out;
 
 	/* 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);
+	ret = ocfs2_bitmap_test(ost->ost_dir_inodes, dirent->inode, &is_dir);
+	if (ret)
+		com_err(whoami, ret, "while checking for inode %"PRIu64" in "
+			"the dir bitmap", dirent->inode);
 	if (!is_dir)
-		return 0;
+		goto out;
 
 	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 (dp == NULL) {
+		ret = OCFS2_ET_INTERNAL_FAILURE;
+		com_err(whoami, ret, "no dir parents recorded for inode "
+			"%"PRIu64, dirent->inode);
+		goto out;
+	}
 
 	/* 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;
+		goto out;
 	}
 
 	if (prompt(ost, 0, 0, "Directory inode %"PRIu64" is not the first to "
@@ -390,57 +404,73 @@
 		dirent->name_len, dirent->name, dirent->inode)) {
 
 		dirent->inode = 0;
-		return OCFS2_DIRENT_CHANGED;
+		*flags |= OCFS2_DIRENT_CHANGED;
 	}
 
-	return 0;
+out:
+	return ret;
 }
 
-static int fix_dirent_dups(o2fsck_state *ost, o2fsck_dirblock_entry *dbe,
-			   struct ocfs2_dir_entry *dirent, 
-			   o2fsck_strings *strings, int *dups_in_block)
+static errcode_t fix_dirent_dups(o2fsck_state *ost,
+				 o2fsck_dirblock_entry *dbe,
+				 struct ocfs2_dir_entry *dirent,
+				 o2fsck_strings *strings,
+				 int *dups_in_block,
+				 int *flags)
 {
-	errcode_t err;
+	errcode_t ret = 0;
 	int was_set;
 
 	if (*dups_in_block)
-		return 0;
+		goto out;
 
-	/* does this need to be fatal?  It appears e2fsck just ignores
-	 * the error. */
-	err = o2fsck_strings_insert(strings, dirent->name, dirent->name_len, 
-				   &was_set);
-	if (err)
-		fatal_error(err, "while allocating space to find duplicate "
-				"directory entries");
+	ret = o2fsck_strings_insert(strings, dirent->name, dirent->name_len, 
+				    &was_set);
+	if (ret) {
+		com_err(whoami, ret, "while allocating space to find "
+			"duplicate directory entries");
+		goto out;
+	}
 
 	if (!was_set)
-		return 0;
+		goto out;
 
-	fprintf(stderr, "Duplicate directory entry '%.*s' found.\n",
-		      dirent->name_len, dirent->name);
-	fprintf(stderr, "Marking its parent %"PRIu64" for rebuilding.\n",
+	printf("Duplicate directory entry '%.*s' found.\n",
+	       dirent->name_len, dirent->name);
+	printf("Marking its parent %"PRIu64" for rebuilding.\n", dbe->e_ino);
+
+	ret = ocfs2_bitmap_set(ost->ost_rebuild_dirs, dbe->e_ino, &was_set);
+	if (ret)
+		com_err(whoami, ret, "while recording that inode %"PRIu64" "
+			"needs to have duplicate entries removed.",
 			dbe->e_ino);
 
-	err = ocfs2_bitmap_test(ost->ost_rebuild_dirs, dbe->e_ino, &was_set);
-	if (err)
-		fatal_error(err, "while checking for inode %"PRIu64" in "
-				"the used bitmap", dbe->e_ino);
-
 	*dups_in_block = 1;
-	return 0;
+out:
+	return ret;
 }
 
+static int corrupt_dirent(struct ocfs2_dir_entry *dirent, int left)
+{
+	if ((dirent->rec_len >= OCFS2_DIR_REC_LEN(1)) &&
+	    ((dirent->rec_len & OCFS2_DIR_ROUND) == 0) &&
+	    (dirent->rec_len <= left) &&
+	    (OCFS2_DIR_REC_LEN(dirent->name_len) <= dirent->rec_len))
+		return 0;
+
+	return 1;
+}
+
 /* this could certainly be more clever to issue reads in groups */
 static unsigned pass2_dir_block_iterate(o2fsck_dirblock_entry *dbe, 
 					void *priv_data) 
 {
 	struct dirblock_data *dd = priv_data;
 	struct ocfs2_dir_entry *dirent, *prev = NULL;
-	unsigned int offset = 0, this_flags, ret_flags = 0;
+	unsigned int offset = 0, ret_flags = 0;
 	o2fsck_strings strings;
 	int dups_in_block = 0;
-	errcode_t retval;
+	errcode_t ret;
 
 	if (!o2fsck_test_inode_allocated(dd->ost, dbe->e_ino)) {
 		printf("Directory block %"PRIu64" belongs to directory inode "
@@ -451,12 +481,11 @@
 
 	o2fsck_strings_init(&strings);
 
- 	retval = ocfs2_read_dir_block(dd->fs, dbe->e_blkno, dd->buf);
-	if (retval && retval != OCFS2_ET_DIR_CORRUPTED) {
-		/* XXX hum, ask to continue here.  more a prompt than a 
-		 * fix.  need to expand problem.c's vocabulary. */
-		fatal_error(retval, "while reading dir block %"PRIu64,
-				dbe->e_blkno);
+ 	ret = ocfs2_read_dir_block(dd->fs, dbe->e_blkno, dd->buf);
+	if (ret && ret != OCFS2_ET_DIR_CORRUPTED) {
+		com_err(whoami, ret, "while reading dir block %"PRIu64,
+			dbe->e_blkno);
+		goto out;
 	}
 
 	verbosef("dir block %"PRIu64"\n", dbe->e_blkno);
@@ -472,24 +501,26 @@
 		/* XXX I wonder if we should be checking that the padding
 		 * is 0 */
 
+		/* if we can't trust this dirent then fix it up or skip
+		 * the whole block */
+		if (corrupt_dirent(dirent, dd->fs->fs_blocksize - offset)) {
+			if (!prompt(dd->ost, PY, 0, "Directory inode %"PRIu64" "
+				    "corrupted in logical block %"PRIu64" "
+				    "physical block %"PRIu64" offset %d. "
+				    "Attempt to repair this block's directory "
+				    "entries?", dbe->e_ino, dbe->e_blkcount,
+				    dbe->e_blkno, offset))
+				break;
 
-		/* first verify that we can trust the dirent's lengths
-		 * to navigate to the next in the block.  This can try to
-		 * get rid of a broken dirent by trying to shift remaining
-		 * dirents into its place.  The 'contiune' attempts to let
-		 * us recheck the current dirent.
-		 *
-		 * XXX this will have to do some swabbing as it tries
-		 * to salvage as read_dir_block stops swabbing
-		 * when it sees bad entries.
-		 */
-		this_flags = fix_dirent_lengths(dd->ost, dbe, dirent, offset, 
-						 dd->fs->fs_blocksize - offset,
-						 prev);
-		ret_flags |= this_flags;
-		if (this_flags & OCFS2_DIRENT_CHANGED)
+			/* we edit the dirent in place so we try to parse
+			 * it again after fixing it */
+			fix_dirent_lengths(dirent,
+					   dd->fs->fs_blocksize - offset,
+					   prev, &ret_flags);
 			continue;
 
+		}
+
 		/* 
 		 * In general, these calls mark ->inode as 0 when they want it
 		 * to be seen as deleted; ignored by fsck and reclaimed by the
@@ -499,29 +530,40 @@
 		 *
 		 * XXX should verify that ocfs2 reclaims entries like that.
 		 */
-		ret_flags |= fix_dirent_dots(dd->ost, dbe, dirent, offset, 
-					     dd->fs->fs_blocksize - offset);
+		ret = fix_dirent_dots(dd->ost, dbe, dirent, offset, 
+					     dd->fs->fs_blocksize - offset,
+					     &ret_flags);
+		if (ret)
+			goto out;
 		if (dirent->inode == 0)
 			goto next;
 
-		ret_flags |= fix_dirent_name(dd->ost, dbe, dirent, offset);
+		fix_dirent_name(dd->ost, dbe, dirent, offset, &ret_flags);
 		if (dirent->inode == 0)
 			goto next;
 
-		ret_flags |= fix_dirent_inode(dd->ost, dbe, dirent, offset);
+		fix_dirent_inode(dd->ost, dbe, dirent, offset, &ret_flags);
 		if (dirent->inode == 0)
 			goto next;
 
-		ret_flags |= fix_dirent_filetype(dd->ost, dbe, dirent, offset);
+		ret = fix_dirent_filetype(dd->ost, dbe, dirent, offset,
+					  &ret_flags);
+		if (ret)
+			goto out;
 		if (dirent->inode == 0)
 			goto next;
 
-		ret_flags |= fix_dirent_linkage(dd->ost, dbe, dirent, offset);
+		ret = fix_dirent_linkage(dd->ost, dbe, dirent, offset,
+					 &ret_flags);
+		if (ret)
+			goto out;
 		if (dirent->inode == 0)
 			goto next;
 
-		ret_flags |= fix_dirent_dups(dd->ost, dbe, dirent, &strings,
-					     &dups_in_block);
+		ret = fix_dirent_dups(dd->ost, dbe, dirent, &strings,
+				      &dups_in_block, &ret_flags);
+		if (ret)
+			goto out;
 		if (dirent->inode == 0)
 			goto next;
 
@@ -534,16 +576,18 @@
 	}
 
 	if (ret_flags & OCFS2_DIRENT_CHANGED) {
-		retval = ocfs2_write_dir_block(dd->fs, dbe->e_blkno, dd->buf);
-		if (retval) {
-			/* XXX hum, ask to continue here.  more a prompt than a 
-			 * fix.  need to expand problem.c's vocabulary. */
-			fatal_error(retval, "while writing dir block %"PRIu64,
-					dbe->e_blkno);
+		ret = ocfs2_write_dir_block(dd->fs, dbe->e_blkno, dd->buf);
+		if (ret) {
+			com_err(whoami, ret, "while writing dir block %"PRIu64,
+				dbe->e_blkno);
+			dd->ost->ost_write_error = 1;
 		}
 	}
 
 	o2fsck_strings_free(&strings);
+out:
+	if (ret)
+		dd->ret = ret;
 	return ret_flags;
 }
 

Modified: trunk/fsck.ocfs2/pass3.c
===================================================================
--- trunk/fsck.ocfs2/pass3.c	2004-12-04 20:38:44 UTC (rev 462)
+++ trunk/fsck.ocfs2/pass3.c	2004-12-05 01:28:04 UTC (rev 463)
@@ -118,9 +118,15 @@
 	 * inode and the "." dirent in its dirblock */
 	o2fsck_icount_set(ost->ost_icount_in_inodes, blkno, 2);
 	o2fsck_icount_set(ost->ost_icount_refs, blkno, 2);
-	o2fsck_add_dir_parent(&ost->ost_dir_parents, blkno, 
-			      ost->ost_fs->fs_root_blkno,
-			      ost->ost_fs->fs_root_blkno);
+	ret = o2fsck_add_dir_parent(&ost->ost_dir_parents, blkno, 
+				    ost->ost_fs->fs_root_blkno,
+				    ost->ost_fs->fs_root_blkno);
+	if (ret) {
+		com_err(whoami, ret, "while recording a new /lost+found "
+			"directory");
+		goto out;
+	}
+
 	/* we've already iterated through the dirblocks in pass2 so there
 	 * is no need to register l+f's new dir block */
 
@@ -272,9 +278,11 @@
 
 static uint64_t loop_no = 0;
 
-static void connect_directory(o2fsck_state *ost, o2fsck_dir_parent *dir)
+static errcode_t connect_directory(o2fsck_state *ost,
+				   o2fsck_dir_parent *dir)
 {
 	o2fsck_dir_parent *dp = dir, *par;
+	errcode_t ret = 0;
 	int fix;
 
 	verbosef("checking dir inode %"PRIu64" parent %"PRIu64" dot_dot "
@@ -294,10 +302,12 @@
 		if (dp->dp_dirent) {
 			par = o2fsck_dir_parent_lookup(&ost->ost_dir_parents, 
 							dp->dp_dirent);
-			if (par == NULL)
-				fatal_error(OCFS2_ET_INTERNAL_FAILURE,
-						"no dir info for parent "
-						"%"PRIu64, dp->dp_dirent);
+			if (par == NULL) {
+				ret = OCFS2_ET_INTERNAL_FAILURE;
+				com_err(whoami, ret, "no dir info for parent "
+					"%"PRIu64, dp->dp_dirent);
+				goto out;
+			}
 			if (par->dp_loop_no != loop_no) {
 				par->dp_loop_no = loop_no;
 				dp = par;
@@ -327,11 +337,14 @@
 		if (fix)
 			fix_dot_dot(ost, dir);
 	}
+out:
+	return ret;
 }
 
 errcode_t o2fsck_pass3(o2fsck_state *ost)
 {
 	o2fsck_dir_parent *dp;
+	errcode_t ret = 0;
 
 	printf("Pass 3: Checking directory connectivity.\n");
 
@@ -343,25 +356,33 @@
 
 	dp = o2fsck_dir_parent_lookup(&ost->ost_dir_parents, 
 					ost->ost_fs->fs_root_blkno);
-	if (dp == NULL)
-		fatal_error(OCFS2_ET_INTERNAL_FAILURE, "root inode %"PRIu64" "
-				"wasn't marked as a directory in pass1",
-				ost->ost_fs->fs_root_blkno);
+	if (dp == NULL) {
+		ret = OCFS2_ET_INTERNAL_FAILURE;
+		com_err(whoami, ret, "root inode %"PRIu64" wasn't marked as "
+			"a directory in pass1", ost->ost_fs->fs_root_blkno);
+		goto out;
+	}
 	dp->dp_connected = 1;
 
 	dp = o2fsck_dir_parent_lookup(&ost->ost_dir_parents, 
 					ost->ost_fs->fs_sysdir_blkno);
-	if (dp == NULL)
-		fatal_error(OCFS2_ET_INTERNAL_FAILURE, "system dir inode "
-				"%"PRIu64" wasn't marked as a directory in "
-				"pass1", ost->ost_fs->fs_sysdir_blkno);
+	if (dp == NULL) {
+		ret = OCFS2_ET_INTERNAL_FAILURE;
+		com_err(whoami, ret, "system dir inode %"PRIu64" wasn't "
+			"marked as a directory in pass1",
+			ost->ost_fs->fs_sysdir_blkno);
+		goto out;
+	}
 	dp->dp_connected = 1;
 
 	for(dp = o2fsck_dir_parent_first(&ost->ost_dir_parents) ;
 	    dp; dp = o2fsck_dir_parent_next(dp)) {
 		/* XXX hmm, make sure dir->ino is in the dir map? */
-		connect_directory(ost, dp);
+		ret = connect_directory(ost, dp);
+		if (ret)
+			goto out;
 	}
 
-	return 0;
+out:
+	return ret;
 }



More information about the Ocfs2-tools-commits mailing list