315 lines
11 KiB
Diff
315 lines
11 KiB
Diff
From git-commits-head-owner@vger.kernel.org Wed Oct 4 17:36:48 2006
|
|
Date: Sun, 1 Oct 2006 08:01:30 GMT
|
|
Message-Id: <200610010801.k9181U4g010098@hera.kernel.org>
|
|
From: Linux Kernel Mailing List <linux-kernel@vger.kernel.org>
|
|
To: git-commits-head@vger.kernel.org
|
|
Subject: [PATCH] reiserfs: reorganize bitmap loading functions
|
|
|
|
commit 6f01046b35d940079822827498a7dd6d3eec8c6b
|
|
tree e65426389691c9d3e7d4f29da73725d15ee8e2f6
|
|
parent 0b3dc17bc0c0997bde9f5d7691ec0cae24258cf7
|
|
author Jeff Mahoney <jeffm@suse.com> 1159684123 -0700
|
|
committer Linus Torvalds <torvalds@g5.osdl.org> 1159688367 -0700
|
|
|
|
[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>
|
|
|
|
fs/reiserfs/bitmap.c | 88 +++++++++++++++++++++++++++++++++
|
|
fs/reiserfs/resize.c | 1
|
|
fs/reiserfs/super.c | 114 --------------------------------------------
|
|
include/linux/reiserfs_fs.h | 4 +
|
|
4 files changed, 94 insertions(+), 113 deletions(-)
|
|
|
|
diff --git a/fs/reiserfs/bitmap.c b/fs/reiserfs/bitmap.c
|
|
index 44d9410..abdd6d9 100644
|
|
--- a/fs/reiserfs/bitmap.c
|
|
+++ b/fs/reiserfs/bitmap.c
|
|
@@ -9,6 +9,7 @@ #include <linux/errno.h>
|
|
#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_
|
|
|
|
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;
|
|
+}
|
|
diff --git a/fs/reiserfs/resize.c b/fs/reiserfs/resize.c
|
|
index 958b759..90d39fd 100644
|
|
--- a/fs/reiserfs/resize.c
|
|
+++ b/fs/reiserfs/resize.c
|
|
@@ -132,6 +132,7 @@ int reiserfs_resize(struct super_block *
|
|
get_bh(bh);
|
|
memset(bh->b_data, 0, sb_blocksize(sb));
|
|
reiserfs_test_and_set_le_bit(0, bh->b_data);
|
|
+ reiserfs_cache_bitmap_metadata(s, bh, bitmap + i);
|
|
|
|
set_buffer_uptodate(bh);
|
|
mark_buffer_dirty(bh);
|
|
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
|
|
index db2c581..c78e99e 100644
|
|
--- a/fs/reiserfs/super.c
|
|
+++ b/fs/reiserfs/super.c
|
|
@@ -1243,118 +1243,6 @@ #endif
|
|
return 0;
|
|
}
|
|
|
|
-/* load_bitmap_info_data - Sets up the reiserfs_bitmap_info structure from disk.
|
|
- * @sb - superblock for this filesystem
|
|
- * @bi - the bitmap info to be loaded. Requires that bi->bh is valid.
|
|
- *
|
|
- * This routine counts how many free bits there are, finding the first zero
|
|
- * as a side effect. Could also be implemented as a loop of test_bit() calls, or
|
|
- * a loop of find_first_zero_bit() calls. This implementation is similar to
|
|
- * find_first_zero_bit(), but doesn't return after it finds the first bit.
|
|
- * Should only be called on fs mount, but should be fairly efficient anyways.
|
|
- *
|
|
- * bi->first_zero_hint is considered unset if it == 0, since the bitmap itself
|
|
- * will * invariably occupt block 0 represented in the bitmap. The only
|
|
- * exception to this is when free_count also == 0, since there will be no
|
|
- * free blocks at all.
|
|
- */
|
|
-
|
|
-static void load_bitmap_info_data(struct super_block *sb,
|
|
- struct reiserfs_bitmap_info *bi)
|
|
-{
|
|
- unsigned long *cur = (unsigned long *)bi->bh->b_data;
|
|
-
|
|
- while ((char *)cur < (bi->bh->b_data + sb->s_blocksize)) {
|
|
-
|
|
- /* No need to scan if all 0's or all 1's.
|
|
- * Since we're only counting 0's, we can simply ignore all 1's */
|
|
- if (*cur == 0) {
|
|
- if (bi->first_zero_hint == 0) {
|
|
- bi->first_zero_hint =
|
|
- ((char *)cur - bi->bh->b_data) << 3;
|
|
- }
|
|
- bi->free_count += sizeof(unsigned long) * 8;
|
|
- } else if (*cur != ~0L) {
|
|
- int b;
|
|
- for (b = 0; b < sizeof(unsigned long) * 8; b++) {
|
|
- if (!reiserfs_test_le_bit(b, cur)) {
|
|
- bi->free_count++;
|
|
- if (bi->first_zero_hint == 0)
|
|
- bi->first_zero_hint =
|
|
- (((char *)cur -
|
|
- bi->bh->b_data) << 3) + b;
|
|
- }
|
|
- }
|
|
- }
|
|
- cur++;
|
|
- }
|
|
-
|
|
-#ifdef CONFIG_REISERFS_CHECK
|
|
-// This outputs a lot of unneded info on big FSes
|
|
-// reiserfs_warning ("bitmap loaded from block %d: %d free blocks",
|
|
-// bi->bh->b_blocknr, bi->free_count);
|
|
-#endif
|
|
-}
|
|
-
|
|
-static int read_bitmaps(struct super_block *s)
|
|
-{
|
|
- int i, bmap_nr;
|
|
-
|
|
- SB_AP_BITMAP(s) =
|
|
- vmalloc(sizeof(struct reiserfs_bitmap_info) * SB_BMAP_NR(s));
|
|
- if (SB_AP_BITMAP(s) == 0)
|
|
- return 1;
|
|
- memset(SB_AP_BITMAP(s), 0,
|
|
- sizeof(struct reiserfs_bitmap_info) * SB_BMAP_NR(s));
|
|
- for (i = 0, bmap_nr =
|
|
- REISERFS_DISK_OFFSET_IN_BYTES / s->s_blocksize + 1;
|
|
- i < SB_BMAP_NR(s); i++, bmap_nr = s->s_blocksize * 8 * i) {
|
|
- SB_AP_BITMAP(s)[i].bh = sb_getblk(s, bmap_nr);
|
|
- if (!buffer_uptodate(SB_AP_BITMAP(s)[i].bh))
|
|
- ll_rw_block(READ, 1, &SB_AP_BITMAP(s)[i].bh);
|
|
- }
|
|
- for (i = 0; i < SB_BMAP_NR(s); i++) {
|
|
- wait_on_buffer(SB_AP_BITMAP(s)[i].bh);
|
|
- if (!buffer_uptodate(SB_AP_BITMAP(s)[i].bh)) {
|
|
- reiserfs_warning(s, "sh-2029: reiserfs read_bitmaps: "
|
|
- "bitmap block (#%lu) reading failed",
|
|
- SB_AP_BITMAP(s)[i].bh->b_blocknr);
|
|
- for (i = 0; i < SB_BMAP_NR(s); i++)
|
|
- brelse(SB_AP_BITMAP(s)[i].bh);
|
|
- vfree(SB_AP_BITMAP(s));
|
|
- SB_AP_BITMAP(s) = NULL;
|
|
- return 1;
|
|
- }
|
|
- load_bitmap_info_data(s, SB_AP_BITMAP(s) + i);
|
|
- }
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static int read_old_bitmaps(struct super_block *s)
|
|
-{
|
|
- int i;
|
|
- struct reiserfs_super_block *rs = SB_DISK_SUPER_BLOCK(s);
|
|
- int bmp1 = (REISERFS_OLD_DISK_OFFSET_IN_BYTES / s->s_blocksize) + 1; /* first of bitmap blocks */
|
|
-
|
|
- /* read true bitmap */
|
|
- SB_AP_BITMAP(s) =
|
|
- vmalloc(sizeof(struct reiserfs_buffer_info *) * sb_bmap_nr(rs));
|
|
- if (SB_AP_BITMAP(s) == 0)
|
|
- return 1;
|
|
-
|
|
- memset(SB_AP_BITMAP(s), 0,
|
|
- sizeof(struct reiserfs_buffer_info *) * sb_bmap_nr(rs));
|
|
-
|
|
- for (i = 0; i < sb_bmap_nr(rs); i++) {
|
|
- SB_AP_BITMAP(s)[i].bh = sb_bread(s, bmp1 + i);
|
|
- if (!SB_AP_BITMAP(s)[i].bh)
|
|
- return 1;
|
|
- load_bitmap_info_data(s, SB_AP_BITMAP(s) + i);
|
|
- }
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
static int read_super_block(struct super_block *s, int offset)
|
|
{
|
|
struct buffer_head *bh;
|
|
@@ -1736,7 +1624,7 @@ static int reiserfs_fill_super(struct su
|
|
sbi->s_mount_state = SB_REISERFS_STATE(s);
|
|
sbi->s_mount_state = REISERFS_VALID_FS;
|
|
|
|
- if (old_format ? read_old_bitmaps(s) : read_bitmaps(s)) {
|
|
+ if ((errval = reiserfs_init_bitmap_cache(s))) {
|
|
SWARN(silent, s,
|
|
"jmacd-8: reiserfs_fill_super: unable to read bitmap");
|
|
goto error;
|
|
diff --git a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h
|
|
index 9c63abf..7bc6bfb 100644
|
|
--- a/include/linux/reiserfs_fs.h
|
|
+++ b/include/linux/reiserfs_fs.h
|
|
@@ -2073,6 +2073,10 @@ void reiserfs_init_alloc_options(struct
|
|
*/
|
|
__le32 reiserfs_choose_packing(struct inode *dir);
|
|
|
|
+int reiserfs_init_bitmap_cache(struct super_block *sb);
|
|
+void reiserfs_free_bitmap_cache(struct super_block *sb);
|
|
+void reiserfs_cache_bitmap_metadata(struct super_block *sb, struct buffer_head *bh, struct reiserfs_bitmap_info *info);
|
|
+struct buffer_head *reiserfs_read_bitmap_block(struct super_block *sb, unsigned int bitmap);
|
|
int is_reusable(struct super_block *s, b_blocknr_t block, int bit_value);
|
|
void reiserfs_free_block(struct reiserfs_transaction_handle *th, struct inode *,
|
|
b_blocknr_t, int for_unformatted);
|