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

Sunil Mushran sunil.mushran at oracle.com
Tue Oct 25 13:37:15 PDT 2011


You comment says that you are setting it for dirs only. Which is fine. But
you appear to be enabling it for refcount too.

Should I just disable it for refcount? We can handle that later.

On 08/22/2011 03:36 PM, Goldwyn Rodrigues wrote:
> 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..2bd9738 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, offset, no_holes,
> +				&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);

no_holes being set for dirblocks.

> +	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);

no_holes not being set dx_dirs.

>   	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);


no_holes being set refcount.


>
>   	/*
>   	 * 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);

not being set of xattrs.

>   			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;




More information about the Ocfs2-tools-devel mailing list