summaryrefslogtreecommitdiffstats
path: root/fs/reiserfs/bitmap.c
diff options
context:
space:
mode:
authorJeff Mahoney <jeffm@suse.com>2006-09-30 23:28:43 -0700
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-01 00:39:27 -0700
commit6f01046b35d940079822827498a7dd6d3eec8c6b (patch)
treee65426389691c9d3e7d4f29da73725d15ee8e2f6 /fs/reiserfs/bitmap.c
parent0b3dc17bc0c0997bde9f5d7691ec0cae24258cf7 (diff)
downloadlinux-stable-6f01046b35d940079822827498a7dd6d3eec8c6b.tar.gz
linux-stable-6f01046b35d940079822827498a7dd6d3eec8c6b.tar.bz2
linux-stable-6f01046b35d940079822827498a7dd6d3eec8c6b.zip
[PATCH] reiserfs: reorganize bitmap loading functions
This patch moves the bitmap loading code from super.c to bitmap.c The code is also restructured somewhat. The only difference between new format bitmaps and old format bitmaps is where they are. That's a two liner before loading the block to use the correct one. There's no need for an entirely separate code path. The load path is generally the same, with the pattern being to throw out a bunch of requests and then wait for them, then cache the metadata from the contents. Again, like the previous patches, the purpose is to set up for later ones. Update: There was a bug in the previously posted version of this that resulted in corruption. The problem was that bitmap 0 on new format file systems must be treated specially, and wasn't. A stupid bug with an easy fix. This is hopefully the last fix for the disaster that is the reiserfs bitmap patch set. If a bitmap block was full, first_zero_hint would end up at zero since it would never be changed from it's zeroed out value. This just sets it beyond the end of the bitmap block. If any bits are freed, it will be reset to a valid bit. When info->free_count = 0, then we already know it's full. Signed-off-by: Jeff Mahoney <jeffm@suse.com> Cc: <reiserfs-dev@namesys.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/reiserfs/bitmap.c')
-rw-r--r--fs/reiserfs/bitmap.c88
1 files changed, 88 insertions, 0 deletions
diff --git a/fs/reiserfs/bitmap.c b/fs/reiserfs/bitmap.c
index 44d9410e9d6a..abdd6d9c4558 100644
--- a/fs/reiserfs/bitmap.c
+++ b/fs/reiserfs/bitmap.c
@@ -9,6 +9,7 @@
#include <linux/buffer_head.h>
#include <linux/kernel.h>
#include <linux/pagemap.h>
+#include <linux/vmalloc.h>
#include <linux/reiserfs_fs_sb.h>
#include <linux/reiserfs_fs_i.h>
#include <linux/quotaops.h>
@@ -1285,3 +1286,90 @@ int reiserfs_can_fit_pages(struct super_block *sb /* superblock of filesystem
return space > 0 ? space : 0;
}
+
+void reiserfs_cache_bitmap_metadata(struct super_block *sb,
+ struct buffer_head *bh,
+ struct reiserfs_bitmap_info *info)
+{
+ unsigned long *cur = (unsigned long *)(bh->b_data + bh->b_size);
+
+ info->first_zero_hint = 1 << (sb->s_blocksize_bits + 3);
+
+ while (--cur >= (unsigned long *)bh->b_data) {
+ int base = ((char *)cur - bh->b_data) << 3;
+
+ /* 0 and ~0 are special, we can optimize for them */
+ if (*cur == 0) {
+ info->first_zero_hint = base;
+ info->free_count += BITS_PER_LONG;
+ } else if (*cur != ~0L) { /* A mix, investigate */
+ int b;
+ for (b = BITS_PER_LONG - 1; b >= 0; b--) {
+ if (!reiserfs_test_le_bit(b, cur)) {
+ info->first_zero_hint = base + b;
+ info->free_count++;
+ }
+ }
+ }
+ }
+ /* The first bit must ALWAYS be 1 */
+ BUG_ON(info->first_zero_hint == 0);
+}
+
+struct buffer_head *reiserfs_read_bitmap_block(struct super_block *sb,
+ unsigned int bitmap)
+{
+ b_blocknr_t block = (sb->s_blocksize << 3) * bitmap;
+ struct buffer_head *bh;
+
+ /* Way old format filesystems had the bitmaps packed up front.
+ * I doubt there are any of these left, but just in case... */
+ if (unlikely(test_bit(REISERFS_OLD_FORMAT,
+ &(REISERFS_SB(sb)->s_properties))))
+ block = REISERFS_SB(sb)->s_sbh->b_blocknr + 1 + bitmap;
+ else if (bitmap == 0)
+ block = (REISERFS_DISK_OFFSET_IN_BYTES >> sb->s_blocksize_bits) + 1;
+
+ bh = sb_getblk(sb, block);
+ if (!buffer_uptodate(bh))
+ ll_rw_block(READ, 1, &bh);
+
+ return bh;
+}
+
+int reiserfs_init_bitmap_cache(struct super_block *sb)
+{
+ struct reiserfs_bitmap_info *bitmap;
+ int i;
+
+ bitmap = vmalloc(sizeof (*bitmap) * SB_BMAP_NR(sb));
+ if (bitmap == NULL)
+ return -ENOMEM;
+
+ memset(bitmap, 0, sizeof (*bitmap) * SB_BMAP_NR(sb));
+
+ for (i = 0; i < SB_BMAP_NR(sb); i++)
+ bitmap[i].bh = reiserfs_read_bitmap_block(sb, i);
+
+ /* make sure we have them all */
+ for (i = 0; i < SB_BMAP_NR(sb); i++) {
+ wait_on_buffer(bitmap[i].bh);
+ if (!buffer_uptodate(bitmap[i].bh)) {
+ reiserfs_warning(sb, "sh-2029: %s: "
+ "bitmap block (#%lu) reading failed",
+ __FUNCTION__, bitmap[i].bh->b_blocknr);
+ for (i = 0; i < SB_BMAP_NR(sb); i++)
+ brelse(bitmap[i].bh);
+ vfree(bitmap);
+ return -EIO;
+ }
+ }
+
+ /* Cache the info on the bitmaps before we get rolling */
+ for (i = 0; i < SB_BMAP_NR(sb); i++)
+ reiserfs_cache_bitmap_metadata(sb, bitmap[i].bh, &bitmap[i]);
+
+ SB_AP_BITMAP(sb) = bitmap;
+
+ return 0;
+}