Btrfs: try to keep a healthy ratio of metadata vs data block groups
authorJosef Bacik <jbacik@redhat.com>
Tue, 21 Apr 2009 21:40:57 +0000 (17:40 -0400)
committerChris Mason <chris.mason@oracle.com>
Fri, 24 Apr 2009 19:46:02 +0000 (15:46 -0400)
This patch makes the chunk allocator keep a good ratio of metadata vs data
block groups.  By default for every 8 data block groups, we'll allocate 1
metadata chunk, or about 12% of the disk will be allocated for metadata.  This
can be changed by specifying the metadata_ratio mount option.

This is simply the number of data block groups that have to be allocated to
force a metadata chunk allocation.  By making sure we allocate metadata chunks
more often, we are less likely to get into situations where the whole disk
has been allocated as data block groups.

Signed-off-by: Josef Bacik <jbacik@redhat.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>
fs/btrfs/ctree.h
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/super.c

index ad96495dedc52f79a05cdbccfea20383b871164f..213535f45da2418578506b0c3ea582da1c6e3b9c 100644 (file)
@@ -881,6 +881,9 @@ struct btrfs_fs_info {
        u64 metadata_alloc_profile;
        u64 system_alloc_profile;
 
+       unsigned data_chunk_allocations;
+       unsigned metadata_ratio;
+
        void *bdev_holder;
 };
 
index a6b83744b05da6184caff93080cff1eeab1159b9..44c94d808e2b9a1d900c55c03b16960a6fd90081 100644 (file)
@@ -1604,6 +1604,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
        fs_info->btree_inode = new_inode(sb);
        fs_info->btree_inode->i_ino = 1;
        fs_info->btree_inode->i_nlink = 1;
+       fs_info->metadata_ratio = 8;
 
        fs_info->thread_pool_size = min_t(unsigned long,
                                          num_online_cpus() + 2, 8);
index 178df4c67de447e87514e90284a7ccc294dc8df1..2895a8373232743c599c51c3c25ba9187162445e 100644 (file)
@@ -1918,15 +1918,29 @@ void btrfs_delalloc_free_space(struct btrfs_root *root, struct inode *inode,
        spin_unlock(&info->lock);
 }
 
+static void force_metadata_allocation(struct btrfs_fs_info *info)
+{
+       struct list_head *head = &info->space_info;
+       struct btrfs_space_info *found;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(found, head, list) {
+               if (found->flags & BTRFS_BLOCK_GROUP_METADATA)
+                       found->force_alloc = 1;
+       }
+       rcu_read_unlock();
+}
+
 static int do_chunk_alloc(struct btrfs_trans_handle *trans,
                          struct btrfs_root *extent_root, u64 alloc_bytes,
                          u64 flags, int force)
 {
        struct btrfs_space_info *space_info;
+       struct btrfs_fs_info *fs_info = extent_root->fs_info;
        u64 thresh;
        int ret = 0;
 
-       mutex_lock(&extent_root->fs_info->chunk_mutex);
+       mutex_lock(&fs_info->chunk_mutex);
 
        flags = btrfs_reduce_alloc_profile(extent_root, flags);
 
@@ -1958,6 +1972,18 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans,
        }
        spin_unlock(&space_info->lock);
 
+       /*
+        * if we're doing a data chunk, go ahead and make sure that
+        * we keep a reasonable number of metadata chunks allocated in the
+        * FS as well.
+        */
+       if (flags & BTRFS_BLOCK_GROUP_DATA) {
+               fs_info->data_chunk_allocations++;
+               if (!(fs_info->data_chunk_allocations %
+                     fs_info->metadata_ratio))
+                       force_metadata_allocation(fs_info);
+       }
+
        ret = btrfs_alloc_chunk(trans, extent_root, flags);
        if (ret)
                space_info->full = 1;
index 9744af9d71e95afa3a66f9ac1b2188722318aad8..30c9a8ca2a5460c1a2b1d2ca0fa651fa951a4252 100644 (file)
@@ -68,7 +68,7 @@ enum {
        Opt_degraded, Opt_subvol, Opt_device, Opt_nodatasum, Opt_nodatacow,
        Opt_max_extent, Opt_max_inline, Opt_alloc_start, Opt_nobarrier,
        Opt_ssd, Opt_thread_pool, Opt_noacl,  Opt_compress, Opt_notreelog,
-       Opt_flushoncommit, Opt_err,
+       Opt_ratio, Opt_flushoncommit, Opt_err,
 };
 
 static match_table_t tokens = {
@@ -87,6 +87,7 @@ static match_table_t tokens = {
        {Opt_noacl, "noacl"},
        {Opt_notreelog, "notreelog"},
        {Opt_flushoncommit, "flushoncommit"},
+       {Opt_ratio, "metadata_ratio=%d"},
        {Opt_err, NULL},
 };
 
@@ -234,6 +235,15 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                        printk(KERN_INFO "btrfs: turning on flush-on-commit\n");
                        btrfs_set_opt(info->mount_opt, FLUSHONCOMMIT);
                        break;
+               case Opt_ratio:
+                       intarg = 0;
+                       match_int(&args[0], &intarg);
+                       if (intarg) {
+                               info->metadata_ratio = intarg;
+                               printk(KERN_INFO "btrfs: metadata ratio %d\n",
+                                      info->metadata_ratio);
+                       }
+                       break;
                default:
                        break;
                }