Message ID | 1291919468-17802-1-git-send-email-josef@redhat.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On 12/10/2010 02:31 AM, Josef Bacik wrote: > So alot of crazy people (I'm looking at you Meego) want to use btrfs on phones > and such with small devices. Unfortunately the way we split out metadata/data > chunks it makes space usage inefficient for volumes that are smaller than > 1gigabyte. So add a -M option for mixing metadata+data, and default to this > mixed mode if the filesystem is less than or equal to 1 gigabyte. I've tested > this with xfstests on a 100mb filesystem and everything is a-ok. > Hi, Josef, While using this mix metadata+data option, I noticed the following from btrfs-debug-tree's print: === chunk tree leaf 143360 items 4 free space 3557 generation 4 owner 3 fs uuid 77d78a87-a886-4bfa-be3b-0dd052213a17 chunk uuid e64148d6-8267-4ff1-aafd-4266f74afbb2 item 0 key (DEV_ITEMS DEV_ITEM 1) itemoff 3897 itemsize 98 dev item devid 1 total_bytes 4999610368 bytes used 20971520 item 1 key (FIRST_CHUNK_TREE CHUNK_ITEM 0) itemoff 3817 itemsize 80 chunk length 4194304 owner 2 type 2 num_stripes 1 stripe 0 devid 1 offset 0 item 2 key (FIRST_CHUNK_TREE CHUNK_ITEM 4194304) itemoff 3737 itemsize 80 chunk length 8388608 owner 2 type 5 num_stripes 1 stripe 0 devid 1 offset 4194304 item 3 key (FIRST_CHUNK_TREE CHUNK_ITEM 12582912) itemoff 3657 itemsize 80 <== THIS ONE chunk length 8388608 owner 2 type 4 num_stripes 1 <== stripe 0 devid 1 offset 12582912 <== === you see, there exists another metadata chunk (type 4) after "mkfs.btrfs -M /dev/xxx". So I was wondering that _IS_ this chunk what we want, or a spare one? thanks, liubo > Signed-off-by: Josef Bacik <josef@redhat.com> > --- > btrfs-vol.c | 4 +- > btrfs_cmds.c | 13 +++++- > ctree.h | 10 +++-- > mkfs.c | 122 +++++++++++++++++++++++++++++++++++++++++----------------- > utils.c | 10 ++-- > utils.h | 2 +- > 6 files changed, 112 insertions(+), 49 deletions(-) > > diff --git a/btrfs-vol.c b/btrfs-vol.c > index 8069778..7200bbc 100644 > --- a/btrfs-vol.c > +++ b/btrfs-vol.c > @@ -129,7 +129,9 @@ int main(int ac, char **av) > exit(1); > } > if (cmd == BTRFS_IOC_ADD_DEV) { > - ret = btrfs_prepare_device(devfd, device, 1, &dev_block_count); > + int mixed = 0; > + > + ret = btrfs_prepare_device(devfd, device, 1, &dev_block_count, &mixed); > if (ret) { > fprintf(stderr, "Unable to init %s\n", device); > exit(1); > diff --git a/btrfs_cmds.c b/btrfs_cmds.c > index 8031c58..683aec0 100644 > --- a/btrfs_cmds.c > +++ b/btrfs_cmds.c > @@ -705,6 +705,7 @@ int do_add_volume(int nargs, char **args) > int devfd, res; > u64 dev_block_count = 0; > struct stat st; > + int mixed = 0; > > devfd = open(args[i], O_RDWR); > if (!devfd) { > @@ -727,7 +728,7 @@ int do_add_volume(int nargs, char **args) > continue; > } > > - res = btrfs_prepare_device(devfd, args[i], 1, &dev_block_count); > + res = btrfs_prepare_device(devfd, args[i], 1, &dev_block_count, &mixed); > if (res) { > fprintf(stderr, "ERROR: Unable to init '%s'\n", args[i]); > close(devfd); > @@ -889,8 +890,14 @@ int do_df_filesystem(int nargs, char **argv) > memset(description, 0, 80); > > if (flags & BTRFS_BLOCK_GROUP_DATA) { > - snprintf(description, 5, "%s", "Data"); > - written += 4; > + if (flags & BTRFS_BLOCK_GROUP_METADATA) { > + snprintf(description, 15, "%s", > + "Data+Metadata"); > + written += 14; > + } else { > + snprintf(description, 5, "%s", "Data"); > + written += 4; > + } > } else if (flags & BTRFS_BLOCK_GROUP_SYSTEM) { > snprintf(description, 7, "%s", "System"); > written += 6; > diff --git a/ctree.h b/ctree.h > index 962c510..ed83d02 100644 > --- a/ctree.h > +++ b/ctree.h > @@ -352,13 +352,15 @@ struct btrfs_super_block { > * ones specified below then we will fail to mount > */ > #define BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF (1ULL << 0) > -#define BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL (2ULL << 0) > +#define BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL (1ULL << 1) > +#define BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS (1ULL << 2) > > #define BTRFS_FEATURE_COMPAT_SUPP 0ULL > #define BTRFS_FEATURE_COMPAT_RO_SUPP 0ULL > -#define BTRFS_FEATURE_INCOMPAT_SUPP \ > - (BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF | \ > - BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL) > +#define BTRFS_FEATURE_INCOMPAT_SUPP \ > + (BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF | \ > + BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL | \ > + BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS) > > /* > * A leaf is full of items. offset and size tell us where to find > diff --git a/mkfs.c b/mkfs.c > index 2e99b95..04de93a 100644 > --- a/mkfs.c > +++ b/mkfs.c > @@ -69,7 +69,7 @@ static u64 parse_size(char *s) > return atol(s) * mult; > } > > -static int make_root_dir(struct btrfs_root *root) > +static int make_root_dir(struct btrfs_root *root, int mixed) > { > struct btrfs_trans_handle *trans; > struct btrfs_key location; > @@ -88,30 +88,47 @@ static int make_root_dir(struct btrfs_root *root) > 0, BTRFS_MKFS_SYSTEM_GROUP_SIZE); > BUG_ON(ret); > > - ret = btrfs_alloc_chunk(trans, root->fs_info->extent_root, > - &chunk_start, &chunk_size, > - BTRFS_BLOCK_GROUP_METADATA); > - BUG_ON(ret); > - ret = btrfs_make_block_group(trans, root, 0, > - BTRFS_BLOCK_GROUP_METADATA, > - BTRFS_FIRST_CHUNK_TREE_OBJECTID, > - chunk_start, chunk_size); > - BUG_ON(ret); > + if (mixed) { > + ret = btrfs_alloc_chunk(trans, root->fs_info->extent_root, > + &chunk_start, &chunk_size, > + BTRFS_BLOCK_GROUP_METADATA | > + BTRFS_BLOCK_GROUP_DATA); > + BUG_ON(ret); > + ret = btrfs_make_block_group(trans, root, 0, > + BTRFS_BLOCK_GROUP_METADATA | > + BTRFS_BLOCK_GROUP_DATA, > + BTRFS_FIRST_CHUNK_TREE_OBJECTID, > + chunk_start, chunk_size); > + BUG_ON(ret); > + printf("Created a data/metadata chunk of size %llu\n", chunk_size); > + } else { > + ret = btrfs_alloc_chunk(trans, root->fs_info->extent_root, > + &chunk_start, &chunk_size, > + BTRFS_BLOCK_GROUP_METADATA); > + BUG_ON(ret); > + ret = btrfs_make_block_group(trans, root, 0, > + BTRFS_BLOCK_GROUP_METADATA, > + BTRFS_FIRST_CHUNK_TREE_OBJECTID, > + chunk_start, chunk_size); > + BUG_ON(ret); > + } > > root->fs_info->system_allocs = 0; > btrfs_commit_transaction(trans, root); > trans = btrfs_start_transaction(root, 1); > BUG_ON(!trans); > > - ret = btrfs_alloc_chunk(trans, root->fs_info->extent_root, > - &chunk_start, &chunk_size, > - BTRFS_BLOCK_GROUP_DATA); > - BUG_ON(ret); > - ret = btrfs_make_block_group(trans, root, 0, > - BTRFS_BLOCK_GROUP_DATA, > - BTRFS_FIRST_CHUNK_TREE_OBJECTID, > - chunk_start, chunk_size); > - BUG_ON(ret); > + if (!mixed) { > + ret = btrfs_alloc_chunk(trans, root->fs_info->extent_root, > + &chunk_start, &chunk_size, > + BTRFS_BLOCK_GROUP_DATA); > + BUG_ON(ret); > + ret = btrfs_make_block_group(trans, root, 0, > + BTRFS_BLOCK_GROUP_DATA, > + BTRFS_FIRST_CHUNK_TREE_OBJECTID, > + chunk_start, chunk_size); > + BUG_ON(ret); > + } > > ret = btrfs_make_root_dir(trans, root->fs_info->tree_root, > BTRFS_ROOT_TREE_DIR_OBJECTID); > @@ -200,7 +217,7 @@ static int create_one_raid_group(struct btrfs_trans_handle *trans, > > static int create_raid_groups(struct btrfs_trans_handle *trans, > struct btrfs_root *root, u64 data_profile, > - u64 metadata_profile) > + u64 metadata_profile, int mixed) > { > u64 num_devices = btrfs_super_num_devices(&root->fs_info->super_copy); > u64 allowed; > @@ -215,20 +232,24 @@ static int create_raid_groups(struct btrfs_trans_handle *trans, > allowed = BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1; > > if (allowed & metadata_profile) { > + u64 meta_flags = BTRFS_BLOCK_GROUP_METADATA; > + > ret = create_one_raid_group(trans, root, > BTRFS_BLOCK_GROUP_SYSTEM | > (allowed & metadata_profile)); > BUG_ON(ret); > > - ret = create_one_raid_group(trans, root, > - BTRFS_BLOCK_GROUP_METADATA | > + if (mixed) > + meta_flags |= BTRFS_BLOCK_GROUP_DATA; > + > + ret = create_one_raid_group(trans, root, meta_flags | > (allowed & metadata_profile)); > BUG_ON(ret); > > ret = recow_roots(trans, root); > BUG_ON(ret); > } > - if (num_devices > 1 && (allowed & data_profile)) { > + if (!mixed && num_devices > 1 && (allowed & data_profile)) { > ret = create_one_raid_group(trans, root, > BTRFS_BLOCK_GROUP_DATA | > (allowed & data_profile)); > @@ -274,6 +295,7 @@ static void print_usage(void) > fprintf(stderr, "\t -l --leafsize size of btree leaves\n"); > fprintf(stderr, "\t -L --label set a label\n"); > fprintf(stderr, "\t -m --metadata metadata profile, values like data profile\n"); > + fprintf(stderr, "\t -M --mixed mix metadata and data together\n"); > fprintf(stderr, "\t -n --nodesize size of btree nodes\n"); > fprintf(stderr, "\t -s --sectorsize min block allocation\n"); > fprintf(stderr, "%s\n", BTRFS_BUILD_VERSION); > @@ -328,6 +350,7 @@ static struct option long_options[] = { > { "leafsize", 1, NULL, 'l' }, > { "label", 1, NULL, 'L'}, > { "metadata", 1, NULL, 'm' }, > + { "mixed", 0, NULL, 'M' }, > { "nodesize", 1, NULL, 'n' }, > { "sectorsize", 1, NULL, 's' }, > { "data", 1, NULL, 'd' }, > @@ -358,10 +381,13 @@ int main(int ac, char **av) > int first_fd; > int ret; > int i; > + int mixed = 0; > + int data_profile_opt = 0; > + int metadata_profile_opt = 0; > > while(1) { > int c; > - c = getopt_long(ac, av, "A:b:l:n:s:m:d:L:V", long_options, > + c = getopt_long(ac, av, "A:b:l:n:s:m:d:L:VM", long_options, > &option_index); > if (c < 0) > break; > @@ -371,6 +397,7 @@ int main(int ac, char **av) > break; > case 'd': > data_profile = parse_profile(optarg); > + data_profile_opt = 1; > break; > case 'l': > leafsize = parse_size(optarg); > @@ -380,6 +407,10 @@ int main(int ac, char **av) > break; > case 'm': > metadata_profile = parse_profile(optarg); > + metadata_profile_opt = 1; > + break; > + case 'M': > + mixed = 1; > break; > case 'n': > nodesize = parse_size(optarg); > @@ -389,12 +420,10 @@ int main(int ac, char **av) > break; > case 'b': > block_count = parse_size(optarg); > - if (block_count < 256*1024*1024) { > - fprintf(stderr, "File system size " > - "%llu bytes is too small, " > - "256M is required at least\n", > - (unsigned long long)block_count); > - exit(1); > + if (block_count <= 1024*1024*1024) { > + printf("SMALL VOLUME: forcing mixed " > + "metadata/data groups\n"); > + mixed = 1; > } > zero_end = 0; > break; > @@ -439,9 +468,22 @@ int main(int ac, char **av) > } > first_fd = fd; > first_file = file; > - ret = btrfs_prepare_device(fd, file, zero_end, &dev_block_count); > + ret = btrfs_prepare_device(fd, file, zero_end, &dev_block_count, > + &mixed); > if (block_count == 0) > block_count = dev_block_count; > + if (mixed) { > + if (!metadata_profile_opt) > + metadata_profile = 0; > + if (!data_profile_opt) > + data_profile = 0; > + > + if (metadata_profile != data_profile) { > + fprintf(stderr, "With mixed block groups data and metadata " > + "profiles must be the same\n"); > + exit(1); > + } > + } > > blocks[0] = BTRFS_SUPER_INFO_OFFSET; > for (i = 1; i < 7; i++) { > @@ -459,7 +501,7 @@ int main(int ac, char **av) > root = open_ctree(file, 0, O_RDWR); > root->fs_info->alloc_start = alloc_start; > > - ret = make_root_dir(root); > + ret = make_root_dir(root, mixed); > if (ret) { > fprintf(stderr, "failed to setup the root directory\n"); > exit(1); > @@ -478,6 +520,8 @@ int main(int ac, char **av) > > zero_end = 1; > while(ac-- > 0) { > + int old_mixed = mixed; > + > file = av[optind++]; > ret = check_mounted(file); > if (ret < 0) { > @@ -503,8 +547,8 @@ int main(int ac, char **av) > continue; > } > ret = btrfs_prepare_device(fd, file, zero_end, > - &dev_block_count); > - > + &dev_block_count, &mixed); > + mixed = old_mixed; > BUG_ON(ret); > > ret = btrfs_add_to_fsid(trans, root, fd, file, dev_block_count, > @@ -515,12 +559,20 @@ int main(int ac, char **av) > > raid_groups: > ret = create_raid_groups(trans, root, data_profile, > - metadata_profile); > + metadata_profile, mixed); > BUG_ON(ret); > > ret = create_data_reloc_tree(trans, root); > BUG_ON(ret); > > + if (mixed) { > + struct btrfs_super_block *super = &root->fs_info->super_copy; > + u64 flags = btrfs_super_incompat_flags(super); > + > + flags |= BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS; > + btrfs_set_super_incompat_flags(super, flags); > + } > + > printf("fs created label %s on %s\n\tnodesize %u leafsize %u " > "sectorsize %u size %s\n", > label, first_file, nodesize, leafsize, sectorsize, > diff --git a/utils.c b/utils.c > index b890728..13d31b7 100644 > --- a/utils.c > +++ b/utils.c > @@ -508,7 +508,8 @@ int btrfs_add_to_fsid(struct btrfs_trans_handle *trans, > return 0; > } > > -int btrfs_prepare_device(int fd, char *file, int zero_end, u64 *block_count_ret) > +int btrfs_prepare_device(int fd, char *file, int zero_end, u64 *block_count_ret, > + int *mixed) > { > u64 block_count; > u64 bytenr; > @@ -528,10 +529,9 @@ int btrfs_prepare_device(int fd, char *file, int zero_end, u64 *block_count_ret) > } > zero_end = 1; > > - if (block_count < 256 * 1024 * 1024) { > - fprintf(stderr, "device %s is too small " > - "(must be at least 256 MB)\n", file); > - exit(1); > + if (block_count < 1024 * 1024 * 1024 && !(*mixed)) { > + printf("SMALL VOLUME: forcing mixed metadata/data groups\n"); > + *mixed = 1; > } > ret = zero_dev_start(fd); > if (ret) { > diff --git a/utils.h b/utils.h > index 7ff542b..b91140e 100644 > --- a/utils.h > +++ b/utils.h > @@ -27,7 +27,7 @@ int make_btrfs(int fd, const char *device, const char *label, > int btrfs_make_root_dir(struct btrfs_trans_handle *trans, > struct btrfs_root *root, u64 objectid); > int btrfs_prepare_device(int fd, char *file, int zero_end, > - u64 *block_count_ret); > + u64 *block_count_ret, int *mixed); > int btrfs_add_to_fsid(struct btrfs_trans_handle *trans, > struct btrfs_root *root, int fd, char *path, > u64 block_count, u32 io_width, u32 io_align, -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 04/08/2011 03:31 AM, liubo wrote: > On 12/10/2010 02:31 AM, Josef Bacik wrote: >> So alot of crazy people (I'm looking at you Meego) want to use btrfs on phones >> and such with small devices. Unfortunately the way we split out metadata/data >> chunks it makes space usage inefficient for volumes that are smaller than >> 1gigabyte. So add a -M option for mixing metadata+data, and default to this >> mixed mode if the filesystem is less than or equal to 1 gigabyte. I've tested >> this with xfstests on a 100mb filesystem and everything is a-ok. >> > > Hi, Josef, > > While using this mix metadata+data option, I noticed the following from btrfs-debug-tree's print: > > === > chunk tree > leaf 143360 items 4 free space 3557 generation 4 owner 3 > fs uuid 77d78a87-a886-4bfa-be3b-0dd052213a17 > chunk uuid e64148d6-8267-4ff1-aafd-4266f74afbb2 > item 0 key (DEV_ITEMS DEV_ITEM 1) itemoff 3897 itemsize 98 > dev item devid 1 total_bytes 4999610368 bytes used 20971520 > item 1 key (FIRST_CHUNK_TREE CHUNK_ITEM 0) itemoff 3817 itemsize 80 > chunk length 4194304 owner 2 type 2 num_stripes 1 > stripe 0 devid 1 offset 0 > item 2 key (FIRST_CHUNK_TREE CHUNK_ITEM 4194304) itemoff 3737 itemsize 80 > chunk length 8388608 owner 2 type 5 num_stripes 1 > stripe 0 devid 1 offset 4194304 > item 3 key (FIRST_CHUNK_TREE CHUNK_ITEM 12582912) itemoff 3657 itemsize 80<== THIS ONE > chunk length 8388608 owner 2 type 4 num_stripes 1 <== > stripe 0 devid 1 offset 12582912 <== > === > > you see, there exists another metadata chunk (type 4) after "mkfs.btrfs -M /dev/xxx". > So I was wondering that _IS_ this chunk what we want, or a spare one? > Hmm that shouldn't be there, thanks for catching that, we should only be creating a system block_group and a mixed block_group, not another metadata one. I will fix that up. Josef -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/btrfs-vol.c b/btrfs-vol.c index 8069778..7200bbc 100644 --- a/btrfs-vol.c +++ b/btrfs-vol.c @@ -129,7 +129,9 @@ int main(int ac, char **av) exit(1); } if (cmd == BTRFS_IOC_ADD_DEV) { - ret = btrfs_prepare_device(devfd, device, 1, &dev_block_count); + int mixed = 0; + + ret = btrfs_prepare_device(devfd, device, 1, &dev_block_count, &mixed); if (ret) { fprintf(stderr, "Unable to init %s\n", device); exit(1); diff --git a/btrfs_cmds.c b/btrfs_cmds.c index 8031c58..683aec0 100644 --- a/btrfs_cmds.c +++ b/btrfs_cmds.c @@ -705,6 +705,7 @@ int do_add_volume(int nargs, char **args) int devfd, res; u64 dev_block_count = 0; struct stat st; + int mixed = 0; devfd = open(args[i], O_RDWR); if (!devfd) { @@ -727,7 +728,7 @@ int do_add_volume(int nargs, char **args) continue; } - res = btrfs_prepare_device(devfd, args[i], 1, &dev_block_count); + res = btrfs_prepare_device(devfd, args[i], 1, &dev_block_count, &mixed); if (res) { fprintf(stderr, "ERROR: Unable to init '%s'\n", args[i]); close(devfd); @@ -889,8 +890,14 @@ int do_df_filesystem(int nargs, char **argv) memset(description, 0, 80); if (flags & BTRFS_BLOCK_GROUP_DATA) { - snprintf(description, 5, "%s", "Data"); - written += 4; + if (flags & BTRFS_BLOCK_GROUP_METADATA) { + snprintf(description, 15, "%s", + "Data+Metadata"); + written += 14; + } else { + snprintf(description, 5, "%s", "Data"); + written += 4; + } } else if (flags & BTRFS_BLOCK_GROUP_SYSTEM) { snprintf(description, 7, "%s", "System"); written += 6; diff --git a/ctree.h b/ctree.h index 962c510..ed83d02 100644 --- a/ctree.h +++ b/ctree.h @@ -352,13 +352,15 @@ struct btrfs_super_block { * ones specified below then we will fail to mount */ #define BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF (1ULL << 0) -#define BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL (2ULL << 0) +#define BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL (1ULL << 1) +#define BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS (1ULL << 2) #define BTRFS_FEATURE_COMPAT_SUPP 0ULL #define BTRFS_FEATURE_COMPAT_RO_SUPP 0ULL -#define BTRFS_FEATURE_INCOMPAT_SUPP \ - (BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF | \ - BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL) +#define BTRFS_FEATURE_INCOMPAT_SUPP \ + (BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF | \ + BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL | \ + BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS) /* * A leaf is full of items. offset and size tell us where to find diff --git a/mkfs.c b/mkfs.c index 2e99b95..04de93a 100644 --- a/mkfs.c +++ b/mkfs.c @@ -69,7 +69,7 @@ static u64 parse_size(char *s) return atol(s) * mult; } -static int make_root_dir(struct btrfs_root *root) +static int make_root_dir(struct btrfs_root *root, int mixed) { struct btrfs_trans_handle *trans; struct btrfs_key location; @@ -88,30 +88,47 @@ static int make_root_dir(struct btrfs_root *root) 0, BTRFS_MKFS_SYSTEM_GROUP_SIZE); BUG_ON(ret); - ret = btrfs_alloc_chunk(trans, root->fs_info->extent_root, - &chunk_start, &chunk_size, - BTRFS_BLOCK_GROUP_METADATA); - BUG_ON(ret); - ret = btrfs_make_block_group(trans, root, 0, - BTRFS_BLOCK_GROUP_METADATA, - BTRFS_FIRST_CHUNK_TREE_OBJECTID, - chunk_start, chunk_size); - BUG_ON(ret); + if (mixed) { + ret = btrfs_alloc_chunk(trans, root->fs_info->extent_root, + &chunk_start, &chunk_size, + BTRFS_BLOCK_GROUP_METADATA | + BTRFS_BLOCK_GROUP_DATA); + BUG_ON(ret); + ret = btrfs_make_block_group(trans, root, 0, + BTRFS_BLOCK_GROUP_METADATA | + BTRFS_BLOCK_GROUP_DATA, + BTRFS_FIRST_CHUNK_TREE_OBJECTID, + chunk_start, chunk_size); + BUG_ON(ret); + printf("Created a data/metadata chunk of size %llu\n", chunk_size); + } else { + ret = btrfs_alloc_chunk(trans, root->fs_info->extent_root, + &chunk_start, &chunk_size, + BTRFS_BLOCK_GROUP_METADATA); + BUG_ON(ret); + ret = btrfs_make_block_group(trans, root, 0, + BTRFS_BLOCK_GROUP_METADATA, + BTRFS_FIRST_CHUNK_TREE_OBJECTID, + chunk_start, chunk_size); + BUG_ON(ret); + } root->fs_info->system_allocs = 0; btrfs_commit_transaction(trans, root); trans = btrfs_start_transaction(root, 1); BUG_ON(!trans); - ret = btrfs_alloc_chunk(trans, root->fs_info->extent_root, - &chunk_start, &chunk_size, - BTRFS_BLOCK_GROUP_DATA); - BUG_ON(ret); - ret = btrfs_make_block_group(trans, root, 0, - BTRFS_BLOCK_GROUP_DATA, - BTRFS_FIRST_CHUNK_TREE_OBJECTID, - chunk_start, chunk_size); - BUG_ON(ret); + if (!mixed) { + ret = btrfs_alloc_chunk(trans, root->fs_info->extent_root, + &chunk_start, &chunk_size, + BTRFS_BLOCK_GROUP_DATA); + BUG_ON(ret); + ret = btrfs_make_block_group(trans, root, 0, + BTRFS_BLOCK_GROUP_DATA, + BTRFS_FIRST_CHUNK_TREE_OBJECTID, + chunk_start, chunk_size); + BUG_ON(ret); + } ret = btrfs_make_root_dir(trans, root->fs_info->tree_root, BTRFS_ROOT_TREE_DIR_OBJECTID); @@ -200,7 +217,7 @@ static int create_one_raid_group(struct btrfs_trans_handle *trans, static int create_raid_groups(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 data_profile, - u64 metadata_profile) + u64 metadata_profile, int mixed) { u64 num_devices = btrfs_super_num_devices(&root->fs_info->super_copy); u64 allowed; @@ -215,20 +232,24 @@ static int create_raid_groups(struct btrfs_trans_handle *trans, allowed = BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1; if (allowed & metadata_profile) { + u64 meta_flags = BTRFS_BLOCK_GROUP_METADATA; + ret = create_one_raid_group(trans, root, BTRFS_BLOCK_GROUP_SYSTEM | (allowed & metadata_profile)); BUG_ON(ret); - ret = create_one_raid_group(trans, root, - BTRFS_BLOCK_GROUP_METADATA | + if (mixed) + meta_flags |= BTRFS_BLOCK_GROUP_DATA; + + ret = create_one_raid_group(trans, root, meta_flags | (allowed & metadata_profile)); BUG_ON(ret); ret = recow_roots(trans, root); BUG_ON(ret); } - if (num_devices > 1 && (allowed & data_profile)) { + if (!mixed && num_devices > 1 && (allowed & data_profile)) { ret = create_one_raid_group(trans, root, BTRFS_BLOCK_GROUP_DATA | (allowed & data_profile)); @@ -274,6 +295,7 @@ static void print_usage(void) fprintf(stderr, "\t -l --leafsize size of btree leaves\n"); fprintf(stderr, "\t -L --label set a label\n"); fprintf(stderr, "\t -m --metadata metadata profile, values like data profile\n"); + fprintf(stderr, "\t -M --mixed mix metadata and data together\n"); fprintf(stderr, "\t -n --nodesize size of btree nodes\n"); fprintf(stderr, "\t -s --sectorsize min block allocation\n"); fprintf(stderr, "%s\n", BTRFS_BUILD_VERSION); @@ -328,6 +350,7 @@ static struct option long_options[] = { { "leafsize", 1, NULL, 'l' }, { "label", 1, NULL, 'L'}, { "metadata", 1, NULL, 'm' }, + { "mixed", 0, NULL, 'M' }, { "nodesize", 1, NULL, 'n' }, { "sectorsize", 1, NULL, 's' }, { "data", 1, NULL, 'd' }, @@ -358,10 +381,13 @@ int main(int ac, char **av) int first_fd; int ret; int i; + int mixed = 0; + int data_profile_opt = 0; + int metadata_profile_opt = 0; while(1) { int c; - c = getopt_long(ac, av, "A:b:l:n:s:m:d:L:V", long_options, + c = getopt_long(ac, av, "A:b:l:n:s:m:d:L:VM", long_options, &option_index); if (c < 0) break; @@ -371,6 +397,7 @@ int main(int ac, char **av) break; case 'd': data_profile = parse_profile(optarg); + data_profile_opt = 1; break; case 'l': leafsize = parse_size(optarg); @@ -380,6 +407,10 @@ int main(int ac, char **av) break; case 'm': metadata_profile = parse_profile(optarg); + metadata_profile_opt = 1; + break; + case 'M': + mixed = 1; break; case 'n': nodesize = parse_size(optarg); @@ -389,12 +420,10 @@ int main(int ac, char **av) break; case 'b': block_count = parse_size(optarg); - if (block_count < 256*1024*1024) { - fprintf(stderr, "File system size " - "%llu bytes is too small, " - "256M is required at least\n", - (unsigned long long)block_count); - exit(1); + if (block_count <= 1024*1024*1024) { + printf("SMALL VOLUME: forcing mixed " + "metadata/data groups\n"); + mixed = 1; } zero_end = 0; break; @@ -439,9 +468,22 @@ int main(int ac, char **av) } first_fd = fd; first_file = file; - ret = btrfs_prepare_device(fd, file, zero_end, &dev_block_count); + ret = btrfs_prepare_device(fd, file, zero_end, &dev_block_count, + &mixed); if (block_count == 0) block_count = dev_block_count; + if (mixed) { + if (!metadata_profile_opt) + metadata_profile = 0; + if (!data_profile_opt) + data_profile = 0; + + if (metadata_profile != data_profile) { + fprintf(stderr, "With mixed block groups data and metadata " + "profiles must be the same\n"); + exit(1); + } + } blocks[0] = BTRFS_SUPER_INFO_OFFSET; for (i = 1; i < 7; i++) { @@ -459,7 +501,7 @@ int main(int ac, char **av) root = open_ctree(file, 0, O_RDWR); root->fs_info->alloc_start = alloc_start; - ret = make_root_dir(root); + ret = make_root_dir(root, mixed); if (ret) { fprintf(stderr, "failed to setup the root directory\n"); exit(1); @@ -478,6 +520,8 @@ int main(int ac, char **av) zero_end = 1; while(ac-- > 0) { + int old_mixed = mixed; + file = av[optind++]; ret = check_mounted(file); if (ret < 0) { @@ -503,8 +547,8 @@ int main(int ac, char **av) continue; } ret = btrfs_prepare_device(fd, file, zero_end, - &dev_block_count); - + &dev_block_count, &mixed); + mixed = old_mixed; BUG_ON(ret); ret = btrfs_add_to_fsid(trans, root, fd, file, dev_block_count, @@ -515,12 +559,20 @@ int main(int ac, char **av) raid_groups: ret = create_raid_groups(trans, root, data_profile, - metadata_profile); + metadata_profile, mixed); BUG_ON(ret); ret = create_data_reloc_tree(trans, root); BUG_ON(ret); + if (mixed) { + struct btrfs_super_block *super = &root->fs_info->super_copy; + u64 flags = btrfs_super_incompat_flags(super); + + flags |= BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS; + btrfs_set_super_incompat_flags(super, flags); + } + printf("fs created label %s on %s\n\tnodesize %u leafsize %u " "sectorsize %u size %s\n", label, first_file, nodesize, leafsize, sectorsize, diff --git a/utils.c b/utils.c index b890728..13d31b7 100644 --- a/utils.c +++ b/utils.c @@ -508,7 +508,8 @@ int btrfs_add_to_fsid(struct btrfs_trans_handle *trans, return 0; } -int btrfs_prepare_device(int fd, char *file, int zero_end, u64 *block_count_ret) +int btrfs_prepare_device(int fd, char *file, int zero_end, u64 *block_count_ret, + int *mixed) { u64 block_count; u64 bytenr; @@ -528,10 +529,9 @@ int btrfs_prepare_device(int fd, char *file, int zero_end, u64 *block_count_ret) } zero_end = 1; - if (block_count < 256 * 1024 * 1024) { - fprintf(stderr, "device %s is too small " - "(must be at least 256 MB)\n", file); - exit(1); + if (block_count < 1024 * 1024 * 1024 && !(*mixed)) { + printf("SMALL VOLUME: forcing mixed metadata/data groups\n"); + *mixed = 1; } ret = zero_dev_start(fd); if (ret) { diff --git a/utils.h b/utils.h index 7ff542b..b91140e 100644 --- a/utils.h +++ b/utils.h @@ -27,7 +27,7 @@ int make_btrfs(int fd, const char *device, const char *label, int btrfs_make_root_dir(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 objectid); int btrfs_prepare_device(int fd, char *file, int zero_end, - u64 *block_count_ret); + u64 *block_count_ret, int *mixed); int btrfs_add_to_fsid(struct btrfs_trans_handle *trans, struct btrfs_root *root, int fd, char *path, u64 block_count, u32 io_width, u32 io_align,