[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