[Ocfs2-tools-devel] [PATCH 32/50] fsck.ocfs2: Add check for refcount record list.

Tao Ma tao.ma at oracle.com
Mon Jan 11 07:31:18 PST 2010


Add check for refcount list.
They are REFCOUNT_LIST_COUNT, REFCOUNT_LIST_USED,
REFCOUNT_CLUSTER_RANGE and REFCOUNT_CLUSTER_COLLISION.

Please note that to check whether the refcounted cluster
has some collision, we need a new parameter "c_end" which
indicates the end of the refcount record we have checked
before.

Signed-off-by: Tao Ma <tao.ma at oracle.com>
---
 fsck.ocfs2/fsck.ocfs2.checks.8.in |   38 +++++++++++
 fsck.ocfs2/refcount.c             |  126 ++++++++++++++++++++++++++++++++++++-
 2 files changed, 163 insertions(+), 1 deletions(-)

diff --git a/fsck.ocfs2/fsck.ocfs2.checks.8.in b/fsck.ocfs2/fsck.ocfs2.checks.8.in
index 02d60a6..8ce056a 100644
--- a/fsck.ocfs2/fsck.ocfs2.checks.8.in
+++ b/fsck.ocfs2/fsck.ocfs2.checks.8.in
@@ -599,6 +599,44 @@ An refcount block was found storing a wrong parent location.
 Answering yes will update the data structure in the refcount block to reflect
 its parent's real location on disk.
 
+.SS "REFCOUNT_LIST_COUNT"
+The number of entries in a refcount list is bounded by the size of the block
+which contains it.  An refcount list was found which claims to have more
+entries than would fit in its container.
+
+Answering yes updates the count field in the refcount list to match the
+container. Answering no to this question may stop further fixes from being
+done because the count value can not be trusted.
+
+.SS "REFCOUNT_LIST_USED"
+The number of free entries in a refcount list must be less than the total
+number of entries in the list.   A list was found which claims to have more
+free entries than possible entries.
+
+Answering yes sets the number of free entries in the list equal to the total
+possible entries.
+
+.SS "REFCOUNT_CLUSTER_RANGE"
+A refcount record was found which references a cluster which can not be
+referenced by a refcount.  The referenced cluster is either very early in the
+volume, and thus reserved, or beyond the end of the volume.
+
+Answering yes removes this refcount record from the tree.
+
+.SS "REFCOUNT_CLUSTER_COLLISION"
+A refcount record was found which references a cluster which has a collision
+with the previous valid refcount record.
+
+Answering yes removes this refcount record from the tree.
+
+.SS "REFCOUNT_LIST_EMPTY"
+A refcount list was found which has no refcount record in it. It is normally
+caused by a corrupted refcount record.
+
+Answering yes removes this refcount block from the tree. It will be
+re-generated in refcounted extent records handler if all the other
+information is sane.
+
 \" pass1b.c
 
 .SS "DUP_CLUSTERS_SYSFILE_CLONE"
diff --git a/fsck.ocfs2/refcount.c b/fsck.ocfs2/refcount.c
index 15687b4..60b2d96 100644
--- a/fsck.ocfs2/refcount.c
+++ b/fsck.ocfs2/refcount.c
@@ -16,13 +16,114 @@
  */
 
 #include <inttypes.h>
+#include <assert.h>
+
 #include "ocfs2/ocfs2.h"
 #include "problem.h"
+#include "fsck.h"
+#include "extent.h"
 
 static const char *whoami = "refcount.c";
 
