From 94968e749b224f01fbb9009ed0285e55f6441784 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Fri, 10 Jun 2011 17:55:09 -0400 Subject: [PATCH] libext2fs: teach bitmap functions about bigalloc/cluster This patch makes the following changes: * ext2fs_allocate_block_bitmap() now allocates a bitmap with cluster granularity for bigalloc file systems. For mke2fs and e2fsck, a newly added function, ext2fs_allocate_subcluster_bitmap() allocates a bitmap with block granularity (even for bigalloc file systems). The newly added function ext2fs_get_bitmap_granularity() will return the number of bits (log2) of the granularity used by the bitmap. * The ext2fs_{mark,unmark,test}_block_bitmap2() functions will shift their passed-in argument by log2(cluster_ganularity) bits right. This means that the arguments for the single-argument bitmap functions will be interpreted with block granluarity, since this minimizes code changes in the rest of the code base. * The ext2fs_{get,set}_block_bitmap_range() functions will interpret their arguments in cluster granularity. This is a bit inconsistent, but the caller of those functions will need to be taught about the subtleties of clusters for bigalloc file systems. Signed-off-by: "Theodore Ts'o" --- lib/ext2fs/bitmaps.c | 55 +++++++++++++++++++++++++++++++++++++++++++++-- lib/ext2fs/bmap64.h | 1 + lib/ext2fs/ext2fs.h | 6 ++++++ lib/ext2fs/gen_bitmap64.c | 51 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 111 insertions(+), 2 deletions(-) diff --git a/lib/ext2fs/bitmaps.c b/lib/ext2fs/bitmaps.c index 4f61d27..b38590f 100644 --- a/lib/ext2fs/bitmaps.c +++ b/lib/ext2fs/bitmaps.c @@ -27,6 +27,7 @@ #include "ext2_fs.h" #include "ext2fs.h" #include "ext2fsP.h" +#include "bmap64.h" void ext2fs_free_inode_bitmap(ext2fs_inode_bitmap bitmap) { @@ -90,8 +91,8 @@ errcode_t ext2fs_allocate_block_bitmap(ext2_filsys fs, fs->write_bitmaps = ext2fs_write_bitmaps; - start = fs->super->s_first_data_block; - end = ext2fs_blocks_count(fs->super)-1; + start = EXT2FS_B2C(fs, fs->super->s_first_data_block); + end = EXT2FS_B2C(fs, ext2fs_blocks_count(fs->super)-1); real_end = ((__u64) EXT2_CLUSTERS_PER_GROUP(fs->super) * (__u64) fs->group_desc_count)-1 + start; @@ -110,6 +111,56 @@ errcode_t ext2fs_allocate_block_bitmap(ext2_filsys fs, (ext2fs_generic_bitmap *) ret)); } +/* + * ext2fs_allocate_block_bitmap() really allocates a per-cluster + * bitmap for backwards compatibility. This function allocates a + * block bitmap which is truly per-block, even if clusters/bigalloc + * are enabled. mke2fs and e2fsck need this for tracking the + * allocation of the file system metadata blocks. + */ +errcode_t ext2fs_allocate_subcluster_bitmap(ext2_filsys fs, + const char *descr, + ext2fs_block_bitmap *ret) +{ + __u64 start, end, real_end; + ext2fs_generic_bitmap bmap; + errcode_t retval; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + fs->write_bitmaps = ext2fs_write_bitmaps; + + if (!fs->cluster_ratio_bits) + return ext2fs_allocate_block_bitmap(fs, descr, ret); + + if ((fs->flags & EXT2_FLAG_64BITS) == 0) + return EXT2_ET_CANT_USE_LEGACY_BITMAPS; + + start = fs->super->s_first_data_block; + end = ext2fs_blocks_count(fs->super)-1; + real_end = ((__u64) EXT2_BLOCKS_PER_GROUP(fs->super) + * (__u64) fs->group_desc_count)-1 + start; + + retval = ext2fs_alloc_generic_bmap(fs, EXT2_ET_MAGIC_BLOCK_BITMAP64, + EXT2FS_BMAP64_BITARRAY, start, + end, real_end, descr, &bmap); + if (retval) + return retval; + bmap->cluster_bits = 0; + *ret = bmap; + return 0; +} + +int ext2fs_get_bitmap_granularity(ext2fs_block_bitmap bitmap) +{ + ext2fs_generic_bitmap bmap = bitmap; + + if (!EXT2FS_IS_64_BITMAP(bmap)) + return 0; + + return bmap->cluster_bits; +} + errcode_t ext2fs_fudge_inode_bitmap_end(ext2fs_inode_bitmap bitmap, ext2_ino_t end, ext2_ino_t *oend) { diff --git a/lib/ext2fs/bmap64.h b/lib/ext2fs/bmap64.h index b0aa84c..3056544 100644 --- a/lib/ext2fs/bmap64.h +++ b/lib/ext2fs/bmap64.h @@ -16,6 +16,7 @@ struct ext2fs_struct_generic_bitmap { int flags; __u64 start, end; __u64 real_end; + int cluster_bits; char *description; void *private; errcode_t base_error_code; diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h index f7d99bb..47be91c 100644 --- a/lib/ext2fs/ext2fs.h +++ b/lib/ext2fs/ext2fs.h @@ -686,6 +686,10 @@ extern errcode_t ext2fs_read_block_bitmap(ext2_filsys fs); extern errcode_t ext2fs_allocate_block_bitmap(ext2_filsys fs, const char *descr, ext2fs_block_bitmap *ret); +extern errcode_t ext2fs_allocate_subcluster_bitmap(ext2_filsys fs, + const char *descr, + ext2fs_block_bitmap *ret); +extern int ext2fs_get_bitmap_granularity(ext2fs_block_bitmap bitmap); extern errcode_t ext2fs_allocate_inode_bitmap(ext2_filsys fs, const char *descr, ext2fs_inode_bitmap *ret); @@ -1118,6 +1122,8 @@ errcode_t ext2fs_get_generic_bmap_range(ext2fs_generic_bitmap bmap, errcode_t ext2fs_set_generic_bmap_range(ext2fs_generic_bitmap bmap, __u64 start, unsigned int num, void *in); +errcode_t ext2fs_convert_subcluster_bitmap(ext2_filsys fs, + ext2fs_block_bitmap *bitmap); /* getsize.c */ extern errcode_t ext2fs_get_device_size(const char *file, int blocksize, diff --git a/lib/ext2fs/gen_bitmap64.c b/lib/ext2fs/gen_bitmap64.c index 94809cd..91dd133 100644 --- a/lib/ext2fs/gen_bitmap64.c +++ b/lib/ext2fs/gen_bitmap64.c @@ -107,12 +107,14 @@ errcode_t ext2fs_alloc_generic_bmap(ext2_filsys fs, errcode_t magic, bitmap->end = end; bitmap->real_end = real_end; bitmap->bitmap_ops = ops; + bitmap->cluster_bits = 0; switch (magic) { case EXT2_ET_MAGIC_INODE_BITMAP64: bitmap->base_error_code = EXT2_ET_BAD_INODE_MARK; break; case EXT2_ET_MAGIC_BLOCK_BITMAP64: bitmap->base_error_code = EXT2_ET_BAD_BLOCK_MARK; + bitmap->cluster_bits = fs->cluster_ratio_bits; break; default: bitmap->base_error_code = EXT2_ET_BAD_GENERIC_MARK; @@ -315,6 +317,8 @@ int ext2fs_mark_generic_bmap(ext2fs_generic_bitmap bitmap, if (!EXT2FS_IS_64_BITMAP(bitmap)) return 0; + arg >>= bitmap->cluster_bits; + if ((arg < bitmap->start) || (arg > bitmap->end)) { warn_bitmap(bitmap, EXT2FS_MARK_ERROR, arg); return 0; @@ -341,6 +345,8 @@ int ext2fs_unmark_generic_bmap(ext2fs_generic_bitmap bitmap, if (!EXT2FS_IS_64_BITMAP(bitmap)) return 0; + arg >>= bitmap->cluster_bits; + if ((arg < bitmap->start) || (arg > bitmap->end)) { warn_bitmap(bitmap, EXT2FS_UNMARK_ERROR, arg); return 0; @@ -367,6 +373,8 @@ int ext2fs_test_generic_bmap(ext2fs_generic_bitmap bitmap, if (!EXT2FS_IS_64_BITMAP(bitmap)) return 0; + arg >>= bitmap->cluster_bits; + if ((arg < bitmap->start) || (arg > bitmap->end)) { warn_bitmap(bitmap, EXT2FS_TEST_ERROR, arg); return 0; @@ -560,3 +568,46 @@ int ext2fs_warn_bitmap32(ext2fs_generic_bitmap bitmap, const char *func) "called %s with 64-bit bitmap", func); #endif } + +errcode_t ext2fs_convert_subcluster_bitmap(ext2_filsys fs, + ext2fs_block_bitmap *bitmap) +{ + ext2fs_block_bitmap cmap, bmap; + errcode_t retval; + blk64_t i, b_end, c_end; + int n, ratio; + + bmap = *bitmap; + + if (fs->cluster_ratio_bits == ext2fs_get_bitmap_granularity(bmap)) + return 0; /* Nothing to do */ + + retval = ext2fs_allocate_block_bitmap(fs, "converted cluster bitmap", + &cmap); + if (retval) + return retval; + + i = bmap->start; + b_end = bmap->end; + bmap->end = bmap->real_end; + c_end = cmap->end; + cmap->end = cmap->real_end; + n = 0; + ratio = 1 << fs->cluster_ratio_bits; + while (i < bmap->real_end) { + if (ext2fs_test_block_bitmap2(bmap, i)) { + ext2fs_mark_block_bitmap2(cmap, i); + i += ratio - n; + n = 0; + continue; + } + i++; n++; + if (n >= ratio) + n = 0; + } + bmap->end = b_end; + cmap->end = c_end; + ext2fs_free_block_bitmap(bmap); + *bitmap = cmap; + return 0; +} -- 1.8.3.1