summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/ctree.h1
-rw-r--r--fs/btrfs/disk-io.c1
-rw-r--r--fs/btrfs/inode.c28
-rw-r--r--fs/btrfs/super.c46
4 files changed, 65 insertions, 11 deletions
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 @@ 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;
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 @@ 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;
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 @@ 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;
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 @@ 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;
}