+static void check_rl(o2fsck_state *ost,
+		     uint64_t rb_blkno, uint64_t root_blkno,
+		     struct ocfs2_refcount_list *rl,
+		     uint64_t *c_end, int *changed)
+{
+	struct ocfs2_refcount_rec *rec;
+	uint16_t i;
+	size_t cpy;
+	int trust_used = 1;
+	int max_recs = ocfs2_refcount_recs_per_rb(ost->ost_fs->fs_blocksize);
+
+	verbosef("count %u used %u\n", rl->rl_count, rl->rl_used);
+
+	if (rl->rl_count > max_recs &&
+	    prompt(ost, PY, PR_REFCOUNT_LIST_COUNT,
+		   "Refcount list in refcount tree %"PRIu64" claims to have %u "
+		   "records, but the maximum is %u. Fix the list's count?",
+		   root_blkno, rl->rl_count, max_recs)) {
+
+		rl->rl_count = max_recs;
+		*changed = 1;
+	}
+
+	if (max_recs > rl->rl_count)
+		max_recs = rl->rl_count;
+
+	if (rl->rl_used > max_recs) {
+		if (prompt(ost, PY, PR_REFCOUNT_LIST_USED,
+			   "Refcount list in refcount tree %"PRIu64" claims %u "
+			   "as the used record, but fsck believes "
+			   "the largest valid value is %u.  Clamp the used "
+			   "record value?", root_blkno,
+			   rl->rl_used, max_recs)) {
+
+			rl->rl_used = rl->rl_count;
+			*changed = 1;
+		} else
+			trust_used = 0;
+	}
+
+	if (trust_used)
+		max_recs = rl->rl_used;
+
+	for (i = 0; i < max_recs; i++) {
+		rec = &rl->rl_recs[i];
+
+		/* offer to remove records that point to nowhere */
+		if (ocfs2_block_out_of_range(ost->ost_fs,
+			ocfs2_clusters_to_blocks(ost->ost_fs,
+					rec->r_cpos + rec->r_clusters - 1)) &&
+		    prompt(ost, PY, PR_REFCOUNT_CLUSTER_RANGE,
+			   "Refcount record %u in refcount block %"PRIu64" "
+			   "of refcount tree %"PRIu64" refers to a cluster "
+			   "that is out of range.  Remove "
+			   "this record from the refcount list?",
+			   i, rb_blkno, root_blkno)) {
+			if (!trust_used) {
+				printf("Can't remove the record becuase "
+				       "rl_used hasn't been fixed\n");
+				continue;
+			}
+			goto remove_rec;
+		}
+
+		if (rec->r_cpos < *c_end &&
+		    prompt(ost, PY, PR_REFCOUNT_CLUSTER_COLLISION,
+			   "Refcount record %u in refcount block %"PRIu64" "
+			   "of refcount tree %"PRIu64" refers to a cluster "
+			   "that is collided with the previous record.  Remove "
+			   "this record from the refcount list?",
+			   i, rb_blkno, root_blkno)) {
+			if (!trust_used) {
+				printf("Can't remove the record becuase "
+				       "rl_used hasn't been fixed\n");
+				continue;
+			}
+			goto remove_rec;
+		}
+
+		*c_end = rec->r_cpos + rec->r_clusters;
+		continue;
+remove_rec:
+		cpy = (max_recs - i - 1) * sizeof(*rec);
+		/* shift the remaining recs into this ones place */
+		if (cpy != 0) {
+			memcpy(rec, rec + 1, cpy);
+			memset(&rl->rl_recs[max_recs - 1], 0,
+			       sizeof(*rec));
+			i--;
+		}
+		rl->rl_used--;
+		max_recs--;
+		*changed = 1;
+		continue;
+	}
+}
+
 static errcode_t check_rb(o2fsck_state *ost, uint64_t blkno,
-			  uint64_t root_blkno, int *is_valid)
+			  uint64_t root_blkno, uint64_t *c_end, int *is_valid)
 {
 	int changed = 0;
 	char *buf = NULL;
@@ -97,6 +198,29 @@ static errcode_t check_rb(o2fsck_state *ost, uint64_t blkno,
 
 	/* XXX worry about suballoc node/bit */
 
+	if (rb->rf_flags & OCFS2_REFCOUNT_TREE_FL) {
+		struct extent_info ei = {0, };
+		uint16_t max_recs =
+			ocfs2_extent_recs_per_rb(ost->ost_fs->fs_blocksize);
+
+		check_el(ost, &ei, rb->rf_blkno, &rb->rf_list,
+			 max_recs, &changed);
+	} else {
+		assert(c_end);
+		check_rl(ost, root_blkno, blkno,
+			 &rb->rf_records, c_end, &changed);
+
+		if (!rb->rf_records.rl_used &&
+		    prompt(ost, PY, PR_REFCOUNT_LIST_EMPTY,
+			   "Refcount block %"PRIu64" claims to have no "
+			   "refcount record in it. Consider it as invalid "
+			   "and Remove from tree?",
+			   (uint64_t)rb->rf_blkno)) {
+			*is_valid = 0;
+			changed = 1;
+		}
+	}
+
 	if (changed) {
 		ret = ocfs2_write_refcount_block(ost->ost_fs, blkno, buf);
 		if (ret) {
-- 
1.5.5




More information about the Ocfs2-tools-devel mailing list