[Ocfs2-tools-devel] [PATCH 2/3 v2] fsck.ocfs2: Add extent list check for discontig bg.

Tao Ma tao.ma at oracle.com
Fri Jul 30 02:11:24 PDT 2010


change from v1:
1. Change almost all of the man page and prompt in fsck.ocfs2.
2. Add some new corrupt fix options:
   1) DISCONTIG_BG_LESS_CLUSTERS in case the sum of all the extent records
      isn't equal to cpg.
   2) DISCONTIG_BG_REC_CORRUPT in the place we used to check
      DISCONTIG_BG_REMOVE_REC, we will drop the group now.

So we will do some basic sanity check for discontig block group.
The check includes:
1. l_tree_depth must be set to 0.
2. l_count must be set to ocfs2_extent_recs_per_gd.
3. if l_next_free_rec is broken and the extent record list looks
   sane, update l_next_free_rec.
4. if any extent record has an invalid e_cpos, dropt the group.
5. if there is only one rec which has invalid e_leaf_clusters,
   update it according to other extent records.
6. if one extent record looks broken while all the others look
   sane and complete, remove it.

Signed-off-by: Tao Ma <tao.ma at oracle.com>
---
 fsck.ocfs2/fsck.ocfs2.checks.8.in |   70 +++++++++++++
 fsck.ocfs2/pass0.c                |  196 +++++++++++++++++++++++++++++++++++++
 2 files changed, 266 insertions(+), 0 deletions(-)

diff --git a/fsck.ocfs2/fsck.ocfs2.checks.8.in b/fsck.ocfs2/fsck.ocfs2.checks.8.in
index 5bea432..16ecfc1 100644
--- a/fsck.ocfs2/fsck.ocfs2.checks.8.in
+++ b/fsck.ocfs2/fsck.ocfs2.checks.8.in
@@ -295,6 +295,76 @@ what was found by totalling up the group descriptors.
 Answering yes updates the c_total and c_free members of the header to reflect
 what was found in the group descriptors in the chain.
 
+.SS "DISCONTIG_BG_DEPTH"
+A discontiguous block group has an extent list which records all the clusters
+allocated to it.  Discontiguous block groups only support extent lists with
+a tree depth of 0.  A block group claims to have a tree depth greater than 0.
+
+Answering yes will set the tree depth of the extent list to 0.
+
+.SS "DISCONTIG_BG_COUNT"
+A discontiguous block group has an extent list which records all the clusters
+allocated to it. A block group claims to have more records than can actually
+fit.
+
+Answering yes will set the record count to the maximum possible.
+
+.SS "DISCONTIG_BG_REC_RANGE"
+Block groups set aside clusters to be used for metadata.  A discontiguous
+block group claims to contain clusters beyond the end of the volume.
+
+Answering yes will remove the block group.
+
+.SS "DISCONTIG_BG_CORRUPT_LEAVES"
+A discontiguous block group has an extent list which records all the clusters
+allocated to it.  A group has more than one extent claiming to have an
+impossible number of clusters.
+
+Answering yes will remove the block group.
+
+.SS "DISCONTIG_BG_CLUSTERS"
+Extent records in a discontiguous block group were found having more clusters
+allocated then a block group can have.
+
+Answering yes will remove the block group.
+
+.SS "DISCONTIG_BG_LESS_CLUSTERS"
+Extent records in a discontiguous block group were found having less clusters
+allocated then a block group can have.
+
+Answering yes will remove the block group.
+
+.SS "DISCONTIG_BG_NEXT_FREE_REC"
+A discontiguous block group has an extent list which records all the clusters
+allocated to it. A group was found with fewer filled in extents than it claims
+to have.  The filled in extents describe a complete and correct group.
+
+Answering yes will set the used extent count to the number of filled extents.
+
+.SS "DISCONTIG_BG_LIST_CORRUPT"
+A discontiguous block group has an extent list which records all the clusters
+allocated to it.  The group claims to have more extents than is possible, and
+the existing extents contain errors.
+
+Answering yes will remove the block group.
+
+.SS "DISCONTIG_BG_REC_CORRUPT"
+A discontiguous block group has a extent list which records all the clusters
+allocated to it.  A group was found with one extent claiming too many
+clusters but the sum of the remaining extents are equal to the total clusters
+a group must have.
+
+Answering yes will remove the block group.
+
+.SS "DISCONTIG_BG_LEAF_CLUSTERS"
+A discontiguous block group has a extent list which records all the clusters
+allocated to it.  A group was found with one extent claiming too many
+clusters, but the remaining extents are correct.
+
+Answering yes will set the number of the clusters on the broken extent
+to the difference between the total clusters a group must have and the
+sum of the remaining extents.
+
 \" pass1.c
 
 .SS "INODE_ALLOC_REPAIR"
