aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/disk-io.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/disk-io.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/disk-io.c')
-rw-r--r--fs/btrfs/disk-io.c111
1 files changed, 40 insertions, 71 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 01a26e2eb310..b131d716d5a5 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -64,7 +64,6 @@ static void btrfs_destroy_ordered_operations(struct btrfs_transaction *t,
64static void btrfs_destroy_ordered_extents(struct btrfs_root *root); 64static void btrfs_destroy_ordered_extents(struct btrfs_root *root);
65static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans, 65static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
66 struct btrfs_root *root); 66 struct btrfs_root *root);
67static void btrfs_evict_pending_snapshots(struct btrfs_transaction *t);
68static void btrfs_destroy_delalloc_inodes(struct btrfs_root *root); 67static void btrfs_destroy_delalloc_inodes(struct btrfs_root *root);
69static int btrfs_destroy_marked_extents(struct btrfs_root *root, 68static int btrfs_destroy_marked_extents(struct btrfs_root *root,
70 struct extent_io_tree *dirty_pages, 69 struct extent_io_tree *dirty_pages,
@@ -3915,24 +3914,6 @@ static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
3915 return ret; 3914 return ret;
3916} 3915}
3917 3916
3918static void btrfs_evict_pending_snapshots(struct btrfs_transaction *t)
3919{
3920 struct btrfs_pending_snapshot *snapshot;
3921 struct list_head splice;
3922
3923 INIT_LIST_HEAD(&splice);
3924
3925 list_splice_init(&t->pending_snapshots, &splice);
3926
3927 while (!list_empty(&splice)) {
3928 snapshot = list_entry(splice.next,
3929 struct btrfs_pending_snapshot,
3930 list);
3931 snapshot->error = -ECANCELED;
3932 list_del_init(&snapshot->list);
3933 }
3934}
3935
3936static void btrfs_destroy_delalloc_inodes(struct btrfs_root *root) 3917static void btrfs_destroy_delalloc_inodes(struct btrfs_root *root)
3937{ 3918{
3938 struct btrfs_inode *btrfs_inode; 3919 struct btrfs_inode *btrfs_inode;
@@ -4062,6 +4043,8 @@ again:
4062void btrfs_cleanup_one_transaction(struct btrfs_transaction *cur_trans, 4043void btrfs_cleanup_one_transaction(struct btrfs_transaction *cur_trans,
4063 struct btrfs_root *root) 4044 struct btrfs_root *root)
4064{ 4045{
4046 btrfs_destroy_ordered_operations(cur_trans, root);
4047
4065 btrfs_destroy_delayed_refs(cur_trans, root); 4048 btrfs_destroy_delayed_refs(cur_trans, root);
4066 btrfs_block_rsv_release(root, &root->fs_info->trans_block_rsv, 4049 btrfs_block_rsv_release(root, &root->fs_info->trans_block_rsv,
4067 cur_trans->dirty_pages.dirty_bytes); 4050 cur_trans->dirty_pages.dirty_bytes);
@@ -4069,8 +4052,6 @@ void btrfs_cleanup_one_transaction(struct btrfs_transaction *cur_trans,
4069 cur_trans->state = TRANS_STATE_COMMIT_START; 4052 cur_trans->state = TRANS_STATE_COMMIT_START;
4070 wake_up(&root->fs_info->transaction_blocked_wait); 4053 wake_up(&root->fs_info->transaction_blocked_wait);
4071 4054
4072 btrfs_evict_pending_snapshots(cur_trans);
4073
4074 cur_trans->state = TRANS_STATE_UNBLOCKED; 4055 cur_trans->state = TRANS_STATE_UNBLOCKED;
4075 wake_up(&root->fs_info->transaction_wait); 4056 wake_up(&root->fs_info->transaction_wait);
4076 4057
@@ -4094,63 +4075,51 @@ void btrfs_cleanup_one_transaction(struct btrfs_transaction *cur_trans,
4094static int btrfs_cleanup_transaction(struct btrfs_root *root) 4075static int btrfs_cleanup_transaction(struct btrfs_root *root)
4095{ 4076{
4096 struct btrfs_transaction *t; 4077 struct btrfs_transaction *t;
4097 LIST_HEAD(list);
4098 4078
4099 mutex_lock(&root->fs_info->transaction_kthread_mutex); 4079 mutex_lock(&root->fs_info->transaction_kthread_mutex);
4100 4080
4101 spin_lock(&root->fs_info->trans_lock); 4081 spin_lock(&root->fs_info->trans_lock);
4102 list_splice_init(&root->fs_info->trans_list, &list); 4082 while (!list_empty(&root->fs_info->trans_list)) {
4103 root->fs_info->running_transaction = NULL; 4083 t = list_first_entry(&root->fs_info->trans_list,
4104 spin_unlock(&root->fs_info->trans_lock); 4084 struct btrfs_transaction, list);
4105 4085 if (t->state >= TRANS_STATE_COMMIT_START) {
4106 while (!list_empty(&list)) { 4086 atomic_inc(&t->use_count);
4107 t = list_entry(list.next, struct btrfs_transaction, list); 4087 spin_unlock(&root->fs_info->trans_lock);
4108 4088 btrfs_wait_for_commit(root, t->transid);
4109 btrfs_destroy_ordered_operations(t, root); 4089 btrfs_put_transaction(t);
4110 4090 spin_lock(&root->fs_info->trans_lock);
4111 btrfs_destroy_all_ordered_extents(root->fs_info); 4091 continue;
4112 4092 }
4113 btrfs_destroy_delayed_refs(t, root); 4093 if (t == root->fs_info->running_transaction) {
4114 4094 t->state = TRANS_STATE_COMMIT_DOING;
4115 /* 4095 spin_unlock(&root->fs_info->trans_lock);
4116 * FIXME: cleanup wait for commit 4096 /*
4117 * We needn't acquire the lock here, because we are during 4097 * We wait for 0 num_writers since we don't hold a trans
4118 * the umount, there is no other task which will change it. 4098 * handle open currently for this transaction.
4119 */ 4099 */
4120 t->state = TRANS_STATE_COMMIT_START; 4100 wait_event(t->writer_wait,
4121 smp_mb(); 4101 atomic_read(&t->num_writers) == 0);
4122 if (waitqueue_active(&root->fs_info->transaction_blocked_wait)) 4102 } else {
4123 wake_up(&root->fs_info->transaction_blocked_wait); 4103 spin_unlock(&root->fs_info->trans_lock);
4124 4104 }
4125 btrfs_evict_pending_snapshots(t); 4105 btrfs_cleanup_one_transaction(t, root);
4126
4127 t->state = TRANS_STATE_UNBLOCKED;
4128 smp_mb();
4129 if (waitqueue_active(&root->fs_info->transaction_wait))
4130 wake_up(&root->fs_info->transaction_wait);
4131
4132 btrfs_destroy_delayed_inodes(root);
4133 btrfs_assert_delayed_root_empty(root);
4134
4135 btrfs_destroy_all_delalloc_inodes(root->fs_info);
4136
4137 btrfs_destroy_marked_extents(root, &t->dirty_pages,
4138 EXTENT_DIRTY);
4139
4140 btrfs_destroy_pinned_extent(root,
4141 root->fs_info->pinned_extents);
4142
4143 t->state = TRANS_STATE_COMPLETED;
4144 smp_mb();
4145 if (waitqueue_active(&t->commit_wait))
4146 wake_up(&t->commit_wait);
4147 4106
4148 atomic_set(&t->use_count, 0); 4107 spin_lock(&root->fs_info->trans_lock);
4108 if (t == root->fs_info->running_transaction)
4109 root->fs_info->running_transaction = NULL;
4149 list_del_init(&t->list); 4110 list_del_init(&t->list);
4150 memset(t, 0, sizeof(*t)); 4111 spin_unlock(&root->fs_info->trans_lock);
4151 kmem_cache_free(btrfs_transaction_cachep, t);
4152 }
4153 4112
4113 btrfs_put_transaction(t);
4114 trace_btrfs_transaction_commit(root);
4115 spin_lock(&root->fs_info->trans_lock);
4116 }
4117 spin_unlock(&root->fs_info->trans_lock);
4118 btrfs_destroy_all_ordered_extents(root->fs_info);
4119 btrfs_destroy_delayed_inodes(root);
4120 btrfs_assert_delayed_root_empty(root);
4121 btrfs_destroy_pinned_extent(root, root->fs_info->pinned_extents);
4122 btrfs_destroy_all_delalloc_inodes(root->fs_info);
4154 mutex_unlock(&root->fs_info->transaction_kthread_mutex); 4123 mutex_unlock(&root->fs_info->transaction_kthread_mutex);
4155 4124
4156 return 0; 4125 return 0;