From af25a6402c3f0224881058f3f4957c34e19e3c74 Mon Sep 17 00:00:00 2001 From: Sebastian Thorarensen Date: Fri, 20 Mar 2015 02:11:11 +0100 Subject: btrfs-progs: btrfs-convert: Allow setting nodesize Allow btrfs-convert to use nodesizes other than 4096. It defaults to max(16384, pagesize), like mkfs. Signed-off-by: Sebastian Thorarensen Signed-off-by: David Sterba --- btrfs-convert.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 53 insertions(+), 7 deletions(-) (limited to 'btrfs-convert.c') diff --git a/btrfs-convert.c b/btrfs-convert.c index 205eaf50..0123654a 100644 --- a/btrfs-convert.c +++ b/btrfs-convert.c @@ -141,6 +141,25 @@ static int ext2_alloc_block(ext2_filsys fs, u64 goal, u64 *block_ret) return -ENOSPC; } +static int ext2_alloc_block_range(ext2_filsys fs, u64 goal, int num, + u64 *block_ret) +{ + blk_t block; + ext2fs_block_bitmap bitmap = fs->block_map; + blk_t start = ext2fs_get_block_bitmap_start(bitmap); + blk_t end = ext2fs_get_block_bitmap_end(bitmap); + + for (block = max_t(u64, goal, start); block + num < end; block++) { + if (ext2fs_fast_test_block_bitmap_range(bitmap, block, num)) { + ext2fs_fast_mark_block_bitmap_range(bitmap, block, + num); + *block_ret = block; + return 0; + } + } + return -ENOSPC; +} + static int ext2_free_block(ext2_filsys fs, u64 block) { BUG_ON(block != (blk_t)block); @@ -148,6 +167,13 @@ static int ext2_free_block(ext2_filsys fs, u64 block) return 0; } +static int ext2_free_block_range(ext2_filsys fs, u64 block, int num) +{ + BUG_ON(block != (blk_t)block); + ext2fs_fast_unmark_block_bitmap_range(fs->block_map, block, num); + return 0; +} + static int cache_free_extents(struct btrfs_root *root, ext2_filsys ext2_fs) { @@ -2233,9 +2259,9 @@ err: } static int do_convert(const char *devname, int datacsum, int packing, int noxattr, - int copylabel, const char *fslabel, int progress) + u32 nodesize, int copylabel, const char *fslabel, int progress) { - int i, ret; + int i, ret, blocks_per_node; int fd = -1; u32 blocksize; u64 blocks[7]; @@ -2262,8 +2288,17 @@ static int do_convert(const char *devname, int datacsum, int packing, int noxatt fprintf(stderr, "filetype feature is missing\n"); goto fail; } + if (btrfs_check_node_or_leaf_size(nodesize, blocksize)) + goto fail; + blocks_per_node = nodesize / blocksize; + ret = -blocks_per_node; for (i = 0; i < 7; i++) { - ret = ext2_alloc_block(ext2_fs, 0, blocks + i); + if (nodesize == blocksize) + ret = ext2_alloc_block(ext2_fs, 0, blocks + i); + else + ret = ext2_alloc_block_range(ext2_fs, + ret + blocks_per_node, blocks_per_node, + blocks + i); if (ret) { fprintf(stderr, "not enough free space\n"); goto fail; @@ -2277,7 +2312,7 @@ static int do_convert(const char *devname, int datacsum, int packing, int noxatt goto fail; } ret = make_btrfs(fd, devname, ext2_fs->super->s_volume_name, - NULL, blocks, total_bytes, blocksize, blocksize, + NULL, blocks, total_bytes, nodesize, nodesize, blocksize, blocksize, 0); if (ret) { fprintf(stderr, "unable to create initial ctree: %s\n", @@ -2304,7 +2339,11 @@ static int do_convert(const char *devname, int datacsum, int packing, int noxatt /* recover block allocation bitmap */ for (i = 0; i < 7; i++) { blocks[i] /= blocksize; - ext2_free_block(ext2_fs, blocks[i]); + if (nodesize == blocksize) + ext2_free_block(ext2_fs, blocks[i]); + else + ext2_free_block_range(ext2_fs, blocks[i], + blocks_per_node); } ret = init_btrfs(root); if (ret) { @@ -2764,6 +2803,7 @@ static void print_usage(void) printf("\t-d disable data checksum\n"); printf("\t-i ignore xattrs and ACLs\n"); printf("\t-n disable packing of small files\n"); + printf("\t-N SIZE set filesystem nodesize\n"); printf("\t-r roll back to ext2fs\n"); printf("\t-l LABEL set filesystem label\n"); printf("\t-L use label from converted fs\n"); @@ -2777,6 +2817,8 @@ int main(int argc, char *argv[]) int packing = 1; int noxattr = 0; int datacsum = 1; + u32 nodesize = max_t(u32, sysconf(_SC_PAGESIZE), + BTRFS_MKFS_DEFAULT_NODE_SIZE); int rollback = 0; int copylabel = 0; int usage_error = 0; @@ -2791,7 +2833,7 @@ int main(int argc, char *argv[]) { "no-progress", no_argument, NULL, GETOPT_VAL_IEC}, { NULL, 0, NULL, 0 } }; - int c = getopt_long(argc, argv, "dinrl:Lp", long_options, + int c = getopt_long(argc, argv, "dinN:rl:Lp", long_options, &long_index); if (c < 0) @@ -2806,6 +2848,9 @@ int main(int argc, char *argv[]) case 'n': packing = 0; break; + case 'N': + nodesize = parse_size(optarg); + break; case 'r': rollback = 1; break; @@ -2865,7 +2910,8 @@ int main(int argc, char *argv[]) if (rollback) { ret = do_rollback(file); } else { - ret = do_convert(file, datacsum, packing, noxattr, copylabel, fslabel, progress); + ret = do_convert(file, datacsum, packing, noxattr, nodesize, + copylabel, fslabel, progress); } if (ret) return 1; -- cgit v1.2.3