aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/transaction.c
diff options
context:
space:
mode:
authorJosef Bacik <josef@redhat.com>2011-06-14 16:22:15 -0400
committerJosef Bacik <josef@redhat.com>2011-06-15 13:24:47 -0400
commited0ca14021e5ae3147602128641aa7f742ab227c (patch)
tree22f9a66f0f99770edb483963ff308982424f2e53 /fs/btrfs/transaction.c
parent8351583e3f6e430ce8f71913909a96ad5cc6a2f6 (diff)
Btrfs: set no_trans_join after trying to expand the transaction
We can lockup if we try to allow new writers join the transaction and we have flushoncommit set or have a pending snapshot. This is because we set no_trans_join and then loop around and try to wait for ordered extents again. The problem is the ordered endio stuff needs to join the transaction, which it can't do because no_trans_join is set. So instead wait until after this loop to set no_trans_join and then make sure to wait for num_writers == 1 in case anybody got started in between us exiting the loop and setting no_trans_join. This could easily be reproduced by mounting -o flushoncommit and running xfstest 13. It cannot be reproduced with this patch. Thanks, Reported-by: Jim Schutt <jaschut@sandia.gov> Signed-off-by: Josef Bacik <josef@redhat.com>
Diffstat (limited to 'fs/btrfs/transaction.c')
-rw-r--r--fs/btrfs/transaction.c14
1 files changed, 11 insertions, 3 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 2b3590b9fe98..56695595e036 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -1241,12 +1241,20 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
1241 schedule_timeout(1); 1241 schedule_timeout(1);
1242 1242
1243 finish_wait(&cur_trans->writer_wait, &wait); 1243 finish_wait(&cur_trans->writer_wait, &wait);
1244 spin_lock(&root->fs_info->trans_lock);
1245 root->fs_info->trans_no_join = 1;
1246 spin_unlock(&root->fs_info->trans_lock);
1247 } while (atomic_read(&cur_trans->num_writers) > 1 || 1244 } while (atomic_read(&cur_trans->num_writers) > 1 ||
1248 (should_grow && cur_trans->num_joined != joined)); 1245 (should_grow && cur_trans->num_joined != joined));
1249 1246
1247 /*
1248 * Ok now we need to make sure to block out any other joins while we
1249 * commit the transaction. We could have started a join before setting
1250 * no_join so make sure to wait for num_writers to == 1 again.
1251 */
1252 spin_lock(&root->fs_info->trans_lock);
1253 root->fs_info->trans_no_join = 1;
1254 spin_unlock(&root->fs_info->trans_lock);
1255 wait_event(cur_trans->writer_wait,
1256 atomic_read(&cur_trans->num_writers) == 1);
1257
1250 ret = create_pending_snapshots(trans, root->fs_info); 1258 ret = create_pending_snapshots(trans, root->fs_info);
1251 BUG_ON(ret); 1259 BUG_ON(ret);
1252 1260