Browse Source

Btrfs: Add mount option to enforce a max extent size

Signed-off-by: Chris Mason <chris.mason@oracle.com>
Chris Mason 17 years ago
parent
commit
c59f8951d4
4 changed files with 65 additions and 11 deletions
  1. 1 0
      fs/btrfs/ctree.h
  2. 1 0
      fs/btrfs/disk-io.c
  3. 18 10
      fs/btrfs/inode.c
  4. 45 1
      fs/btrfs/super.c

+ 1 - 0
fs/btrfs/ctree.h

@@ -322,6 +322,7 @@ struct btrfs_fs_info {
 	u64 generation;
 	u64 generation;
 	u64 last_trans_committed;
 	u64 last_trans_committed;
 	unsigned long mount_opt;
 	unsigned long mount_opt;
+	u64 max_extent;
 	struct btrfs_transaction *running_transaction;
 	struct btrfs_transaction *running_transaction;
 	struct btrfs_super_block super_copy;
 	struct btrfs_super_block super_copy;
 	struct extent_buffer *sb_buffer;
 	struct extent_buffer *sb_buffer;

+ 1 - 0
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->extent_root = extent_root;
 	fs_info->sb = sb;
 	fs_info->sb = sb;
 	fs_info->mount_opt = 0;
 	fs_info->mount_opt = 0;
+	fs_info->max_extent = (u64)-1;
 	fs_info->btree_inode = new_inode(sb);
 	fs_info->btree_inode = new_inode(sb);
 	fs_info->btree_inode->i_ino = 1;
 	fs_info->btree_inode->i_ino = 1;
 	fs_info->btree_inode->i_nlink = 1;
 	fs_info->btree_inode->i_nlink = 1;

+ 18 - 10
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;
 	struct btrfs_trans_handle *trans;
 	u64 alloc_hint = 0;
 	u64 alloc_hint = 0;
 	u64 num_bytes;
 	u64 num_bytes;
+	u64 cur_alloc_size;
 	u64 blocksize = root->sectorsize;
 	u64 blocksize = root->sectorsize;
 	struct btrfs_key ins;
 	struct btrfs_key ins;
 	int ret;
 	int ret;
@@ -94,17 +95,24 @@ static int cow_file_range(struct inode *inode, u64 start, u64 end)
 	if (alloc_hint == EXTENT_MAP_INLINE)
 	if (alloc_hint == EXTENT_MAP_INLINE)
 		goto out;
 		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:
 out:
 	btrfs_end_transaction(trans, root);
 	btrfs_end_transaction(trans, root);
 	return ret;
 	return ret;

+ 45 - 1
fs/btrfs/super.c

@@ -34,6 +34,7 @@
 #include <linux/statfs.h>
 #include <linux/statfs.h>
 #include <linux/compat.h>
 #include <linux/compat.h>
 #include <linux/parser.h>
 #include <linux/parser.h>
+#include <linux/ctype.h>
 #include "ctree.h"
 #include "ctree.h"
 #include "disk-io.h"
 #include "disk-io.h"
 #include "transaction.h"
 #include "transaction.h"
@@ -61,16 +62,42 @@ static void btrfs_put_super (struct super_block * sb)
 }
 }
 
 
 enum {
 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 = {
 static match_table_t tokens = {
 	{Opt_subvol, "subvol=%s"},
 	{Opt_subvol, "subvol=%s"},
 	{Opt_nodatasum, "nodatasum"},
 	{Opt_nodatasum, "nodatasum"},
 	{Opt_nodatacow, "nodatacow"},
 	{Opt_nodatacow, "nodatacow"},
+	{Opt_max_extent, "max_extent=%s"},
 	{Opt_err, NULL}
 	{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,
 static int parse_options (char * options,
 			  struct btrfs_root *root,
 			  struct btrfs_root *root,
 			  char **subvol_name)
 			  char **subvol_name)
@@ -118,6 +145,21 @@ static int parse_options (char * options,
 				btrfs_set_opt(info->mount_opt, NODATASUM);
 				btrfs_set_opt(info->mount_opt, NODATASUM);
 			}
 			}
 			break;
 			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:
 		default:
 			break;
 			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,
 	ret = btrfs_get_sb_bdev(fs_type, flags, dev_name, data,
 			btrfs_fill_super, mnt,
 			btrfs_fill_super, mnt,
 			subvol_name ? subvol_name : "default");
 			subvol_name ? subvol_name : "default");
+	if (subvol_name)
+		kfree(subvol_name);
 	return ret;
 	return ret;
 }
 }