[Ocfs2-tools-devel] [PATCH 2/3] Fix holes in directories

Goldwyn Rodrigues rgoldwyn at gmail.com
Fri Aug 12 15:33:44 PDT 2011


Calculate the expected offset as the extent tree is traversed and
compare with the offset in the extent record. If the file is not
supposed to have holes, such as directories, prompt and correct it.

Currently no_holes is set for directories only.

I agree this is an ugly hack which bounces variables to the extent
traversal functions, but it gets the job done.

Signed-off-by: Goldwyn Rodrigues <rgoldwyn at suse.de>
---
 fsck.ocfs2/extent.c               |   57 ++++++++++++++++++++++++++++++++----
 fsck.ocfs2/fsck.ocfs2.checks.8.in |    6 ++++
 fsck.ocfs2/include/extent.h       |    7 ++++-
 fsck.ocfs2/pass1.c                |    2 +-
 fsck.ocfs2/refcount.c             |   16 ++++++----
 fsck.ocfs2/xattr.c                |    5 ++-
 6 files changed, 76 insertions(+), 17 deletions(-)

diff --git a/fsck.ocfs2/extent.c b/fsck.ocfs2/extent.c
index 0075319..f53e54b 100644
--- a/fsck.ocfs2/extent.c
+++ b/fsck.ocfs2/extent.c
@@ -49,6 +49,7 @@ static const char *whoami = "extent.c";

 static errcode_t check_eb(o2fsck_state *ost, struct extent_info *ei,
 			  uint64_t owner, uint64_t blkno,
+			  uint32_t offset, int no_holes,
 			  int *is_valid)
 {
 	int changed = 0;
@@ -113,10 +114,9 @@ static errcode_t check_eb(o2fsck_state *ost,
struct extent_info *ei,

 	/* XXX worry about suballoc node/bit */
 	/* XXX worry about next_leaf_blk */
-
 	check_el(ost, ei, owner, &eb->h_list,
 		 ocfs2_extent_recs_per_eb(ost->ost_fs->fs_blocksize),
-		 &changed);
+		 offset, no_holes, &changed);

 	if (changed) {
 		ret = ocfs2_write_extent_block(ost->ost_fs, blkno, buf);
@@ -139,7 +139,9 @@ out:
 static errcode_t check_er(o2fsck_state *ost, struct extent_info *ei,
 			  uint64_t owner,
 			  struct ocfs2_extent_list *el,
-			  struct ocfs2_extent_rec *er, int *changed)
+			  struct ocfs2_extent_rec *er,
+			  uint32_t offset, int no_holes,
+			  int *changed)
 {
 	errcode_t ret = 0;
 	uint32_t clusters;
@@ -151,6 +153,15 @@ static errcode_t check_er(o2fsck_state *ost,
struct extent_info *ei,
 	if (ocfs2_block_out_of_range(ost->ost_fs, er->e_blkno))
 		goto out;

+	if (no_holes && (er->e_cpos != offset) &&
+		prompt(ost, PY, PR_NO_HOLES,
+			"Extent record of owner %"PRIu64" is incorrectly "
+			"set to %d instead of %d. Fix?", owner, er->e_cpos,
+			offset)) {
+		er->e_cpos = offset;
+		*changed = 1;
+	}
+
 	if (el->l_tree_depth) {
 		int is_valid = 0;
 		/* we only expect a given depth when we descend to extent blocks
@@ -158,7 +169,8 @@ static errcode_t check_er(o2fsck_state *ost,
struct extent_info *ei,
 		 * is checked */
 		ei->ei_expect_depth = 1;
 		ei->ei_expected_depth = el->l_tree_depth - 1;
-		check_eb(ost, ei, owner, er->e_blkno, &is_valid);
+		check_eb(ost, ei, owner, er->e_blkno, no_holes, offset,
+				&is_valid);
 		if (!is_valid &&
 		    prompt(ost, PY, PR_EXTENT_EB_INVALID,
 			   "The extent record for cluster offset "
@@ -175,7 +187,8 @@ static errcode_t check_er(o2fsck_state *ost,
struct extent_info *ei,
 	}

 	if (ei->chk_rec_func)
-		ret = ei->chk_rec_func(ost, owner, el, er, changed, ei->para);
+		ret = ei->chk_rec_func(ost, owner, el, er, changed, offset,
+				no_holes, ei->para);
 	/* XXX offer to remove leaf records with er_clusters set to 0? */

 	/* XXX check that the blocks that are referenced aren't already
@@ -188,7 +201,8 @@ out:
 errcode_t check_el(o2fsck_state *ost, struct extent_info *ei,
 		   uint64_t owner,
 		   struct ocfs2_extent_list *el,
-		   uint16_t max_recs, int *changed)
+		   uint16_t max_recs, uint32_t offset, int no_holes,
+		   int *changed)
 {
 	int trust_next_free = 1;
 	struct ocfs2_extent_rec *er;
@@ -259,7 +273,12 @@ errcode_t check_el(o2fsck_state *ost, struct
extent_info *ei,
 		/* returns immediately if blkno is out of range.
 		 * descends into eb.  checks that data er doesn't
 		 * reference past the volume or anything crazy. */
-		check_er(ost, ei, owner, el, er, changed);
+		check_er(ost, ei, owner, el, er, offset, no_holes, changed);
+
+		if (el->l_tree_depth)
+			offset += er->e_int_clusters;
+		else
+			offset += er->e_leaf_clusters;

 		/* offer to remove records that point to nowhere */
 		if (ocfs2_block_out_of_range(ost->ost_fs, er->e_blkno) &&
@@ -313,6 +332,8 @@ errcode_t o2fsck_check_extent_rec(o2fsck_state *ost,
 				  struct ocfs2_extent_list *el,
 				  struct ocfs2_extent_rec *er,
 				  int *changed,
+				  uint32_t offset,
+				  int no_holes,
 				  void *para)
 {
 	uint32_t clusters, last_cluster;
@@ -417,8 +438,30 @@ errcode_t o2fsck_check_extents(o2fsck_state *ost,
 	ei.para = di;
 	ret = check_el(ost, &ei, di->i_blkno, &di->id2.i_list,
 	         ocfs2_extent_recs_per_inode(ost->ost_fs->fs_blocksize),
+		 0, S_ISDIR(di->i_mode),
 		 &changed);

+	if (S_ISDIR(di->i_mode) && !(di->i_dyn_features
+				& OCFS2_INLINE_DATA_FL)) {
+		struct ocfs2_extent_list *el = &(di->id2.i_list);
+		struct ocfs2_extent_rec *er =
+			&(el->l_recs[el->l_next_free_rec - 1]);
+		uint64_t expected;
+		if (el->l_tree_depth)
+			expected = er->e_cpos + er->e_int_clusters;
+		else
+			expected = er->e_cpos + er->e_leaf_clusters;
+		expected = ocfs2_clusters_to_bytes(ost->ost_fs, expected);
+		if ((di->i_size > expected) && prompt(ost, PY,
+				PR_INODE_SIZE, "Inode %"PRIu64" has a size of "
+				"%"PRIu64" but has %"PRIu64" bytes of actual "
+				"data. Correct the file size?",
+				(uint64_t)di->i_blkno,
+				(uint64_t)di->i_size, expected)) {
+			di->i_size = expected;
+			changed = 1;
+		}
+	}
 	if (changed)
 		o2fsck_write_inode(ost, di->i_blkno, di);

diff --git a/fsck.ocfs2/fsck.ocfs2.checks.8.in
b/fsck.ocfs2/fsck.ocfs2.checks.8.in
index e706ea5..d887a16 100644
--- a/fsck.ocfs2/fsck.ocfs2.checks.8.in
+++ b/fsck.ocfs2/fsck.ocfs2.checks.8.in
@@ -1137,6 +1137,12 @@ index entry will cause lookups on this name to fail.

 Answering yes will rebuild the directory index, restoring the missing entry.

+.SS "NO_HOLES"
+A metadata structure enocuntered a hole where it should not. Examples of such
+structures are directories, refcount trees, dx_trees etc.
+
+Answering yes will remove the hole.
+
 .SH "SEE ALSO"
 .BR fsck.ocfs2(8)

diff --git a/fsck.ocfs2/include/extent.h b/fsck.ocfs2/include/extent.h
index fe9b021..badd593 100644
--- a/fsck.ocfs2/include/extent.h
+++ b/fsck.ocfs2/include/extent.h
@@ -27,6 +27,8 @@ typedef errcode_t (check_leaf_er_func)(o2fsck_state *ost,
 				       struct ocfs2_extent_list *el,
 				       struct ocfs2_extent_rec *er,
 				       int *changed,
+				       uint32_t offset,
+				       int no_holes,
 				       void *para);
 typedef errcode_t (mark_leaf_er_alloc_func)(o2fsck_state *ost,
 					    struct ocfs2_extent_rec *er,
@@ -50,12 +52,15 @@ errcode_t o2fsck_check_extents(o2fsck_state *ost,
 errcode_t check_el(o2fsck_state *ost, struct extent_info *ei,
 		   uint64_t owner,
 		   struct ocfs2_extent_list *el,
-		   uint16_t max_recs, int *changed);
+		   uint16_t max_recs, uint32_t offset, int no_holes,
+		   int *changed);
 errcode_t o2fsck_check_extent_rec(o2fsck_state *ost,
 				  uint64_t owner,
 				  struct ocfs2_extent_list *el,
 				  struct ocfs2_extent_rec *er,
 				  int *changed,
+				  uint32_t offset,
+				  int no_holes,
 				  void *para);

 errcode_t o2fsck_mark_tree_clusters_allocated(o2fsck_state *ost,
diff --git a/fsck.ocfs2/pass1.c b/fsck.ocfs2/pass1.c
index 22dafdf..398fbf3 100644
--- a/fsck.ocfs2/pass1.c
+++ b/fsck.ocfs2/pass1.c
@@ -815,7 +815,7 @@ static errcode_t o2fsck_check_dx_dir(o2fsck_state
*ost, struct ocfs2_dinode *di)

 	ret = check_el(ost, &ei, di->i_blkno, &dx_root->dr_list,
 			ocfs2_extent_recs_per_dx_root(fs->fs_blocksize),
-			&changed);
+			0, 0, &changed);
 	if (ret)
 		goto out;

diff --git a/fsck.ocfs2/refcount.c b/fsck.ocfs2/refcount.c
index 127c291..5a8ff73 100644
--- a/fsck.ocfs2/refcount.c
+++ b/fsck.ocfs2/refcount.c
@@ -64,7 +64,8 @@ struct refcount_tree {
 };

 static errcode_t check_rb(o2fsck_state *ost, uint64_t blkno,
-			  uint64_t root_blkno, uint64_t *c_end, int *is_valid);
+			  uint64_t root_blkno, uint64_t *c_end,
+			  uint32_t offset, int no_holes, int *is_valid);

 static void check_rl(o2fsck_state *ost,
 		     uint64_t rb_blkno, uint64_t root_blkno,
@@ -167,7 +168,8 @@ static errcode_t
refcount_check_leaf_extent_rec(o2fsck_state *ost,
 						uint64_t owner,
 						struct ocfs2_extent_list *el,
 						struct ocfs2_extent_rec *er,
-						int *changed,
+						int *changed, uint32_t offset,
+						int no_holes,
 						void *para)
 {
 	errcode_t ret;
@@ -175,7 +177,8 @@ static errcode_t
refcount_check_leaf_extent_rec(o2fsck_state *ost,
 	struct check_refcount_rec *check = para;

 	ret = check_rb(ost, er->e_blkno,
-		       check->root_blkno, &check->c_end, &is_valid);
+		       check->root_blkno, &check->c_end, offset, no_holes,
+		       &is_valid);

 	if (!is_valid &&
 	    prompt(ost, PY, PR_REFCOUNT_BLOCK_INVALID,
@@ -190,7 +193,8 @@ static errcode_t
refcount_check_leaf_extent_rec(o2fsck_state *ost,
 }

 static errcode_t check_rb(o2fsck_state *ost, uint64_t blkno,
-			  uint64_t root_blkno, uint64_t *c_end, int *is_valid)
+			  uint64_t root_blkno, uint64_t *c_end,
+			  uint32_t offset, int no_holes, int *is_valid)
 {
 	int changed = 0;
 	char *buf = NULL;
@@ -279,7 +283,7 @@ static errcode_t check_rb(o2fsck_state *ost, uint64_t blkno,
 		 * here.
 		 */
 		check_el(ost, &ei, rb->rf_blkno, &rb->rf_list,
-			 max_recs, &changed);
+			 max_recs, offset, no_holes, &changed);
 		*c_end = check.c_end;

 		if (ei.ei_clusters != rb->rf_clusters &&
@@ -387,7 +391,7 @@ errcode_t o2fsck_check_refcount_tree(o2fsck_state *ost,
 		return ret;

 	ret = check_rb(ost, di->i_refcount_loc, di->i_refcount_loc,
-		       &c_end, &is_valid);
+		       &c_end, 0, 1, &is_valid);

 	/*
 	 * Add refcount tree to the rb-tree.
diff --git a/fsck.ocfs2/xattr.c b/fsck.ocfs2/xattr.c
index 46c54d4..4a2efe2 100644
--- a/fsck.ocfs2/xattr.c
+++ b/fsck.ocfs2/xattr.c
@@ -395,7 +395,8 @@ static errcode_t check_xattr_value(o2fsck_state *ost,
 				((void *)xh + offset);
 			struct ocfs2_extent_list *el = &xv->xr_list;
 			owner = start + offset / ost->ost_fs->fs_blocksize;
-			ret = check_el(ost, &ei, owner, el, 1, &change);
+			ret = check_el(ost, &ei, owner, el, 1,
+					0, 0, &change);
 			if (ret)
 				return ret;
 			if (change)
@@ -612,7 +613,7 @@ static errcode_t
o2fsck_check_xattr_index_block(o2fsck_state *ost,
 	ei.mark_rec_alloc_func = o2fsck_mark_tree_clusters_allocated;
 	ei.para = di;
 	ret = check_el(ost, &ei, xb->xb_blkno, el,
-		ocfs2_xattr_recs_per_xb(ost->ost_fs->fs_blocksize),
+		ocfs2_xattr_recs_per_xb(ost->ost_fs->fs_blocksize), 0, 0,
 		changed);
 	if (ret)
 		return ret;
-- 
1.7.6



More information about the Ocfs2-tools-devel mailing list