Btrfs: two stage dirty block group writeout

Block group cache writeout is currently waiting on the pages for each
block group cache before moving on to writing the next one.  This commit
switches things around to send down all the caches and then wait on them
in batches.

The end result is much faster, since we're keeping the disk pipeline
full.

Signed-off-by: Chris Mason <clm@fb.com>
This commit is contained in:
Chris Mason
2015-04-04 17:14:42 -07:00
parent 4c6d1d85ad
commit c9dc4c6578
4 changed files with 170 additions and 32 deletions

View File

@@ -3388,7 +3388,11 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
struct btrfs_block_group_cache *cache;
struct btrfs_transaction *cur_trans = trans->transaction;
int ret = 0;
int should_put;
struct btrfs_path *path;
LIST_HEAD(io);
int num_started = 0;
int num_waited = 0;
if (list_empty(&cur_trans->dirty_bgs))
return 0;
@@ -3407,16 +3411,60 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
cache = list_first_entry(&cur_trans->dirty_bgs,
struct btrfs_block_group_cache,
dirty_list);
/*
* this can happen if cache_save_setup re-dirties a block
* group that is already under IO. Just wait for it to
* finish and then do it all again
*/
if (!list_empty(&cache->io_list)) {
list_del_init(&cache->io_list);
btrfs_wait_cache_io(root, trans, cache,
&cache->io_ctl, path,
cache->key.objectid);
btrfs_put_block_group(cache);
num_waited++;
}
list_del_init(&cache->dirty_list);
should_put = 1;
if (cache->disk_cache_state == BTRFS_DC_CLEAR)
cache_save_setup(cache, trans, path);
if (!ret)
ret = btrfs_run_delayed_refs(trans, root,
(unsigned long) -1);
if (!ret && cache->disk_cache_state == BTRFS_DC_SETUP)
btrfs_write_out_cache(root, trans, cache, path);
ret = btrfs_run_delayed_refs(trans, root, (unsigned long) -1);
if (!ret && cache->disk_cache_state == BTRFS_DC_SETUP) {
cache->io_ctl.inode = NULL;
ret = btrfs_write_out_cache(root, trans, cache, path);
if (ret == 0 && cache->io_ctl.inode) {
num_started++;
should_put = 0;
list_add_tail(&cache->io_list, &io);
} else {
/*
* if we failed to write the cache, the
* generation will be bad and life goes on
*/
ret = 0;
}
}
if (!ret)
ret = write_one_cache_group(trans, root, path, cache);
/* if its not on the io list, we need to put the block group */
if (should_put)
btrfs_put_block_group(cache);
}
while (!list_empty(&io)) {
cache = list_first_entry(&io, struct btrfs_block_group_cache,
io_list);
list_del_init(&cache->io_list);
num_waited++;
btrfs_wait_cache_io(root, trans, cache,
&cache->io_ctl, path, cache->key.objectid);
btrfs_put_block_group(cache);
}
@@ -9013,6 +9061,7 @@ btrfs_create_block_group_cache(struct btrfs_root *root, u64 start, u64 size)
INIT_LIST_HEAD(&cache->bg_list);
INIT_LIST_HEAD(&cache->ro_list);
INIT_LIST_HEAD(&cache->dirty_list);
INIT_LIST_HEAD(&cache->io_list);
btrfs_init_free_space_ctl(cache);
atomic_set(&cache->trimming, 0);