diff options
| author | Chris Mason <clm@fb.com> | 2016-04-27 09:59:38 -0400 |
|---|---|---|
| committer | Chris Mason <clm@fb.com> | 2016-06-22 20:54:18 -0400 |
| commit | 0f873eca82a0bee45f38862e0ea2ac7b1c2a31bd (patch) | |
| tree | 75b28a6c1e173e4a36e63d90b2e6122699158d01 | |
| parent | 31b9655f439a26856edca0f3f8daa368a61f16d5 (diff) | |
btrfs: fix deadlock in delayed_ref_async_start
"Btrfs: track transid for delayed ref flushing" was deadlocking on
btrfs_attach_transaction because its not safe to call from the async
delayed ref start code. This commit brings back btrfs_join_transaction
instead and checks for a blocked commit.
Signed-off-by: Josef Bacik <jbacik@fb.com>
Signed-off-by: Chris Mason <clm@fb.com>
| -rw-r--r-- | fs/btrfs/extent-tree.c | 20 |
1 files changed, 11 insertions, 9 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index ecfa52002363..82b912a293ab 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
| @@ -2851,16 +2851,13 @@ static void delayed_ref_async_start(struct btrfs_work *work) | |||
| 2851 | 2851 | ||
| 2852 | async = container_of(work, struct async_delayed_refs, work); | 2852 | async = container_of(work, struct async_delayed_refs, work); |
| 2853 | 2853 | ||
| 2854 | trans = btrfs_attach_transaction(async->root); | 2854 | /* if the commit is already started, we don't need to wait here */ |
| 2855 | if (IS_ERR(trans)) { | 2855 | if (btrfs_transaction_blocked(async->root->fs_info)) |
| 2856 | if (PTR_ERR(trans) != -ENOENT) | ||
| 2857 | async->error = PTR_ERR(trans); | ||
| 2858 | goto done; | 2856 | goto done; |
| 2859 | } | ||
| 2860 | 2857 | ||
| 2861 | /* Don't bother flushing if we got into a different transaction */ | 2858 | trans = btrfs_join_transaction(async->root); |
| 2862 | if (trans->transid != async->transid) { | 2859 | if (IS_ERR(trans)) { |
| 2863 | btrfs_end_transaction(trans, async->root); | 2860 | async->error = PTR_ERR(trans); |
| 2864 | goto done; | 2861 | goto done; |
| 2865 | } | 2862 | } |
| 2866 | 2863 | ||
| @@ -2869,10 +2866,15 @@ static void delayed_ref_async_start(struct btrfs_work *work) | |||
| 2869 | * wait on delayed refs | 2866 | * wait on delayed refs |
| 2870 | */ | 2867 | */ |
| 2871 | 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 | |||
| 2872 | ret = btrfs_run_delayed_refs(trans, async->root, async->count); | 2874 | ret = btrfs_run_delayed_refs(trans, async->root, async->count); |
| 2873 | if (ret) | 2875 | if (ret) |
| 2874 | async->error = ret; | 2876 | async->error = ret; |
| 2875 | 2877 | end: | |
| 2876 | ret = btrfs_end_transaction(trans, async->root); | 2878 | ret = btrfs_end_transaction(trans, async->root); |
| 2877 | if (ret && !async->error) | 2879 | if (ret && !async->error) |
| 2878 | async->error = ret; | 2880 | async->error = ret; |
