Btrfs: Add mount option to enforce a max extent size
authorChris Mason <chris.mason@oracle.com>
Tue, 18 Dec 2007 01:14:04 +0000 (20:14 -0500)
committerChris Mason <chris.mason@oracle.com>
Thu, 25 Sep 2008 15:03:58 +0000 (11:03 -0400)
Signed-off-by: Chris Mason <chris.mason@oracle.com>
fs/btrfs/ctree.h
fs/btrfs/disk-io.c
fs/btrfs/inode.c
fs/btrfs/super.c

index b51b021fff85e9ad70f0ed6c5af0f1849cfded85..32b24460ec822d91d9c8329b65d8b9d0dee8d5d9 100644 (file)
@@ -322,6 +322,7 @@ struct btrfs_fs_info {
        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;
index 2785641789932ae8b097b482c4ba5df4f6431217..7213012c27d529027a8d574a4f391b72e6c225ec 100644 (file)
@@ -569,6 +569,7 @@ struct btrfs_root *open_ctree(struct super_block *sb)
        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;
index 91f3fc43e2a98c2a89c1e36981e4f10c15019309..686dd03f34f25d8d6fc0e17c6116e71672592b3f 100644 (file)
@@ -78,6 +78,7 @@ static int cow_file_range(struct inode *inode, u64 start, u64 end)
        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 @@ static int cow_file_range(struct inode *inode, u64 start, u64 end)
        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;
index 2116728d1f98223345d8ca0018d1940821b39806..b7323914bf5a144fc098d63764eb3db9190268f2 100644 (file)
@@ -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 @@ static void btrfs_put_super (struct super_block * sb)
 }
 
 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 @@ static int parse_options (char * options,
                                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 @@ static int btrfs_get_sb(struct file_system_type *fs_type,
        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;
 }