diff options
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r-- | fs/btrfs/extent-tree.c | 79 |
1 files changed, 79 insertions, 0 deletions
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 | ||
2690 | struct 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 | |||
2699 | static 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; | ||
2725 | done: | ||
2726 | if (async->sync) | ||
2727 | complete(&async->wait); | ||
2728 | else | ||
2729 | kfree(async); | ||
2730 | } | ||
2731 | |||
2732 | int 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 |