Btrfs: try to keep a healthy ratio of metadata vs data block groups
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>
This commit is contained in:
Родитель
546888da82
Коммит
97e728d435
|
@ -881,6 +881,9 @@ struct btrfs_fs_info {
|
||||||
u64 metadata_alloc_profile;
|
u64 metadata_alloc_profile;
|
||||||
u64 system_alloc_profile;
|
u64 system_alloc_profile;
|
||||||
|
|
||||||
|
unsigned data_chunk_allocations;
|
||||||
|
unsigned metadata_ratio;
|
||||||
|
|
||||||
void *bdev_holder;
|
void *bdev_holder;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1604,6 +1604,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
|
||||||
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;
|
||||||
|
fs_info->metadata_ratio = 8;
|
||||||
|
|
||||||
fs_info->thread_pool_size = min_t(unsigned long,
|
fs_info->thread_pool_size = min_t(unsigned long,
|
||||||
num_online_cpus() + 2, 8);
|
num_online_cpus() + 2, 8);
|
||||||
|
|
|
@ -1918,15 +1918,29 @@ void btrfs_delalloc_free_space(struct btrfs_root *root, struct inode *inode,
|
||||||
spin_unlock(&info->lock);
|
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,
|
static int do_chunk_alloc(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *extent_root, u64 alloc_bytes,
|
struct btrfs_root *extent_root, u64 alloc_bytes,
|
||||||
u64 flags, int force)
|
u64 flags, int force)
|
||||||
{
|
{
|
||||||
struct btrfs_space_info *space_info;
|
struct btrfs_space_info *space_info;
|
||||||
|
struct btrfs_fs_info *fs_info = extent_root->fs_info;
|
||||||
u64 thresh;
|
u64 thresh;
|
||||||
int ret = 0;
|
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);
|
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);
|
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);
|
ret = btrfs_alloc_chunk(trans, extent_root, flags);
|
||||||
if (ret)
|
if (ret)
|
||||||
space_info->full = 1;
|
space_info->full = 1;
|
||||||
|
|
|
@ -68,7 +68,7 @@ enum {
|
||||||
Opt_degraded, Opt_subvol, Opt_device, Opt_nodatasum, Opt_nodatacow,
|
Opt_degraded, Opt_subvol, Opt_device, Opt_nodatasum, Opt_nodatacow,
|
||||||
Opt_max_extent, Opt_max_inline, Opt_alloc_start, Opt_nobarrier,
|
Opt_max_extent, Opt_max_inline, Opt_alloc_start, Opt_nobarrier,
|
||||||
Opt_ssd, Opt_thread_pool, Opt_noacl, Opt_compress, Opt_notreelog,
|
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 = {
|
static match_table_t tokens = {
|
||||||
|
@ -87,6 +87,7 @@ static match_table_t tokens = {
|
||||||
{Opt_noacl, "noacl"},
|
{Opt_noacl, "noacl"},
|
||||||
{Opt_notreelog, "notreelog"},
|
{Opt_notreelog, "notreelog"},
|
||||||
{Opt_flushoncommit, "flushoncommit"},
|
{Opt_flushoncommit, "flushoncommit"},
|
||||||
|
{Opt_ratio, "metadata_ratio=%d"},
|
||||||
{Opt_err, NULL},
|
{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");
|
printk(KERN_INFO "btrfs: turning on flush-on-commit\n");
|
||||||
btrfs_set_opt(info->mount_opt, FLUSHONCOMMIT);
|
btrfs_set_opt(info->mount_opt, FLUSHONCOMMIT);
|
||||||
break;
|
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:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче