diff options
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r-- | fs/btrfs/extent-tree.c | 27 |
1 files changed, 20 insertions, 7 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 689d25ac6a68..82b912a293ab 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -2835,6 +2835,7 @@ int btrfs_should_throttle_delayed_refs(struct btrfs_trans_handle *trans, | |||
2835 | 2835 | ||
2836 | struct async_delayed_refs { | 2836 | struct async_delayed_refs { |
2837 | struct btrfs_root *root; | 2837 | struct btrfs_root *root; |
2838 | u64 transid; | ||
2838 | int count; | 2839 | int count; |
2839 | int error; | 2840 | int error; |
2840 | int sync; | 2841 | int sync; |
@@ -2850,6 +2851,10 @@ static void delayed_ref_async_start(struct btrfs_work *work) | |||
2850 | 2851 | ||
2851 | async = container_of(work, struct async_delayed_refs, work); | 2852 | async = container_of(work, struct async_delayed_refs, work); |
2852 | 2853 | ||
2854 | /* if the commit is already started, we don't need to wait here */ | ||
2855 | if (btrfs_transaction_blocked(async->root->fs_info)) | ||
2856 | goto done; | ||
2857 | |||
2853 | trans = btrfs_join_transaction(async->root); | 2858 | trans = btrfs_join_transaction(async->root); |
2854 | if (IS_ERR(trans)) { | 2859 | if (IS_ERR(trans)) { |
2855 | async->error = PTR_ERR(trans); | 2860 | async->error = PTR_ERR(trans); |
@@ -2861,10 +2866,15 @@ static void delayed_ref_async_start(struct btrfs_work *work) | |||
2861 | * wait on delayed refs | 2866 | * wait on delayed refs |
2862 | */ | 2867 | */ |
2863 | trans->sync = true; | 2868 | trans->sync = true; |
2869 | |||
2870 | /* Don't bother flushing if we got into a different transaction */ | ||
2871 | if (trans->transid > async->transid) | ||
2872 | goto end; | ||
2873 | |||
2864 | ret = btrfs_run_delayed_refs(trans, async->root, async->count); | 2874 | ret = btrfs_run_delayed_refs(trans, async->root, async->count); |
2865 | if (ret) | 2875 | if (ret) |
2866 | async->error = ret; | 2876 | async->error = ret; |
2867 | 2877 | end: | |
2868 | ret = btrfs_end_transaction(trans, async->root); | 2878 | ret = btrfs_end_transaction(trans, async->root); |
2869 | if (ret && !async->error) | 2879 | if (ret && !async->error) |
2870 | async->error = ret; | 2880 | async->error = ret; |
@@ -2876,7 +2886,7 @@ done: | |||
2876 | } | 2886 | } |
2877 | 2887 | ||
2878 | int btrfs_async_run_delayed_refs(struct btrfs_root *root, | 2888 | int btrfs_async_run_delayed_refs(struct btrfs_root *root, |
2879 | unsigned long count, int wait) | 2889 | unsigned long count, u64 transid, int wait) |
2880 | { | 2890 | { |
2881 | struct async_delayed_refs *async; | 2891 | struct async_delayed_refs *async; |
2882 | int ret; | 2892 | int ret; |
@@ -2888,6 +2898,7 @@ int btrfs_async_run_delayed_refs(struct btrfs_root *root, | |||
2888 | async->root = root->fs_info->tree_root; | 2898 | async->root = root->fs_info->tree_root; |
2889 | async->count = count; | 2899 | async->count = count; |
2890 | async->error = 0; | 2900 | async->error = 0; |
2901 | async->transid = transid; | ||
2891 | if (wait) | 2902 | if (wait) |
2892 | async->sync = 1; | 2903 | async->sync = 1; |
2893 | else | 2904 | else |
@@ -8016,8 +8027,9 @@ btrfs_init_new_buffer(struct btrfs_trans_handle *trans, struct btrfs_root *root, | |||
8016 | struct extent_buffer *buf; | 8027 | struct extent_buffer *buf; |
8017 | 8028 | ||
8018 | buf = btrfs_find_create_tree_block(root, bytenr); | 8029 | buf = btrfs_find_create_tree_block(root, bytenr); |
8019 | if (!buf) | 8030 | if (IS_ERR(buf)) |
8020 | return ERR_PTR(-ENOMEM); | 8031 | return buf; |
8032 | |||
8021 | btrfs_set_header_generation(buf, trans->transid); | 8033 | btrfs_set_header_generation(buf, trans->transid); |
8022 | btrfs_set_buffer_lockdep_class(root->root_key.objectid, buf, level); | 8034 | btrfs_set_buffer_lockdep_class(root->root_key.objectid, buf, level); |
8023 | btrfs_tree_lock(buf); | 8035 | btrfs_tree_lock(buf); |
@@ -8044,7 +8056,7 @@ btrfs_init_new_buffer(struct btrfs_trans_handle *trans, struct btrfs_root *root, | |||
8044 | set_extent_dirty(&trans->transaction->dirty_pages, buf->start, | 8056 | set_extent_dirty(&trans->transaction->dirty_pages, buf->start, |
8045 | buf->start + buf->len - 1, GFP_NOFS); | 8057 | buf->start + buf->len - 1, GFP_NOFS); |
8046 | } | 8058 | } |
8047 | trans->blocks_used++; | 8059 | trans->dirty = true; |
8048 | /* this returns a buffer locked for blocking */ | 8060 | /* this returns a buffer locked for blocking */ |
8049 | return buf; | 8061 | return buf; |
8050 | } | 8062 | } |
@@ -8659,8 +8671,9 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans, | |||
8659 | next = btrfs_find_tree_block(root->fs_info, bytenr); | 8671 | next = btrfs_find_tree_block(root->fs_info, bytenr); |
8660 | if (!next) { | 8672 | if (!next) { |
8661 | next = btrfs_find_create_tree_block(root, bytenr); | 8673 | next = btrfs_find_create_tree_block(root, bytenr); |
8662 | if (!next) | 8674 | if (IS_ERR(next)) |
8663 | return -ENOMEM; | 8675 | return PTR_ERR(next); |
8676 | |||
8664 | btrfs_set_buffer_lockdep_class(root->root_key.objectid, next, | 8677 | btrfs_set_buffer_lockdep_class(root->root_key.objectid, next, |
8665 | level - 1); | 8678 | level - 1); |
8666 | reada = 1; | 8679 | reada = 1; |