[patch 2/3] reiserfs: ignore s_bmap_nr on disk for file systems >= 8 TiB

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



 The reiserfs disk format is designed to handle file systems up to
 2^32-1 blocks, which at 4KiB blocks means ~ 16 TiB - 4KiB.

 Unfortunately, the superblock's s_bmap_nr value, which contains a
 count of the number of bitmap blocks in the file system is a 16 bit
 value. This limits the usable size of the file system to
 8 TiB (4096^2 * 8 * 65536).

 This patch implements the changes introduced with reiserfsprogs 3.6.20,
 where s_bmap_nr is zeroed out if the value would overflow.

 Older implementations will see the zero value of s_bmap_nr and abort
 the mount due to a vmalloc(0) before reading the bitmaps. This is safer
 than the current behavior which can result in corruption or BUG's.

Signed-off-by: Jeff Mahoney <jeffm@xxxxxxxx>

---

 fs/reiserfs/bitmap.c           |   39 ++++++++++++++++++++++-----------------
 fs/reiserfs/journal.c          |    6 +++---
 fs/reiserfs/resize.c           |    6 +++---
 fs/reiserfs/super.c            |   15 +++++++++++++++
 include/linux/reiserfs_fs.h    |    5 +++++
 include/linux/reiserfs_fs_sb.h |    1 +
 6 files changed, 49 insertions(+), 23 deletions(-)

