[Ocfs2-tools-devel] [PATCH 3/6] ocfs2: add fsck.ocfs2 support to ocfs2 local alloc rec

Srinivas Eeda srinivas.eeda at oracle.com
Mon May 7 16:49:07 PDT 2012


This patch enhances fsck.ocfs2 code to handle new ocfs2 local alloc record

Signed-off-by: Srinivas Eeda <srinivas.eeda at oracle.com>
---
 fsck.ocfs2/fsck.ocfs2.checks.8.in |   24 ++++
 fsck.ocfs2/pass1.c                |  264 +++++++++++++++++++++++++++----------
 fsck.ocfs2/slot_recovery.c        |   88 +++++++-----
 3 files changed, 272 insertions(+), 104 deletions(-)

diff --git a/fsck.ocfs2/fsck.ocfs2.checks.8.in b/fsck.ocfs2/fsck.ocfs2.checks.8.in
index 45f9336..0527e03 100644
--- a/fsck.ocfs2/fsck.ocfs2.checks.8.in
+++ b/fsck.ocfs2/fsck.ocfs2.checks.8.in
@@ -440,6 +440,30 @@ Answering yes clears the local allocator.  No information is lost but the
 global bitmap allocator may need to be updated to reflect clusters that were
 reserved for the local allocator but were free.
 
+.SS "LALLOC_REC_COUNT"
+The given local allocator has more records than allowed.
+
+Answering yes will reset the record count to 0 and clear bitmap. No allocated
+data will be lost.
+
+.SS "LALLOC_NZ_REC_COUNT"
+The given local allocator claims to have records when the bitmap is empty.
+
+Answering yes will reset the record count to 0. No allocated data will
+be lost.
+
+.SS "LALLOC_NZ_BM_COUNT"
+The given local allocator has zero records but local alloc bitmap count is not
+empty.
+
+Answering yes will reset the bitmap count to 0. No allocated data will
+be lost.
+
+.SS "LALLOC_CLSTR_COUNT"
+The given local allocator has more clusters than in the bitmap.
+
+Answering yes will reset the local alloc block. No allocated data will be lost.
+
 .SS "DEALLOC_COUNT"
 The given truncate log inode contains a count that is greater than the 
 value that is possible given the size of the inode.
diff --git a/fsck.ocfs2/pass1.c b/fsck.ocfs2/pass1.c
index 3590a2d..0ec2dea 100644
--- a/fsck.ocfs2/pass1.c
+++ b/fsck.ocfs2/pass1.c
@@ -182,13 +182,18 @@ static errcode_t verify_local_alloc(o2fsck_state *ost,
 				    struct ocfs2_dinode *di)
 {
 	struct ocfs2_local_alloc *la = &di->id2.i_lab;
-	uint32_t max;
-	int broken = 0, changed = 0, clear = 0;
+	uint32_t max, start, end, clusters;
+	int i, broken = 0, changed = 0, clear = 0;
 	errcode_t ret = 0;
 
-	verbosef("la_bm_off %u size %u total %u used %u\n", la->la_bm_off,
-		 la->la_size, di->id1.bitmap1.i_total,
-		 di->id1.bitmap1.i_used);
+	if (ocfs2_supports_discontig_la(&di->id2.i_super))
+		verbosef("size %u la_rec_count %u clusters %u used %u\n",
+			 la->la_size, la->la_rec_count,
+			 di->id1.bitmap1.i_total, di->id1.bitmap1.i_used);
+	else
+		verbosef("la_bm_off %u size %u total %u used %u\n",
+			 la->la_bm_off, la->la_size, di->id1.bitmap1.i_total,
+			 di->id1.bitmap1.i_used);
 
 	max = ocfs2_local_alloc_size(ost->ost_fs->fs_blocksize);
 
@@ -206,44 +211,48 @@ static errcode_t verify_local_alloc(o2fsck_state *ost,
 		}
 	}
 