diff --git a/fsck.ocfs2/pass0.c b/fsck.ocfs2/pass0.c
index aac0561..3715332 100644
--- a/fsck.ocfs2/pass0.c
+++ b/fsck.ocfs2/pass0.c
@@ -155,6 +155,197 @@ out:
 	return ret;
 }
 
+static void check_discontig_bg(o2fsck_state *ost, int cpg,
+			       struct ocfs2_group_desc *bg,
+			       int *changed, int *clear_ref)
+{
+	uint64_t blkno = bg->bg_blkno;
+	int next_free, i, total_clusters = 0;
+	int fix_pos = -1;
+	struct ocfs2_extent_rec *rec;
+
+	if (bg->bg_list.l_tree_depth &&
+	    prompt(ost, PY, PR_DISCONTIG_BG_DEPTH,
+		   "Discontiguous Group descriptor at block %"PRIu64" has "
+		   "a tree depth %u which is greater than 0. "
+		   "Change it to 0?", blkno, bg->bg_list.l_tree_depth)) {
+		bg->bg_list.l_tree_depth = 0;
+		*changed = 1;
+	}
+
+	if ((bg->bg_list.l_count >
+	     ocfs2_extent_recs_per_gd(ost->ost_fs->fs_blocksize)) &&
+	    prompt(ost, PY, PR_DISCONTIG_BG_COUNT,
+		   "Discontigous group descriptor at block %"PRIu64" has "
+		   "an extent count of %u, but discontiguous groups can "
+		   "only hold %u records.  Set it to %u?", blkno,
+		   bg->bg_list.l_count,
+		   ocfs2_extent_recs_per_gd(ost->ost_fs->fs_blocksize),
+		   ocfs2_extent_recs_per_gd(ost->ost_fs->fs_blocksize))) {
+		bg->bg_list.l_count =
+			ocfs2_extent_recs_per_gd(ost->ost_fs->fs_blocksize);
+		*changed = 1;
+	}
+
+	if (bg->bg_list.l_next_free_rec > bg->bg_list.l_count)
+		next_free = bg->bg_list.l_count;
+	else
+		next_free = bg->bg_list.l_next_free_rec;
+
+	for (i = 0; i < next_free; i++) {
+		rec = &bg->bg_list.l_recs[i];
+
+		/*
+		 * We treat e_blkno = 0 and e_leaf_cluster = 0 as the
+		 * end of the extent list so that we can find the proper
+		 * l_next_free_rec.
+		 */
+		if (!rec->e_blkno && !rec->e_leaf_clusters)
+			break;
+
+		if (ocfs2_block_out_of_range(ost->ost_fs, rec->e_blkno) ||
+		    ocfs2_block_out_of_range(ost->ost_fs, rec->e_blkno +
+			ocfs2_clusters_to_blocks(ost->ost_fs,
+						 rec->e_leaf_clusters) - 1)) {
+			if (prompt(ost, PY, PR_DISCONTIG_BG_REC_RANGE,
+				   "Discontiguous block group %"PRIu64" in "
+				   "chain %d of inode %"PRIu64" claims "
+				   "clusters which is out of range. "
+				   "Drop this group?",
+				   blkno, bg->bg_chain,
+				   (uint64_t)bg->bg_parent_dinode))
+				*clear_ref = 1;
+			goto out;
+		}
+
+		if (rec->e_leaf_clusters > cpg) {
+			if (fix_pos >= 0) {
+				if (prompt(ost, PY,
+					   PR_DISCONTIG_BG_CORRUPT_LEAVES,
+					   "Discontiguous block group %"PRIu64
+					   " in chain %d of inode %"PRIu64" "
+					   "has errors in more than one extent "
+					   "record.  Record %d claims %u "
+					   "clusters and record %d claims %u "
+					   "clusters, but a group does not "
+					   "contain more than %u clusters. "
+					   "Drop this group?", blkno,
+					   bg->bg_chain,
+					   (uint64_t)bg->bg_parent_dinode,
+					   fix_pos,
+					   bg->bg_list.l_recs[fix_pos].e_leaf_clusters,
+					   i, rec->e_leaf_clusters, cpg))
+					*clear_ref = 1;
+				goto out;
+			}
+			fix_pos = i;
+			continue;
+		}
+
+		if ((total_clusters + rec->e_leaf_clusters) > cpg) {
+			if (total_clusters == cpg) {
+				if (fix_pos >= 0) {
+					/*
+					 * We have to drop the group here since
+					 * both l_next_free_rec and a extent
+					 * record have errors.
+					 */
+					if (prompt(ost, PY,
+						   PR_DISCONTIG_BG_LIST_CORRUPT,
+						   "Discontiguous group "
+						   "descriptor at block "
+						   "%"PRIu64" claims to use %u "
+						   "extents but only has %u "
+						   "filled in.  The filled in "
+						   "records contain errors. "
+						   "Drop this group?",
+						   blkno,
+						   bg->bg_list.l_next_free_rec,
+						   i))
+						*clear_ref = 1;
+					goto out;
+				}
+
+				/*
+				 * break out here so that we can fix the
+				 * l_next_free_rec.
+				 */
+				break;
+			} else {
+				if (prompt(ost, PY, PR_DISCONTIG_BG_CLUSTERS,
+					   "Discontiguous group descriptor at "
+					   "block %"PRIu64" claims to have %u "
+					   "clusters but a group does not "
+					   "contain more than %u clusters. "
+					   "Drop the group?",
+					   blkno,
+					   total_clusters +
+					   rec->e_leaf_clusters, cpg))
+					*clear_ref = 1;
+				goto out;
+			}
+		} else
+			total_clusters += rec->e_leaf_clusters;
+	}
+
+	if (bg->bg_list.l_next_free_rec != i) {
+		/* Change l_next_free_rec since the extent list look sane. */
+		if (prompt(ost, PY,
+			   PR_DISCONTIG_BG_NEXT_FREE_REC,
+			   "Discontiguous group descriptor at "
+			   "block %"PRIu64" claims to use %u "
+			   "extents but only has %u filled in. "
+			   "The filled in records appear to "
+			   "be correct.  Set the used extent "
+			   "count to the number filled in?",
+			   blkno, bg->bg_list.l_next_free_rec,
+			   i)) {
+			bg->bg_list.l_next_free_rec = i;
+			*changed = 1;
+		}
+	}
+
+	if (fix_pos < 0 && total_clusters < cpg) {
+		if (prompt(ost, PY, PR_DISCONTIG_BG_LESS_CLUSTERS,
+			   "Discontiguous group descriptor at "
+			   "block %"PRIu64" claims to have %u "
+			   "clusters but a group does not "
+			   "contain less than %u clusters. "
+			   "Drop the group?",
+			   blkno, total_clusters, cpg))
+			*clear_ref = 1;
+		goto out;
+	}
+
+	if (fix_pos >= 0) {
+		rec = &bg->bg_list.l_recs[fix_pos];
+
+		if (total_clusters == cpg) {
+			if (prompt(ost, PY, PR_DISCONTIG_BG_REC_CORRUPT,
+				   "Extent record %d of discontiguous group "
+				   "descriptor at block %"PRIu64" claims %u "
+				   "clusters, but a group does not "
+				   "contain more than %u clusters. "
+				   "Drop the group?",
+				   fix_pos, blkno, rec->e_leaf_clusters, cpg))
+					*clear_ref = 1;
+				goto out;
+		}
+
+		if (prompt(ost, PY, PR_DISCONTIG_BG_LEAF_CLUSTERS,
+			   "Extent record %d of discontiguous group "
+			   "descriptor %"PRIu64" claims %u clusters, "
+			   "but it should only have %u.  Correct it?",
+			   fix_pos, blkno, rec->e_leaf_clusters,
+			   cpg - total_clusters)) {
+			rec->e_leaf_clusters = cpg - total_clusters;
+			*changed = 1;
+		}
+	}
+out:
+	return;
+}
+
 static errcode_t repair_group_desc(o2fsck_state *ost,
 				   struct ocfs2_dinode *di,
 				   struct chain_state *cs,
@@ -251,6 +442,11 @@ static errcode_t repair_group_desc(o2fsck_state *ost,
 		changed = 1;
 	}
 
+	if (ocfs2_gd_is_discontig(bg))
+		check_discontig_bg(ost, cs->cs_cpg, bg, &changed, clear_ref);
+	if (*clear_ref)
+		goto out;
+
 	/* XXX check bg_bits vs cpg/bpc. */
 
 	if (changed) {
-- 
1.7.1.GIT




More information about the Ocfs2-tools-devel mailing list