Commit 633c0aad authored by Josef Bacik's avatar Josef Bacik Committed by Chris Mason

Btrfs: move read only block groups onto their own list V2

Our gluster boxes were spending lots of time in statfs because our fs'es are
huge.  The problem is statfs loops through all of the block groups looking for
read only block groups, and when you have several terabytes worth of data that
ends up being a lot of block groups.  Move the read only block groups onto a
read only list and only proces that list in
btrfs_account_ro_block_groups_free_space to reduce the amount of churn.  Thanks,
Signed-off-by: default avatarJosef Bacik <jbacik@fb.com>
Reviewed-by: default avatarLiu Bo <bo.li.liu@oracle.com>
Signed-off-by: default avatarChris Mason <clm@fb.com>
parent cd743fac
...@@ -1170,6 +1170,7 @@ struct btrfs_space_info { ...@@ -1170,6 +1170,7 @@ struct btrfs_space_info {
struct percpu_counter total_bytes_pinned; struct percpu_counter total_bytes_pinned;
struct list_head list; struct list_head list;
struct list_head ro_bgs;
struct rw_semaphore groups_sem; struct rw_semaphore groups_sem;
/* for block groups in our same type */ /* for block groups in our same type */
...@@ -1305,6 +1306,9 @@ struct btrfs_block_group_cache { ...@@ -1305,6 +1306,9 @@ struct btrfs_block_group_cache {
/* For delayed block group creation or deletion of empty block groups */ /* For delayed block group creation or deletion of empty block groups */
struct list_head bg_list; struct list_head bg_list;
/* For read-only block groups */
struct list_head ro_list;
}; };
/* delayed seq elem */ /* delayed seq elem */
......
...@@ -3504,6 +3504,7 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags, ...@@ -3504,6 +3504,7 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags,
found->chunk_alloc = 0; found->chunk_alloc = 0;
found->flush = 0; found->flush = 0;
init_waitqueue_head(&found->wait); init_waitqueue_head(&found->wait);
INIT_LIST_HEAD(&found->ro_bgs);
ret = kobject_init_and_add(&found->kobj, &space_info_ktype, ret = kobject_init_and_add(&found->kobj, &space_info_ktype,
info->space_info_kobj, "%s", info->space_info_kobj, "%s",
...@@ -8511,6 +8512,7 @@ static int set_block_group_ro(struct btrfs_block_group_cache *cache, int force) ...@@ -8511,6 +8512,7 @@ static int set_block_group_ro(struct btrfs_block_group_cache *cache, int force)
min_allocable_bytes <= sinfo->total_bytes) { min_allocable_bytes <= sinfo->total_bytes) {
sinfo->bytes_readonly += num_bytes; sinfo->bytes_readonly += num_bytes;
cache->ro = 1; cache->ro = 1;
list_add_tail(&cache->ro_list, &sinfo->ro_bgs);
ret = 0; ret = 0;
} }
out: out:
...@@ -8565,15 +8567,20 @@ int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans, ...@@ -8565,15 +8567,20 @@ int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans,
/* /*
* helper to account the unused space of all the readonly block group in the * helper to account the unused space of all the readonly block group in the
* list. takes mirrors into account. * space_info. takes mirrors into account.
*/ */
static u64 __btrfs_get_ro_block_group_free_space(struct list_head *groups_list) u64 btrfs_account_ro_block_groups_free_space(struct btrfs_space_info *sinfo)
{ {
struct btrfs_block_group_cache *block_group; struct btrfs_block_group_cache *block_group;
u64 free_bytes = 0; u64 free_bytes = 0;
int factor; int factor;
list_for_each_entry(block_group, groups_list, list) { /* It's df, we don't care if it's racey */
if (list_empty(&sinfo->ro_bgs))
return 0;
spin_lock(&sinfo->lock);
list_for_each_entry(block_group, &sinfo->ro_bgs, ro_list) {
spin_lock(&block_group->lock); spin_lock(&block_group->lock);
if (!block_group->ro) { if (!block_group->ro) {
...@@ -8594,26 +8601,6 @@ static u64 __btrfs_get_ro_block_group_free_space(struct list_head *groups_list) ...@@ -8594,26 +8601,6 @@ static u64 __btrfs_get_ro_block_group_free_space(struct list_head *groups_list)
spin_unlock(&block_group->lock); spin_unlock(&block_group->lock);
} }
return free_bytes;
}
/*
* helper to account the unused space of all the readonly block group in the
* space_info. takes mirrors into account.
*/
u64 btrfs_account_ro_block_groups_free_space(struct btrfs_space_info *sinfo)
{
int i;
u64 free_bytes = 0;
spin_lock(&sinfo->lock);
for (i = 0; i < BTRFS_NR_RAID_TYPES; i++)
if (!list_empty(&sinfo->block_groups[i]))
free_bytes += __btrfs_get_ro_block_group_free_space(
&sinfo->block_groups[i]);
spin_unlock(&sinfo->lock); spin_unlock(&sinfo->lock);
return free_bytes; return free_bytes;
...@@ -8633,6 +8620,7 @@ void btrfs_set_block_group_rw(struct btrfs_root *root, ...@@ -8633,6 +8620,7 @@ void btrfs_set_block_group_rw(struct btrfs_root *root,
cache->bytes_super - btrfs_block_group_used(&cache->item); cache->bytes_super - btrfs_block_group_used(&cache->item);
sinfo->bytes_readonly -= num_bytes; sinfo->bytes_readonly -= num_bytes;
cache->ro = 0; cache->ro = 0;
list_del_init(&cache->ro_list);
spin_unlock(&cache->lock); spin_unlock(&cache->lock);
spin_unlock(&sinfo->lock); spin_unlock(&sinfo->lock);
} }
...@@ -9002,6 +8990,7 @@ btrfs_create_block_group_cache(struct btrfs_root *root, u64 start, u64 size) ...@@ -9002,6 +8990,7 @@ btrfs_create_block_group_cache(struct btrfs_root *root, u64 start, u64 size)
INIT_LIST_HEAD(&cache->list); INIT_LIST_HEAD(&cache->list);
INIT_LIST_HEAD(&cache->cluster_list); INIT_LIST_HEAD(&cache->cluster_list);
INIT_LIST_HEAD(&cache->bg_list); INIT_LIST_HEAD(&cache->bg_list);
INIT_LIST_HEAD(&cache->ro_list);
btrfs_init_free_space_ctl(cache); btrfs_init_free_space_ctl(cache);
return cache; return cache;
...@@ -9411,6 +9400,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, ...@@ -9411,6 +9400,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
* are still on the list after taking the semaphore * are still on the list after taking the semaphore
*/ */
list_del_init(&block_group->list); list_del_init(&block_group->list);
list_del_init(&block_group->ro_list);
if (list_empty(&block_group->space_info->block_groups[index])) { if (list_empty(&block_group->space_info->block_groups[index])) {
kobj = block_group->space_info->block_group_kobjs[index]; kobj = block_group->space_info->block_group_kobjs[index];
block_group->space_info->block_group_kobjs[index] = NULL; block_group->space_info->block_group_kobjs[index] = NULL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment