aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/transaction.c
diff options
context:
space:
mode:
authorJosef Bacik <jbacik@fusionio.com>2013-09-30 11:36:38 -0400
committerChris Mason <chris.mason@fusionio.com>2013-11-11 21:54:03 -0500
commit724e2315db3d59a8201d4a87c7c7a873e60e1ce0 (patch)
tree0a1af5a08bfd4312ad169ed4c1ac9a8e804b3419 /fs/btrfs/transaction.c
parentc16ce1901431629fbe5b9387cc966d62a089e4df (diff)
Btrfs: fix two use-after-free bugs with transaction cleanup
I was noticing the slab redzone stuff going off every once and a while during transaction aborts. This was caused by two things 1) We would walk the pending snapshots and set their error to -ECANCELED. We don't need to do this, the snapshot stuff waits for a transaction commit and if there is a problem we just free our pending snapshot object and exit. Doing this was causing us to touch the pending snapshot object after the thing had already been freed. 2) We were freeing the transaction manually with wanton disregard for it's use_count reference counter. To fix this I cleaned up the transaction freeing loop to either wait for the transaction commit to finish if it was in the middle of that (since it will be cleaned and freed up there) or to do the cleanup oursevles. I also moved the global "kill all things dirty everywhere" stuff outside of the transaction cleanup loop since that only needs to be done once. With this patch I'm no longer seeing slab corruption because of use after frees. Thanks, Signed-off-by: Josef Bacik <jbacik@fusionio.com> Signed-off-by: Chris Mason <chris.mason@fusionio.com>
Diffstat (limited to 'fs/btrfs/transaction.c')
-rw-r--r--fs/btrfs/transaction.c22
1 files changed, 11 insertions, 11 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index f08e22885c21..134039fd59bb 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -57,7 +57,7 @@ static unsigned int btrfs_blocked_trans_types[TRANS_STATE_MAX] = {
57 __TRANS_JOIN_NOLOCK), 57 __TRANS_JOIN_NOLOCK),
58}; 58};
59 59
60static void put_transaction(struct btrfs_transaction *transaction) 60void btrfs_put_transaction(struct btrfs_transaction *transaction)
61{ 61{
62 WARN_ON(atomic_read(&transaction->use_count) == 0); 62 WARN_ON(atomic_read(&transaction->use_count) == 0);
63 if (atomic_dec_and_test(&transaction->use_count)) { 63 if (atomic_dec_and_test(&transaction->use_count)) {
@@ -332,7 +332,7 @@ static void wait_current_trans(struct btrfs_root *root)
332 wait_event(root->fs_info->transaction_wait, 332 wait_event(root->fs_info->transaction_wait,
333 cur_trans->state >= TRANS_STATE_UNBLOCKED || 333 cur_trans->state >= TRANS_STATE_UNBLOCKED ||
334 cur_trans->aborted); 334 cur_trans->aborted);
335 put_transaction(cur_trans); 335 btrfs_put_transaction(cur_trans);
336 } else { 336 } else {
337 spin_unlock(&root->fs_info->trans_lock); 337 spin_unlock(&root->fs_info->trans_lock);
338 } 338 }
@@ -610,7 +610,7 @@ int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid)
610 } 610 }
611 611
612 wait_for_commit(root, cur_trans); 612 wait_for_commit(root, cur_trans);
613 put_transaction(cur_trans); 613 btrfs_put_transaction(cur_trans);
614out: 614out:
615 return ret; 615 return ret;
616} 616}
@@ -735,7 +735,7 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
735 smp_mb(); 735 smp_mb();
736 if (waitqueue_active(&cur_trans->writer_wait)) 736 if (waitqueue_active(&cur_trans->writer_wait))
737 wake_up(&cur_trans->writer_wait); 737 wake_up(&cur_trans->writer_wait);
738 put_transaction(cur_trans); 738 btrfs_put_transaction(cur_trans);
739 739
740 if (current->journal_info == trans) 740 if (current->journal_info == trans)
741 current->journal_info = NULL; 741 current->journal_info = NULL;
@@ -1515,7 +1515,7 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans,
1515 if (current->journal_info == trans) 1515 if (current->journal_info == trans)
1516 current->journal_info = NULL; 1516 current->journal_info = NULL;
1517 1517
1518 put_transaction(cur_trans); 1518 btrfs_put_transaction(cur_trans);
1519 return 0; 1519 return 0;
1520} 1520}
1521 1521
@@ -1559,8 +1559,8 @@ static void cleanup_transaction(struct btrfs_trans_handle *trans,
1559 1559
1560 if (trans->type & __TRANS_FREEZABLE) 1560 if (trans->type & __TRANS_FREEZABLE)
1561 sb_end_intwrite(root->fs_info->sb); 1561 sb_end_intwrite(root->fs_info->sb);
1562 put_transaction(cur_trans); 1562 btrfs_put_transaction(cur_trans);
1563 put_transaction(cur_trans); 1563 btrfs_put_transaction(cur_trans);
1564 1564
1565 trace_btrfs_transaction_commit(root); 1565 trace_btrfs_transaction_commit(root);
1566 1566
@@ -1676,7 +1676,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
1676 1676
1677 wait_for_commit(root, cur_trans); 1677 wait_for_commit(root, cur_trans);
1678 1678
1679 put_transaction(cur_trans); 1679 btrfs_put_transaction(cur_trans);
1680 1680
1681 return ret; 1681 return ret;
1682 } 1682 }
@@ -1693,7 +1693,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
1693 1693
1694 wait_for_commit(root, prev_trans); 1694 wait_for_commit(root, prev_trans);
1695 1695
1696 put_transaction(prev_trans); 1696 btrfs_put_transaction(prev_trans);
1697 } else { 1697 } else {
1698 spin_unlock(&root->fs_info->trans_lock); 1698 spin_unlock(&root->fs_info->trans_lock);
1699 } 1699 }
@@ -1892,8 +1892,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
1892 list_del_init(&cur_trans->list); 1892 list_del_init(&cur_trans->list);
1893 spin_unlock(&root->fs_info->trans_lock); 1893 spin_unlock(&root->fs_info->trans_lock);
1894 1894
1895 put_transaction(cur_trans); 1895 btrfs_put_transaction(cur_trans);
1896 put_transaction(cur_trans); 1896 btrfs_put_transaction(cur_trans);
1897 1897
1898 if (trans->type & __TRANS_FREEZABLE) 1898 if (trans->type & __TRANS_FREEZABLE)
1899 sb_end_intwrite(root->fs_info->sb); 1899 sb_end_intwrite(root->fs_info->sb);