+	if (la->la_bm_off + di->id1.bitmap1.i_total >
+	    ost->ost_fs->fs_clusters) {
+		broken = 1;
+		if (prompt(ost, PY, PR_LALLOC_BM_STRADDLE,
+			   "Local alloc inode %"PRIu64" claims to "
+			   "have a bitmap that covers clusters numbered %u "
+			   "through %u but %u is the last valid cluster. "
+			   "Mark the local bitmap as unused?",
+			   (uint64_t)di->i_blkno,
+			   la->la_bm_off,
+			   la->la_bm_off + di->id1.bitmap1.i_total - 1,
+			   ost->ost_fs->fs_clusters - 1)) {
+
+			clear = 1;
+		}
+		/* we can't possibly check _used if bm/off and total are
+		 * so busted */
+		goto out;
+	}
+
 	if (di->id1.bitmap1.i_total == 0) {
 		/* ok, it's not used.  we don't mark these errors as 
 		 * 'broken' as the kernel shouldn't care.. right? */
 		if (di->id1.bitmap1.i_used != 0) {
 			if (prompt(ost, PY, PR_LALLOC_NZ_USED,
-				   "Local alloc inode %"PRIu64" "
-			    "isn't in use bit its i_used isn't 0.  Set it to "
-			    "0?", (uint64_t)di->i_blkno)) {
+				   "Local alloc inode %"PRIu64" isn't in use "
+				   "bit its i_used isn't 0.  Set it to "
+				   "0?", (uint64_t)di->i_blkno)) {
 
 				di->id1.bitmap1.i_used = 0;
 				changed = 1;
 			}
 		}
-
 		if (la->la_bm_off != 0) {
 			if (prompt(ost, PY, PR_LALLOC_NZ_BM,
-				   "Local alloc inode %"PRIu64" "
-			    "isn't in use bit its i_bm_off isn't 0.  Set it "
-			    "to 0?", (uint64_t)di->i_blkno)) {
-
+				   "Local alloc inode %"PRIu64" isn't in use "
+				   "bit its i_bm_off isn't 0.  Set it to 0?",
+				   (uint64_t)di->i_blkno)) {
 				la->la_bm_off = 0;
 				changed = 1;
 			}
 		}
-
-		goto out;
-	}
-
-	if (la->la_bm_off >= ost->ost_fs->fs_clusters) {
-		broken = 1;
-		if (prompt(ost, PY, PR_LALLOC_BM_OVERRUN,
-			   "Local alloc inode %"PRIu64" claims to "
-			   "contain a bitmap that starts at cluster %u but "
-			   "the volume contains %u clusters.  Mark the local "
-			   "alloc bitmap as unused?", (uint64_t)di->i_blkno,
-			   la->la_bm_off, ost->ost_fs->fs_clusters)) {
-			clear = 1;
-		}
 	}
 
 	if (di->id1.bitmap1.i_total > la->la_size * 8) {
@@ -261,26 +270,6 @@ static errcode_t verify_local_alloc(o2fsck_state *ost,
 		}
 	}
 