--- a/fs/reiserfs/bitmap.c	2007-08-08 15:59:01.000000000 -0400
+++ b/fs/reiserfs/bitmap.c	2007-08-08 16:09:59.000000000 -0400
@@ -62,6 +62,7 @@ static inline void get_bit_address(struc
 int is_reusable(struct super_block *s, b_blocknr_t block, int bit_value)
 {
 	unsigned int bmap, offset;
+	unsigned int bmap_count = reiserfs_bmap_count(s);
 
 	if (block == 0 || block >= SB_BLOCK_COUNT(s)) {
 		reiserfs_warning(s,
@@ -77,25 +78,26 @@ int is_reusable(struct super_block *s, b
 	if (unlikely(test_bit(REISERFS_OLD_FORMAT,
 			      &(REISERFS_SB(s)->s_properties)))) {
 		b_blocknr_t bmap1 = REISERFS_SB(s)->s_sbh->b_blocknr + 1;
-		if (block >= bmap1 && block <= bmap1 + SB_BMAP_NR(s)) {
+		if (block >= bmap1 &&
+		    block <= bmap1 + bmap_count) {
 			reiserfs_warning(s, "vs: 4019: is_reusable: "
 					 "bitmap block %lu(%u) can't be freed or reused",
-					 block, SB_BMAP_NR(s));
+					 block, bmap_count);
 			return 0;
 		}
 	} else {
 		if (offset == 0) {
 			reiserfs_warning(s, "vs: 4020: is_reusable: "
 					 "bitmap block %lu(%u) can't be freed or reused",
-					 block, SB_BMAP_NR(s));
+					 block, bmap_count);
 			return 0;
 		}
 	}
 
-	if (bmap >= SB_BMAP_NR(s)) {
+	if (bmap >= bmap_count) {
 		reiserfs_warning(s,
 				 "vs-4030: is_reusable: there is no so many bitmap blocks: "
-				 "block=%lu, bitmap_nr=%d", block, bmap);
+				 "block=%lu, bitmap_nr=%u", block, bmap);
 		return 0;
 	}
 
@@ -145,8 +147,8 @@ static int scan_bitmap_block(struct reis
 
 	BUG_ON(!th->t_trans_id);
 
-	RFALSE(bmap_n >= SB_BMAP_NR(s), "Bitmap %d is out of range (0..%d)",
-	       bmap_n, SB_BMAP_NR(s) - 1);
+	RFALSE(bmap_n >= reiserfs_bmap_count(s), "Bitmap %u is out of "
+	       "range (0..%u)", bmap_n, reiserfs_bmap_count(s) - 1);
 	PROC_INFO_INC(s, scan_bitmap.bmap);
 /* this is unclear and lacks comments, explain how journal bitmaps
    work here for the reader.  Convey a sense of the design here. What
@@ -251,12 +253,12 @@ static int bmap_hash_id(struct super_blo
 	} else {
 		hash_in = (char *)(&id);
 		hash = keyed_hash(hash_in, 4);
-		bm = hash % SB_BMAP_NR(s);
+		bm = hash % reiserfs_bmap_count(s);
 		if (!bm)
 			bm = 1;
 	}
 	/* this can only be true when SB_BMAP_NR = 1 */
-	if (bm >= SB_BMAP_NR(s))
+	if (bm >= reiserfs_bmap_count(s))
 		bm = 0;
 	return bm;
 }
@@ -330,10 +332,10 @@ static int scan_bitmap(struct reiserfs_t
 
 	get_bit_address(s, *start, &bm, &off);
 	get_bit_address(s, finish, &end_bm, &end_off);
-	if (bm > SB_BMAP_NR(s))
+	if (bm > reiserfs_bmap_count(s))
 		return 0;
-	if (end_bm > SB_BMAP_NR(s))
-		end_bm = SB_BMAP_NR(s);
+	if (end_bm > reiserfs_bmap_count(s))
+		end_bm = reiserfs_bmap_count(s);
 
 	/* When the bitmap is more than 10% free, anyone can allocate.
 	 * When it's less than 10% free, only files that already use the
@@ -399,10 +401,12 @@ static void _reiserfs_free_block(struct 
 
 	get_bit_address(s, block, &nr, &offset);
 
-	if (nr >= sb_bmap_nr(rs)) {
+	if (nr >= reiserfs_bmap_count(s)) {
 		reiserfs_warning(s, "vs-4075: reiserfs_free_block: "
-				 "block %lu is out of range on %s",
-				 block, reiserfs_bdevname(s));
+				 "block %lu is out of range on %s "
+				 "(nr=%u,max=%u)", block,
+				 reiserfs_bdevname(s), nr,
+				 reiserfs_bmap_count(s));
 		return;
 	}
 
@@ -1326,12 +1330,13 @@ struct buffer_head *reiserfs_read_bitmap
 int reiserfs_init_bitmap_cache(struct super_block *sb)
 {
 	struct reiserfs_bitmap_info *bitmap;
+	unsigned int bmap_nr = reiserfs_bmap_count(sb);
 
-	bitmap = vmalloc(sizeof (*bitmap) * SB_BMAP_NR(sb));
+	bitmap = vmalloc(sizeof (*bitmap) * bmap_nr);
 	if (bitmap == NULL)
 		return -ENOMEM;
 
-	memset(bitmap, 0, sizeof (*bitmap) * SB_BMAP_NR(sb));
+	memset(bitmap, 0, sizeof (*bitmap) * bmap_nr);
 
 	SB_AP_BITMAP(sb) = bitmap;
 
--- a/fs/reiserfs/journal.c	2007-08-08 15:59:01.000000000 -0400
+++ b/fs/reiserfs/journal.c	2007-08-08 16:03:29.000000000 -0400
@@ -240,7 +240,7 @@ static void cleanup_bitmap_list(struct s
 	if (jb->bitmaps == NULL)
 		return;
 
-	for (i = 0; i < SB_BMAP_NR(p_s_sb); i++) {
+	for (i = 0; i < reiserfs_bmap_count(p_s_sb); i++) {
 		if (jb->bitmaps[i]) {
 			free_bitmap_node(p_s_sb, jb->bitmaps[i]);
 			jb->bitmaps[i] = NULL;
@@ -2651,7 +2651,7 @@ int journal_init(struct super_block *p_s
 	journal->j_persistent_trans = 0;
 	if (reiserfs_allocate_list_bitmaps(p_s_sb,
 					   journal->j_list_bitmap,
-					   SB_BMAP_NR(p_s_sb)))
+					   reiserfs_bmap_count(p_s_sb)))
 		goto free_and_return;
 	allocate_bitmap_nodes(p_s_sb);
 
@@ -2659,7 +2659,7 @@ int journal_init(struct super_block *p_s
 	SB_JOURNAL_1st_RESERVED_BLOCK(p_s_sb) = (old_format ?
 						 REISERFS_OLD_DISK_OFFSET_IN_BYTES
 						 / p_s_sb->s_blocksize +
-						 SB_BMAP_NR(p_s_sb) +
+						 reiserfs_bmap_count(p_s_sb) +
 						 1 :
 						 REISERFS_DISK_OFFSET_IN_BYTES /
 						 p_s_sb->s_blocksize + 2);
--- a/fs/reiserfs/resize.c	2007-08-08 15:59:01.000000000 -0400
+++ b/fs/reiserfs/resize.c	2007-08-08 16:04:14.000000000 -0400
@@ -61,7 +61,7 @@ int reiserfs_resize(struct super_block *
 	}
 
 	/* count used bits in last bitmap block */
-	block_r = SB_BLOCK_COUNT(s) - (SB_BMAP_NR(s) - 1) * s->s_blocksize * 8;
+	block_r = SB_BLOCK_COUNT(s) - (reiserfs_bmap_count(s) - 1) * s->s_blocksize * 8;
 
 	/* count bitmap blocks in new fs */
 	bmap_nr_new = block_count_new / (s->s_blocksize * 8);
@@ -73,7 +73,7 @@ int reiserfs_resize(struct super_block *
 
 	/* save old values */
 	block_count = SB_BLOCK_COUNT(s);
-	bmap_nr = SB_BMAP_NR(s);
+	bmap_nr = reiserfs_bmap_count(s);
 
 	/* resizing of reiserfs bitmaps (journal and real), if needed */
 	if (bmap_nr_new > bmap_nr) {
@@ -206,7 +206,7 @@ int reiserfs_resize(struct super_block *
 			   free_blocks + (block_count_new - block_count -
 					  (bmap_nr_new - bmap_nr)));
 	PUT_SB_BLOCK_COUNT(s, block_count_new);
-	PUT_SB_BMAP_NR(s, bmap_nr_new);
+	PUT_SB_BMAP_NR(s, bmap_would_wrap(bmap_nr_new) ? : bmap_nr_new );
 	s->s_dirt = 1;
 
 	journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB(s));
--- a/fs/reiserfs/super.c	2007-08-08 15:59:01.000000000 -0400
+++ b/fs/reiserfs/super.c	2007-08-08 16:04:51.000000000 -0400
@@ -1713,6 +1713,21 @@ static int reiserfs_fill_super(struct su
 		set_sb_umount_state(rs, REISERFS_ERROR_FS);
 		set_sb_fs_state(rs, 0);
 
+		/* Clear out s_bmap_nr if it would wrap. We can handle this
+		 * case, but older revisions can't. This will cause the
+		 * file system to fail mount on those older implementations,
+		 * avoiding corruption. -jeffm */
+		if (bmap_would_wrap(reiserfs_bmap_count(s)) &&
+		    sb_bmap_nr(rs) != 0) {
+			reiserfs_warning(s, "super-2030: This file system "
+		                         "claims to use %u bitmap blocks in "
+		                         "its super block, but requires %u. "
+		                         "Clearing to zero.", sb_bmap_nr(rs),
+		                         reiserfs_bmap_count(s));
+
+			set_sb_bmap_nr(rs, 0);
+		}
+
 		if (old_format_only(s)) {
 			/* filesystem of format 3.5 either with standard or non-standard
 			   journal */
--- a/include/linux/reiserfs_fs.h	2007-08-08 15:59:01.000000000 -0400
+++ b/include/linux/reiserfs_fs.h	2007-08-08 16:10:59.000000000 -0400
@@ -229,6 +229,11 @@ struct reiserfs_super_block {
          ((!is_reiserfs_jr(SB_DISK_SUPER_BLOCK(s)) ? \
          SB_ONDISK_JOURNAL_SIZE(s) + 1 : SB_ONDISK_RESERVED_FOR_JOURNAL(s)))
 
+/* s_bmap_nr is a u16 */
+#define reiserfs_bmap_count(sb)	reiserfs_bmap_nr(SB_BLOCK_COUNT(sb), sb->s_blocksize)
+#define reiserfs_bmap_nr(count, blk_size) ((count - 1) / (blk_size * 8) + 1)
+#define bmap_would_wrap(n)		(n > ((1LL << 16) - 1))
+
 int is_reiserfs_3_5(struct reiserfs_super_block *rs);
 int is_reiserfs_3_6(struct reiserfs_super_block *rs);
 int is_reiserfs_jr(struct reiserfs_super_block *rs);
--- a/include/linux/reiserfs_fs_sb.h	2007-08-08 15:59:01.000000000 -0400
+++ b/include/linux/reiserfs_fs_sb.h	2007-08-08 15:59:03.000000000 -0400
@@ -410,6 +410,7 @@ struct reiserfs_sb_info {
 	char *s_qf_names[MAXQUOTAS];
 	int s_jquota_fmt;
 #endif
+	unsigned int s_bmap_nr;
 };
 
 /* Definitions of reiserfs on-disk properties: */

-- 
Jeff Mahoney
SUSE Labs

-
To unsubscribe from this list: send the line "unsubscribe reiserfs-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux File System Development]     [Linux BTRFS]     [Linux NFS]     [Linux Filesystems]     [Ext4 Filesystem]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite Forum]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Device Mapper]     [Linux Resources]

  Powered by Linux