aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorChris Mason <clm@fb.com>2014-05-22 19:18:52 -0400
committerChris Mason <clm@fb.com>2014-06-09 20:20:58 -0400
commita79b7d4b3e8118f265dcb4bdf9a572c392f02708 (patch)
treea7b4792e01ea5a44467f053e1822d4240e70edc6 /fs
parent40f765805f082ed679c55bf6ab60212e55fb6fc1 (diff)
Btrfs: async delayed refs
Delayed extent operations are triggered during transaction commits. The goal is to queue up a healthly batch of changes to the extent allocation tree and run through them in bulk. This farms them off to async helper threads. The goal is to have the bulk of the delayed operations being done in the background, but this is also important to limit our stack footprint. Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/ctree.h5
-rw-r--r--fs/btrfs/disk-io.c6
-rw-r--r--fs/btrfs/extent-tree.c79
-rw-r--r--fs/btrfs/inode.c1
-rw-r--r--fs/btrfs/transaction.c19
5 files changed, 107 insertions, 3 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 4896d7a947eb..02895a126ab9 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -1546,6 +1546,9 @@ struct btrfs_fs_info {
1546 */ 1546 */
1547 struct btrfs_workqueue *fixup_workers; 1547 struct btrfs_workqueue *fixup_workers;
1548 struct btrfs_workqueue *delayed_workers; 1548 struct btrfs_workqueue *delayed_workers;
1549
1550 /* the extent workers do delayed refs on the extent allocation tree */
1551 struct btrfs_workqueue *extent_workers;
1549 struct task_struct *transaction_kthread; 1552 struct task_struct *transaction_kthread;
1550 struct task_struct *cleaner_kthread; 1553 struct task_struct *cleaner_kthread;
1551 int thread_pool_size; 1554 int thread_pool_size;
@@ -3268,6 +3271,8 @@ int btrfs_check_space_for_delayed_refs(struct btrfs_trans_handle *trans,
3268void btrfs_put_block_group(struct btrfs_block_group_cache *cache); 3271void btrfs_put_block_group(struct btrfs_block_group_cache *cache);
3269int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, 3272int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
3270 struct btrfs_root *root, unsigned long count); 3273 struct btrfs_root *root, unsigned long count);
3274int btrfs_async_run_delayed_refs(struct btrfs_root *root,
3275 unsigned long count, int wait);
3271int btrfs_lookup_extent(struct btrfs_root *root, u64 start, u64 len); 3276int btrfs_lookup_extent(struct btrfs_root *root, u64 start, u64 len);
3272int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans, 3277int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans,
3273 struct btrfs_root *root, u64 bytenr, 3278 struct btrfs_root *root, u64 bytenr,
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 0c0fa78ef452..8bb4aa19898f 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -2069,6 +2069,7 @@ static void btrfs_stop_all_workers(struct btrfs_fs_info *fs_info)
2069 btrfs_destroy_workqueue(fs_info->readahead_workers); 2069 btrfs_destroy_workqueue(fs_info->readahead_workers);
2070 btrfs_destroy_workqueue(fs_info->flush_workers); 2070 btrfs_destroy_workqueue(fs_info->flush_workers);
2071 btrfs_destroy_workqueue(fs_info->qgroup_rescan_workers); 2071 btrfs_destroy_workqueue(fs_info->qgroup_rescan_workers);
2072 btrfs_destroy_workqueue(fs_info->extent_workers);
2072} 2073}
2073 2074
2074static void free_root_extent_buffers(struct btrfs_root *root) 2075static void free_root_extent_buffers(struct btrfs_root *root)
@@ -2586,6 +2587,10 @@ int open_ctree(struct super_block *sb,
2586 btrfs_alloc_workqueue("readahead", flags, max_active, 2); 2587 btrfs_alloc_workqueue("readahead", flags, max_active, 2);
2587 fs_info->qgroup_rescan_workers = 2588 fs_info->qgroup_rescan_workers =
2588 btrfs_alloc_workqueue("qgroup-rescan", flags, 1, 0); 2589 btrfs_alloc_workqueue("qgroup-rescan", flags, 1, 0);
2590 fs_info->extent_workers =
2591 btrfs_alloc_workqueue("extent-refs", flags,
2592 min_t(u64, fs_devices->num_devices,
2593 max_active), 8);
2589 2594
2590 if (!(fs_info->workers && fs_info->delalloc_workers && 2595 if (!(fs_info->workers && fs_info->delalloc_workers &&
2591 fs_info->submit_workers && fs_info->flush_workers && 2596 fs_info->submit_workers && fs_info->flush_workers &&
@@ -2595,6 +2600,7 @@ int open_ctree(struct super_block *sb,
2595 fs_info->endio_freespace_worker && fs_info->rmw_workers && 2600 fs_info->endio_freespace_worker && fs_info->rmw_workers &&
2596 fs_info->caching_workers && fs_info->readahead_workers && 2601 fs_info->caching_workers && fs_info->readahead_workers &&
2597 fs_info->fixup_workers && fs_info->delayed_workers && 2602 fs_info->fixup_workers && fs_info->delayed_workers &&
2603 fs_info->fixup_workers && fs_info->extent_workers &&
2598 fs_info->qgroup_rescan_workers)) { 2604 fs_info->qgroup_rescan_workers)) {
2599 err = -ENOMEM; 2605 err = -ENOMEM;
2600 goto fail_sb_buffer; 2606 goto fail_sb_buffer;
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index bb5b3067ddc3..6caddd5970e4 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -2674,15 +2674,94 @@ int btrfs_should_throttle_delayed_refs(struct btrfs_trans_handle *trans,
2674 u64 num_entries = 2674 u64 num_entries =
2675 atomic_read(&trans->transaction->delayed_refs.num_entries); 2675 atomic_read(&trans->transaction->delayed_refs.num_entries);
2676 u64 avg_runtime; 2676 u64 avg_runtime;
2677 u64 val;
2677 2678
2678 smp_mb(); 2679 smp_mb();
2679 avg_runtime = fs_info->avg_delayed_ref_runtime; 2680 avg_runtime = fs_info->avg_delayed_ref_runtime;
2681 val = num_entries * avg_runtime;
2680 if (num_entries * avg_runtime >= NSEC_PER_SEC) 2682 if (num_entries * avg_runtime >= NSEC_PER_SEC)
2681 return 1; 2683 return 1;
2684 if (val >= NSEC_PER_SEC / 2)
2685 return 2;
2682 2686
2683 return btrfs_check_space_for_delayed_refs(trans, root); 2687 return btrfs_check_space_for_delayed_refs(trans, root);
2684} 2688}
2685 2689
2690struct async_delayed_refs {
2691 struct btrfs_root *root;
2692 int count;
2693 int error;
2694 int sync;
2695 struct completion wait;
2696 struct btrfs_work work;
2697};
2698
2699static void delayed_ref_async_start(struct btrfs_work *work)
2700{
2701 struct async_delayed_refs *async;
2702 struct btrfs_trans_handle *trans;
2703 int ret;
2704
2705 async = container_of(work, struct async_delayed_refs, work);
2706
2707 trans = btrfs_join_transaction(async->root);
2708 if (IS_ERR(trans)) {
2709 async->error = PTR_ERR(trans);
2710 goto done;
2711 }
2712
2713 /*
2714 * trans->sync means that when we call end_transaciton, we won't
2715 * wait on delayed refs
2716 */
2717 trans->sync = true;
2718 ret = btrfs_run_delayed_refs(trans, async->root, async->count);
2719 if (ret)
2720 async->error = ret;
2721
2722 ret = btrfs_end_transaction(trans, async->root);
2723 if (ret && !async->error)
2724 async->error = ret;
2725done:
2726 if (async->sync)
2727 complete(&async->wait);
2728 else
2729 kfree(async);
2730}
2731
2732int btrfs_async_run_delayed_refs(struct btrfs_root *root,
2733 unsigned long count, int wait)
2734{
2735 struct async_delayed_refs *async;
2736 int ret;
2737
2738 async = kmalloc(sizeof(*async), GFP_NOFS);
2739 if (!async)
2740 return -ENOMEM;
2741
2742 async->root = root->fs_info->tree_root;
2743 async->count = count;
2744 async->error = 0;
2745 if (wait)
2746 async->sync = 1;
2747 else
2748 async->sync = 0;
2749 init_completion(&async->wait);
2750
2751 btrfs_init_work(&async->work, delayed_ref_async_start,
2752 NULL, NULL);
2753
2754 btrfs_queue_work(root->fs_info->extent_workers, &async->work);
2755
2756 if (wait) {
2757 wait_for_completion(&async->wait);
2758 ret = async->error;
2759 kfree(async);
2760 return ret;
2761 }
2762 return 0;
2763}
2764
2686/* 2765/*
2687 * this starts processing the delayed reference count updates and 2766 * this starts processing the delayed reference count updates and
2688 * extent insertions we have queued up so far. count can be 2767 * extent insertions we have queued up so far. count can be
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 992aae6c00b0..38d1e7b976d8 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -2678,6 +2678,7 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent)
2678 trans = NULL; 2678 trans = NULL;
2679 goto out_unlock; 2679 goto out_unlock;
2680 } 2680 }
2681
2681 trans->block_rsv = &root->fs_info->delalloc_block_rsv; 2682 trans->block_rsv = &root->fs_info->delalloc_block_rsv;
2682 2683
2683 if (test_bit(BTRFS_ORDERED_COMPRESSED, &ordered_extent->flags)) 2684 if (test_bit(BTRFS_ORDERED_COMPRESSED, &ordered_extent->flags))
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 3aafbde8b637..1c54e2eb74ab 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -697,6 +697,7 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
697 unsigned long cur = trans->delayed_ref_updates; 697 unsigned long cur = trans->delayed_ref_updates;
698 int lock = (trans->type != TRANS_JOIN_NOLOCK); 698 int lock = (trans->type != TRANS_JOIN_NOLOCK);
699 int err = 0; 699 int err = 0;
700 int must_run_delayed_refs = 0;
700 701
701 if (trans->use_count > 1) { 702 if (trans->use_count > 1) {
702 trans->use_count--; 703 trans->use_count--;
@@ -711,10 +712,18 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
711 btrfs_create_pending_block_groups(trans, root); 712 btrfs_create_pending_block_groups(trans, root);
712 713
713 trans->delayed_ref_updates = 0; 714 trans->delayed_ref_updates = 0;
714 if (!trans->sync && btrfs_should_throttle_delayed_refs(trans, root)) { 715 if (!trans->sync) {
716 must_run_delayed_refs =
717 btrfs_should_throttle_delayed_refs(trans, root);
715 cur = max_t(unsigned long, cur, 32); 718 cur = max_t(unsigned long, cur, 32);
716 trans->delayed_ref_updates = 0; 719
717 btrfs_run_delayed_refs(trans, root, cur); 720 /*
721 * don't make the caller wait if they are from a NOLOCK
722 * or ATTACH transaction, it will deadlock with commit
723 */
724 if (must_run_delayed_refs == 1 &&
725 (trans->type & (__TRANS_JOIN_NOLOCK | __TRANS_ATTACH)))
726 must_run_delayed_refs = 2;
718 } 727 }
719 728
720 if (trans->qgroup_reserved) { 729 if (trans->qgroup_reserved) {
@@ -775,6 +784,10 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
775 assert_qgroups_uptodate(trans); 784 assert_qgroups_uptodate(trans);
776 785
777 kmem_cache_free(btrfs_trans_handle_cachep, trans); 786 kmem_cache_free(btrfs_trans_handle_cachep, trans);
787 if (must_run_delayed_refs) {
788 btrfs_async_run_delayed_refs(root, cur,
789 must_run_delayed_refs == 1);
790 }
778 return err; 791 return err;
779} 792}
780 793