@@ -1203,6 +1203,7 @@ struct btrfs_fs_info {
struct btrfs_workers submit_workers;
struct btrfs_workers caching_workers;
struct btrfs_workers readahead_workers;
+ struct btrfs_workers es_merge_workers;
/*
* fixup workers take dirty pages that didn't properly go through
@@ -2214,6 +2214,9 @@ int open_ctree(struct super_block *sb,
btrfs_init_workers(&fs_info->readahead_workers, "readahead",
fs_info->thread_pool_size,
&fs_info->generic_worker);
+ btrfs_init_workers(&fs_info->es_merge_workers, "esmerge",
+ fs_info->thread_pool_size,
+ &fs_info->generic_worker);
/*
* endios are largely parallel and should have a very
@@ -2244,6 +2247,7 @@ int open_ctree(struct super_block *sb,
ret |= btrfs_start_workers(&fs_info->delayed_workers);
ret |= btrfs_start_workers(&fs_info->caching_workers);
ret |= btrfs_start_workers(&fs_info->readahead_workers);
+ ret |= btrfs_start_workers(&fs_info->es_merge_workers);
if (ret) {
ret = -ENOMEM;
goto fail_sb_buffer;
@@ -2544,6 +2548,7 @@ fail_sb_buffer:
btrfs_stop_workers(&fs_info->submit_workers);
btrfs_stop_workers(&fs_info->delayed_workers);
btrfs_stop_workers(&fs_info->caching_workers);
+ btrfs_stop_workers(&fs_info->es_merge_workers);
fail_alloc:
fail_iput:
btrfs_mapping_tree_free(&fs_info->mapping_tree);
@@ -3149,6 +3154,7 @@ int close_ctree(struct btrfs_root *root)
btrfs_stop_workers(&fs_info->delayed_workers);
btrfs_stop_workers(&fs_info->caching_workers);
btrfs_stop_workers(&fs_info->readahead_workers);
+ btrfs_stop_workers(&fs_info->es_merge_workers);
#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
if (btrfs_test_opt(root, CHECK_INTEGRITY))
@@ -552,16 +552,34 @@ static int test_merge_state(struct extent_io_tree *tree,
return 0;
}
-static void process_merge_state(struct extent_io_tree *tree, u64 start)
+struct async_merge_state {
+ struct extent_io_tree *tree;
+ u64 start;
+ struct btrfs_work work;
+};
+
+static void process_merge_state(struct btrfs_work *work)
{
+ struct async_merge_state *async = NULL;
+ struct extent_io_tree *tree = NULL;
struct extent_state *state = NULL;
struct rb_node *node = NULL;
+ struct btrfs_fs_info *fs_info = NULL;
+ u64 start;
+
+ async = container_of(work, struct async_merge_state, work);
+ BUG_ON(!async);
+ tree = async->tree;
+ start = async->start;
if (!tree || start == (u64)-1) {
WARN_ON(1);
+ kfree(async);
return;
}
+ fs_info = BTRFS_I(tree->mapping->host)->root->fs_info;
+
write_lock(&tree->lock);
node = tree_search(tree, start);
if (!node)
@@ -574,6 +592,31 @@ static void process_merge_state(struct extent_io_tree *tree, u64 start)
spin_unlock(&state->lock);
out:
write_unlock(&tree->lock);
+
+ WARN_ON(!tree->mapping->host);
+ if (tree->mapping->host)
+ iput(tree->mapping->host);
+ kfree(async);
+}
+
+static int btrfs_async_merge_state(struct extent_io_tree *tree,
+ u64 start, gfp_t mask)
+{
+ struct async_merge_state *async;
+ struct btrfs_fs_info *fs_info
+ = BTRFS_I(tree->mapping->host)->root->fs_info;
+
+ async = kzalloc(sizeof(*async), mask);
+ if (!async)
+ return -ENOMEM;
+ igrab(tree->mapping->host);
+ async->tree = tree;
+ async->start = start;
+ async->work.func = process_merge_state;
+ async->work.flags = 0;
+ btrfs_queue_worker(&fs_info->es_merge_workers, &async->work);
+
+ return 0;
}
enum extent_lock_type {
@@ -808,7 +851,7 @@ out:
if (orig_bits & EXTENT_NOMERGE)
return merge;
else
- process_merge_state(tree, orig_start);
+ btrfs_async_merge_state(tree, orig_start, mask);
}
return 0;
@@ -1156,7 +1199,7 @@ out:
if (prealloc)
free_extent_state(prealloc);
if (merge)
- process_merge_state(tree, orig_start);
+ btrfs_async_merge_state(tree, orig_start, mask);
return err;
@@ -2703,7 +2746,7 @@ static void end_bio_extent_readpage(struct bio *bio, int err)
} while (bvec <= bvec_end);
if (merge && tree && range_start < (u64)-1)
- process_merge_state(tree, range_start);
+ btrfs_async_merge_state(tree, range_start, GFP_ATOMIC);
bio_put(bio);
}
@@ -1134,6 +1134,7 @@ static void btrfs_resize_thread_pool(struct btrfs_fs_info *fs_info,
btrfs_set_max_workers(&fs_info->delayed_workers, new_pool_size);
btrfs_set_max_workers(&fs_info->readahead_workers, new_pool_size);
btrfs_set_max_workers(&fs_info->scrub_workers, new_pool_size);
+ btrfs_set_max_workers(&fs_info->es_merge_workers, new_pool_size);
}
static int btrfs_remount(struct super_block *sb, int *flags, char *data)
This is the second part of parallel endios for read. Here we use an async helper thread to process batched merges, so we eventually get endio for read to avoid acquiring or holding any write locks of extent state tree. Signed-off-by: Liu Bo <liubo2009@cn.fujitsu.com> --- fs/btrfs/ctree.h | 1 + fs/btrfs/disk-io.c | 6 +++++ fs/btrfs/extent_io.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++--- fs/btrfs/super.c | 1 + 4 files changed, 55 insertions(+), 4 deletions(-)