diff options
author | Josef Bacik <jbacik@fusionio.com> | 2013-02-06 16:55:41 -0500 |
---|---|---|
committer | Josef Bacik <jbacik@fusionio.com> | 2013-02-20 12:59:35 -0500 |
commit | e4a2bcaca9643e7430207810653222fc5187f2be (patch) | |
tree | 204d6af57fbf70525359f5a2aa717a4785b89cd5 | |
parent | 3e04e7f10b68999e0d8321516ea19d9d5b044dee (diff) |
Btrfs: if we aren't committing just end the transaction if we error out
I hit a deadlock where transaction commit was waiting on num_writers to be
0. This happened because somebody came into btrfs_commit_transaction and
noticed we had aborted and it went to cleanup_transaction. This shouldn't
happen because cleanup_transaction is really to fixup a bad commit, it
doesn't do the normal trans handle cleanup things. So if we have an error
just do the normal btrfs_end_transaction dance and return. Once we are in
the actual commit path we can use cleanup_transaction and be good to go.
Thanks,
Signed-off-by: Josef Bacik <jbacik@fusionio.com>
-rw-r--r-- | fs/btrfs/transaction.c | 18 |
1 files changed, 12 insertions, 6 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index baf6d74fd0f2..5144ad19ef47 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -1476,21 +1476,25 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1476 | ret = btrfs_run_ordered_operations(root, 0); | 1476 | ret = btrfs_run_ordered_operations(root, 0); |
1477 | if (ret) { | 1477 | if (ret) { |
1478 | btrfs_abort_transaction(trans, root, ret); | 1478 | btrfs_abort_transaction(trans, root, ret); |
1479 | goto cleanup_transaction; | 1479 | btrfs_end_transaction(trans, root); |
1480 | return ret; | ||
1480 | } | 1481 | } |
1481 | 1482 | ||
1482 | /* Stop the commit early if ->aborted is set */ | 1483 | /* Stop the commit early if ->aborted is set */ |
1483 | if (unlikely(ACCESS_ONCE(cur_trans->aborted))) { | 1484 | if (unlikely(ACCESS_ONCE(cur_trans->aborted))) { |
1484 | ret = cur_trans->aborted; | 1485 | ret = cur_trans->aborted; |
1485 | goto cleanup_transaction; | 1486 | btrfs_end_transaction(trans, root); |
1487 | return ret; | ||
1486 | } | 1488 | } |
1487 | 1489 | ||
1488 | /* make a pass through all the delayed refs we have so far | 1490 | /* make a pass through all the delayed refs we have so far |
1489 | * any runnings procs may add more while we are here | 1491 | * any runnings procs may add more while we are here |
1490 | */ | 1492 | */ |
1491 | ret = btrfs_run_delayed_refs(trans, root, 0); | 1493 | ret = btrfs_run_delayed_refs(trans, root, 0); |
1492 | if (ret) | 1494 | if (ret) { |
1493 | goto cleanup_transaction; | 1495 | btrfs_end_transaction(trans, root); |
1496 | return ret; | ||
1497 | } | ||
1494 | 1498 | ||
1495 | btrfs_trans_release_metadata(trans, root); | 1499 | btrfs_trans_release_metadata(trans, root); |
1496 | trans->block_rsv = NULL; | 1500 | trans->block_rsv = NULL; |
@@ -1507,8 +1511,10 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1507 | btrfs_create_pending_block_groups(trans, root); | 1511 | btrfs_create_pending_block_groups(trans, root); |
1508 | 1512 | ||
1509 | ret = btrfs_run_delayed_refs(trans, root, 0); | 1513 | ret = btrfs_run_delayed_refs(trans, root, 0); |
1510 | if (ret) | 1514 | if (ret) { |
1511 | goto cleanup_transaction; | 1515 | btrfs_end_transaction(trans, root); |
1516 | return ret; | ||
1517 | } | ||
1512 | 1518 | ||
1513 | spin_lock(&cur_trans->commit_lock); | 1519 | spin_lock(&cur_trans->commit_lock); |
1514 | if (cur_trans->in_commit) { | 1520 | if (cur_trans->in_commit) { |