[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