aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Mason <clm@fb.com>2016-04-27 09:59:38 -0400
committerChris Mason <clm@fb.com>2016-06-22 20:54:18 -0400
commit0f873eca82a0bee45f38862e0ea2ac7b1c2a31bd (patch)
tree75b28a6c1e173e4a36e63d90b2e6122699158d01
parent31b9655f439a26856edca0f3f8daa368a61f16d5 (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.c20
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 2877end:
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;