-	if (la->la_bm_off + di->id1.bitmap1.i_total >
-	    ost->ost_fs->fs_clusters) {
-		broken = 1;
-		if (prompt(ost, PY, PR_LALLOC_BM_STRADDLE,
-			   "Local alloc inode %"PRIu64" claims to "
-			   "have a bitmap that covers clusters numbered %u "
-			   "through %u but %u is the last valid cluster. "
-			   "Mark the local bitmap as unused?",
-			   (uint64_t)di->i_blkno,
-			   la->la_bm_off,
-			   la->la_bm_off + di->id1.bitmap1.i_total - 1, 
-			   ost->ost_fs->fs_clusters - 1)) {
-
-			clear = 1;
-		}
-		/* we can't possibly check _used if bm/off and total are
-		 * so busted */
-		goto out;
-	}
-
 	if (di->id1.bitmap1.i_used > di->id1.bitmap1.i_total) {
 		broken = 1;
 		if (prompt(ost, PY, PR_LALLOC_USED_OVERRUN,
@@ -295,6 +284,121 @@ static errcode_t verify_local_alloc(o2fsck_state *ost,
 		}
 	}
 
+	if (!ocfs2_supports_discontig_la(&di->id2.i_super))
+		goto out;
+
+	if (di->id1.bitmap1.i_total == 0) {
+		if (la->la_rec_count != 0) {
+			if (prompt(ost, PY, PR_LALLOC_NZ_REC_COUNT,
+				   "Local alloc inode %"PRIu64" isn't in use "
+				   "but has %u records. Set the record count "
+				   "to 0?", (uint64_t)di->i_blkno,
+				   la->la_rec_count)) {
+
+				la->la_rec_count = 0;
+				changed = 1;
+
+			}
+		}
+		goto out;
+	}
+
+	if (la->la_rec_count == 0) {
+		if (di->id1.bitmap1.i_total != 0) {
+			if (prompt(ost, PY, PR_LALLOC_NZ_BM_COUNT,
+				   "Local alloc inode %"PRIu64" records is 0 "
+				   "but has %u bits set. Set the bit count "
+				   "to 0?", (uint64_t)di->i_blkno,
+				   la->la_rec_count)) {
+
+				di->id1.bitmap1.i_total = 0;
+				changed = 1;
+
+			}
+		}
+	}
+
+	if (la->la_rec_count > OCFS2_MAX_LOCAL_ALLOC_REC_LIMIT) {
+		broken = 1;
+		if (prompt(ost, PY, PR_LALLOC_REC_COUNT,
+			   "Local alloc inode %"PRIu64" claims to "
+			   "have %u records but max allowed records is %u "
+			   "Set the inode's count to the maximum?",
+			   (uint64_t)di->i_blkno, la->la_rec_count,
+			   OCFS2_MAX_LOCAL_ALLOC_REC_LIMIT)) {
+
+			la->la_rec_count = OCFS2_MAX_LOCAL_ALLOC_REC_LIMIT;
+			changed = 1;
+		}
+	}
+
+	clusters = 0;
+	for (i = 0; i < la->la_rec_count; i++) {
+
+		start = la->la_recs[i].la_start;
+		end   = la->la_recs[i].la_clusters + start;
+
+		verbosef("bitmap offset %u clusters %u\n",
+			la->la_recs[i].la_start, la->la_recs[i].la_clusters);
+
+		if (start >= ost->ost_fs->fs_clusters) {
+			if (prompt(ost, PY, PR_LALLOC_BM_OVERRUN,
+				   "Local alloc inode %"PRIu64" claims to "
+				   "contain a bitmap that starts at cluster "
+				   "%u but the volume contains %u clusters. "
+				   "Mark the local alloc bitmap as unused?",
+				   (uint64_t)di->i_blkno, start,
+				   ost->ost_fs->fs_clusters)) {
+
+				clear = 1;
+				goto out;
+		    }
+
+		}
+
+		if (end >= ost->ost_fs->fs_clusters) {
+			broken = 1;
+			if (prompt(ost, PY, PR_LALLOC_BM_STRADDLE,
+				   "Local alloc inode %"PRIu64" record claims "
+				   "to contain a extent that starts at cluster "
+				   "%u, ends at %u but the volume contains %u "
+				   "clusters. Mark the local alloc bitmap as "
+				   " unused? ", (uint64_t)di->i_blkno, start,
+				   end, ost->ost_fs->fs_clusters)) {
+
+				clear = 1;
+				goto out;
+			}
+		}
+		clusters += la->la_recs[i].la_clusters;
+	}
+
+	if (clusters >= ost->ost_fs->fs_clusters) {
+		if (prompt(ost, PY, PR_LALLOC_BM_STRADDLE,
+			   "Local alloc inode %"PRIu64" record claims "
+			   "to contain %u clusters but the volume "
+			   "contains %u clusters. Mark the local alloc "
+			   "bitmap as unused? ",
+			   (uint64_t)di->i_blkno, clusters,
+			   ost->ost_fs->fs_clusters)) {
+
+			clear = 1;
+			goto out;
+		}
+	}
+
+	if (di->id1.bitmap1.i_total != clusters) {
+		if (prompt(ost, PY, PR_LALLOC_CLSTR_COUNT,
+			   "Local alloc inode %"PRIu64" has %u bits set "
+			   "but only %u clusters are reserved. Set it to %u? ",
+			    (uint64_t)di->i_blkno, di->id1.bitmap1.i_total,
+			    clusters, clusters)) {
+
+			clear = 1;
+			goto out;
+		}
+	}
+
 out:
 	if (broken && !clear &&
 	    prompt(ost, PY, PR_LALLOC_CLEAR,
@@ -308,7 +412,8 @@ out:
 		di->id1.bitmap1.i_total = 0;
 		di->id1.bitmap1.i_used = 0;
 		la->la_bm_off = 0;
-		memset(la->la_bitmap, 0, 
+		la->la_rec_count = 0;
+		memset(la->la_recs, 0,
 		       ocfs2_local_alloc_size(ost->ost_fs->fs_blocksize));
 		changed = 1;
 	}
@@ -1099,10 +1204,12 @@ static void mark_local_allocs(o2fsck_state *ost)
 	uint16_t max_slots;
 	char *buf = NULL;
 	errcode_t ret;
-	uint64_t blkno, start, end;
+	uint64_t blkno;
+	uint32_t start, end, clusters;
 	struct ocfs2_dinode *di;
 	struct ocfs2_local_alloc *la;
-	int bit;
+	int i, j, bit;
+	void *bitmap;
 
 	max_slots = OCFS2_RAW_SB(ost->ost_fs->fs_super)->s_max_slots;
 
@@ -1134,11 +1241,11 @@ static void mark_local_allocs(o2fsck_state *ost)
 			goto out;
 		}
 
-		la = &di->id2.i_lab;
-
 		if (di->id1.bitmap1.i_total == 0)
 			continue;
 
+		la = &di->id2.i_lab;
+
 		/* make sure we don't try to work with a crazy bitmap.  It
 		 * can only be this crazy if the user wouldn't let us fix
 		 * it up.. just ignore it */
@@ -1148,31 +1255,54 @@ static void mark_local_allocs(o2fsck_state *ost)
 		    di->id1.bitmap1.i_total > la->la_size * 8)
 			continue;
 
-		start = la->la_bm_off;
-		end = la->la_bm_off + di->id1.bitmap1.i_total;
+		/*
+		 * if discontig localalloc is not enabled and localalloc bitmap
+		 * is in use then adjust the info into the first record
+		 */
+		if (!ocfs2_supports_discontig_la(&di->id2.i_super) &&
+		    la->la_bm_off) {
+			la->la_rec_count = 1;
+			la->la_recs[0].la_start = la->la_bm_off;
+			la->la_recs[0].la_clusters = di->id1.bitmap1.i_total;
+		}
 
-		if (start >= ost->ost_fs->fs_clusters || 
-		    end < start ||
-		    end > ost->ost_fs->fs_clusters)
+		if (!la->la_rec_count || (la->la_rec_count >=
+					  OCFS2_MAX_LOCAL_ALLOC_REC_LIMIT))
+			continue;
+
+		clusters = 0;
+		for (i = 0; i < la->la_rec_count; i++)
+			clusters += la->la_recs[i].la_clusters;
+
+		if (!clusters || (clusters > di->id1.bitmap1.i_total))
 			continue;
 
 		/* bits that are clear in the local alloc haven't been 
 		 * used by the slot yet, they must still be set in the
 		 * main bitmap.  bits that are set might have been used
 		 * and already freed in the main bitmap. */
-		for(bit = 0; bit < di->id1.bitmap1.i_total; bit++) {
-			bit = ocfs2_find_next_bit_clear(la->la_bitmap,
-							di->id1.bitmap1.i_total,
-							bit);
+		bit = 0;
+		bitmap = OCFS2_LOCAL_ALLOC_BITMAP(la);
+		for (i = 0; i < la->la_rec_count; i++) {
+
+			start = la->la_recs[i].la_start;
+			end   = start + la->la_recs[i].la_clusters;
+			if ((start > ost->ost_fs->fs_clusters) ||
+			    (end > ost->ost_fs->fs_clusters))
+				break;
+
+			for (j = 0; j < la->la_recs[i].la_clusters; j++) {
+				if (ocfs2_test_bit(bit++, bitmap))
+					continue;
+
+				start = la->la_recs[i].la_start + j;
+				if (start > ost->ost_fs->fs_clusters)
+					continue;
 
-			if (bit < di->id1.bitmap1.i_total) {
 				verbosef("bit %u is clear, reserving "
-					 "cluster %u\n", bit,
-					 bit + la->la_bm_off);
+					 "cluster %u\n", j, start);
 
-				o2fsck_mark_cluster_allocated(ost,
-							      bit + 
-							      la->la_bm_off);
+				o2fsck_mark_cluster_allocated(ost, start);
 			}
 		}
 	}
diff --git a/fsck.ocfs2/slot_recovery.c b/fsck.ocfs2/slot_recovery.c
index 784602c..58378bf 100644
--- a/fsck.ocfs2/slot_recovery.c
+++ b/fsck.ocfs2/slot_recovery.c
@@ -91,7 +91,7 @@ static errcode_t ocfs2_clear_local_alloc(ocfs2_filesys *fs,
 					 int slot)
 {
 	errcode_t ret = 0;
-	int bit_off, left, count, start, was_set = 0, cleared = 0;
+	int i, bit_off, left, count, prev, start, was_set = 0, cleared = 0;
 	uint64_t la_start_blk;
 	uint64_t blkno;
 	void *bitmap;
@@ -110,49 +110,63 @@ static errcode_t ocfs2_clear_local_alloc(ocfs2_filesys *fs,
 	if (di->id1.bitmap1.i_used == di->id1.bitmap1.i_total)
 		goto clear_inode;
 
-	la_start_blk = ocfs2_clusters_to_blocks(fs, la->la_bm_off);
-	bitmap = la->la_bitmap;
-	start = count = bit_off = 0;
-	left = di->id1.bitmap1.i_total;
+	/*
+	 * if discontig localalloc is not enabled and bitmap is in use then
+	 * fill the first record appropriately
+	 */
+	if (!ocfs2_supports_discontig_la(&di->id2.i_super) && la->la_bm_off) {
+		la->la_rec_count = 1;
+		la->la_recs[0].la_start = la->la_bm_off;
+		la->la_recs[0].la_clusters = di->id1.bitmap1.i_total;
+	}
 
-	while ((bit_off = ocfs2_find_next_bit_clear(bitmap, left, start))
-	       != -1) {
-		if ((bit_off < left) && (bit_off == start)) {
-			count++;
-			start++;
-			continue;
-		}
-		if (count) {
-			blkno = la_start_blk +
-				ocfs2_clusters_to_blocks(fs, start - count);
-
-			ret = ocfs2_test_clusters(fs, count,
-						  blkno, 1, &was_set);
-			if (ret)
-				goto bail;
-
-			if (!was_set) {
-				ret = OCFS2_ET_INVALID_BIT;
-				goto bail;
+	bitmap = OCFS2_LOCAL_ALLOC_BITMAP(la);
+	left = start = count = bit_off = 0;
+
+	for (i = 0; i < la->la_rec_count; i++) {
+		la_start_blk =
+			ocfs2_clusters_to_blocks(fs, la->la_recs[i].la_start);
+		prev = start = left;
+		left += la->la_recs[i].la_clusters;
+		while ((bit_off =
+			ocfs2_find_next_bit_clear(bitmap, left, start)) != -1) {
+			if ((bit_off < left) && (bit_off == start)) {
+				count++;
+				start++;
+				continue;
 			}
-
-			ret = ocfs2_free_clusters(fs, count, blkno);
-			if (ret)
-				goto bail;
-
-			cleared = 1;
+			if (count) {
+				blkno = la_start_blk +
+					ocfs2_clusters_to_blocks(fs,
+						 ((start - prev) - count));
+				ret = ocfs2_test_clusters(fs, count, blkno, 1,
+							  &was_set);
+				if (ret)
+					goto bail;
+				if (!was_set) {
+					ret = OCFS2_ET_INVALID_BIT;
+					goto bail;
+				}
+
+				ret = ocfs2_free_clusters(fs, count, blkno);
+				if (ret)
+					goto bail;
+				cleared = 1;
+			}
+			if (bit_off >= left)
+				break;
+			count = 1;
+			start = bit_off + 1;
 		}
-
-		if (bit_off >= left)
-			break;
-		count = 1;
-		start = bit_off + 1;
 	}
+
 clear_inode:
 	di->id1.bitmap1.i_total = 0;
 	di->id1.bitmap1.i_used = 0;
-	la->la_bm_off = 0;
-	memset(la->la_bitmap, 0, ocfs2_local_alloc_size(fs->fs_blocksize));
+	la->la_rec_count = 0;
+	la->la_bm_off  = 0;
+	memset(OCFS2_LOCAL_ALLOC_BITMAP(la), 0,
+	       ocfs2_local_alloc_size(fs->fs_blocksize));
 
 	ret = ocfs2_write_inode(fs, di->i_blkno, (char *)di);
 	if (!ret && cleared)
-- 
1.5.4.3




More information about the Ocfs2-tools-devel mailing list