Btrfs: Add mount option to enforce a max extent size Signed-off-by: Chris Mason <chris.mason@oracle.com>
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index b51b021..32b2446 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h
@@ -322,6 +322,7 @@ u64 generation; u64 last_trans_committed; unsigned long mount_opt; + u64 max_extent; struct btrfs_transaction *running_transaction; struct btrfs_super_block super_copy; struct extent_buffer *sb_buffer;
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 2785641..7213012 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c
@@ -569,6 +569,7 @@ fs_info->extent_root = extent_root; fs_info->sb = sb; fs_info->mount_opt = 0; + fs_info->max_extent = (u64)-1; fs_info->btree_inode = new_inode(sb); fs_info->btree_inode->i_ino = 1; fs_info->btree_inode->i_nlink = 1;
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 91f3fc4..686dd03 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c
@@ -78,6 +78,7 @@ struct btrfs_trans_handle *trans; u64 alloc_hint = 0; u64 num_bytes; + u64 cur_alloc_size; u64 blocksize = root->sectorsize; struct btrfs_key ins; int ret; @@ -94,17 +95,24 @@ if (alloc_hint == EXTENT_MAP_INLINE) goto out; - ret = btrfs_alloc_extent(trans, root, num_bytes, - root->root_key.objectid, trans->transid, - inode->i_ino, start, 0, - alloc_hint, (u64)-1, &ins, 1); - if (ret) { - WARN_ON(1); - goto out; + while(num_bytes > 0) { + cur_alloc_size = min(num_bytes, root->fs_info->max_extent); + ret = btrfs_alloc_extent(trans, root, cur_alloc_size, + root->root_key.objectid, + trans->transid, + inode->i_ino, start, 0, + alloc_hint, (u64)-1, &ins, 1); + if (ret) { + WARN_ON(1); + goto out; + } + ret = btrfs_insert_file_extent(trans, root, inode->i_ino, + start, ins.objectid, ins.offset, + ins.offset); + num_bytes -= cur_alloc_size; + alloc_hint = ins.objectid + ins.offset; + start += cur_alloc_size; } - ret = btrfs_insert_file_extent(trans, root, inode->i_ino, - start, ins.objectid, ins.offset, - ins.offset); out: btrfs_end_transaction(trans, root); return ret;
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 2116728..b732391 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c
@@ -34,6 +34,7 @@ #include <linux/statfs.h> #include <linux/compat.h> #include <linux/parser.h> +#include <linux/ctype.h> #include "ctree.h" #include "disk-io.h" #include "transaction.h" @@ -61,16 +62,42 @@ } enum { - Opt_subvol, Opt_nodatasum, Opt_nodatacow, Opt_err, + Opt_subvol, Opt_nodatasum, Opt_nodatacow, Opt_max_extent, Opt_err, }; static match_table_t tokens = { {Opt_subvol, "subvol=%s"}, {Opt_nodatasum, "nodatasum"}, {Opt_nodatacow, "nodatacow"}, + {Opt_max_extent, "max_extent=%s"}, {Opt_err, NULL} }; +static unsigned long parse_size(char *str) +{ + unsigned long res; + int mult = 1; + char *end; + char last; + + res = simple_strtoul(str, &end, 10); + + last = end[0]; + if (isalpha(last)) { + last = tolower(last); + switch (last) { + case 'g': + mult *= 1024; + case 'm': + mult *= 1024; + case 'k': + mult *= 1024; + } + res = res * mult; + } + return res; +} + static int parse_options (char * options, struct btrfs_root *root, char **subvol_name) @@ -118,6 +145,21 @@ btrfs_set_opt(info->mount_opt, NODATASUM); } break; + case Opt_max_extent: + if (info) { + char *num = match_strdup(&args[0]); + if (num) { + info->max_extent = parse_size(num); + kfree(num); + + info->max_extent = max_t(u64, + info->max_extent, + root->sectorsize); + printk("btrfs: max_extent at %Lu\n", + info->max_extent); + } + } + break; default: break; } @@ -329,6 +371,8 @@ ret = btrfs_get_sb_bdev(fs_type, flags, dev_name, data, btrfs_fill_super, mnt, subvol_name ? subvol_name : "default"); + if (subvol_name) + kfree(subvol_name); return ret; }