diff options
author | Jeff Mahoney <jeffm@suse.com> | 2012-03-01 11:24:58 -0500 |
---|---|---|
committer | David Sterba <dsterba@suse.cz> | 2012-03-21 20:45:40 -0400 |
commit | 49b25e0540904be0bf558b84475c69d72e4de66e (patch) | |
tree | 5a89b2f5d6e5bd8b1ff39bdb387071ec1cb2a615 /fs | |
parent | 4da35113426d16673aa1fb0613c14ca2e419e7fd (diff) |
btrfs: enhance transaction abort infrastructure
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/ctree.h | 13 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 50 | ||||
-rw-r--r-- | fs/btrfs/disk-io.h | 4 | ||||
-rw-r--r-- | fs/btrfs/relocation.c | 14 | ||||
-rw-r--r-- | fs/btrfs/scrub.c | 8 | ||||
-rw-r--r-- | fs/btrfs/super.c | 74 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 190 | ||||
-rw-r--r-- | fs/btrfs/transaction.h | 3 |
8 files changed, 300 insertions, 56 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 8829f8099851..b6ebea5582c6 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -2968,6 +2968,16 @@ void btrfs_printk(struct btrfs_fs_info *fs_info, const char *fmt, ...); | |||
2968 | void __btrfs_std_error(struct btrfs_fs_info *fs_info, const char *function, | 2968 | void __btrfs_std_error(struct btrfs_fs_info *fs_info, const char *function, |
2969 | unsigned int line, int errno, const char *fmt, ...); | 2969 | unsigned int line, int errno, const char *fmt, ...); |
2970 | 2970 | ||
2971 | void __btrfs_abort_transaction(struct btrfs_trans_handle *trans, | ||
2972 | struct btrfs_root *root, const char *function, | ||
2973 | unsigned int line, int errno); | ||
2974 | |||
2975 | #define btrfs_abort_transaction(trans, root, errno) \ | ||
2976 | do { \ | ||
2977 | __btrfs_abort_transaction(trans, root, __func__, \ | ||
2978 | __LINE__, errno); \ | ||
2979 | } while (0) | ||
2980 | |||
2971 | #define btrfs_std_error(fs_info, errno) \ | 2981 | #define btrfs_std_error(fs_info, errno) \ |
2972 | do { \ | 2982 | do { \ |
2973 | if ((errno)) \ | 2983 | if ((errno)) \ |
@@ -3024,7 +3034,7 @@ void btrfs_reloc_cow_block(struct btrfs_trans_handle *trans, | |||
3024 | void btrfs_reloc_pre_snapshot(struct btrfs_trans_handle *trans, | 3034 | void btrfs_reloc_pre_snapshot(struct btrfs_trans_handle *trans, |
3025 | struct btrfs_pending_snapshot *pending, | 3035 | struct btrfs_pending_snapshot *pending, |
3026 | u64 *bytes_to_reserve); | 3036 | u64 *bytes_to_reserve); |
3027 | void btrfs_reloc_post_snapshot(struct btrfs_trans_handle *trans, | 3037 | int btrfs_reloc_post_snapshot(struct btrfs_trans_handle *trans, |
3028 | struct btrfs_pending_snapshot *pending); | 3038 | struct btrfs_pending_snapshot *pending); |
3029 | 3039 | ||
3030 | /* scrub.c */ | 3040 | /* scrub.c */ |
@@ -3034,6 +3044,7 @@ void btrfs_scrub_pause(struct btrfs_root *root); | |||
3034 | void btrfs_scrub_pause_super(struct btrfs_root *root); | 3044 | void btrfs_scrub_pause_super(struct btrfs_root *root); |
3035 | void btrfs_scrub_continue(struct btrfs_root *root); | 3045 | void btrfs_scrub_continue(struct btrfs_root *root); |
3036 | void btrfs_scrub_continue_super(struct btrfs_root *root); | 3046 | void btrfs_scrub_continue_super(struct btrfs_root *root); |
3047 | int __btrfs_scrub_cancel(struct btrfs_fs_info *info); | ||
3037 | int btrfs_scrub_cancel(struct btrfs_root *root); | 3048 | int btrfs_scrub_cancel(struct btrfs_root *root); |
3038 | int btrfs_scrub_cancel_dev(struct btrfs_root *root, struct btrfs_device *dev); | 3049 | int btrfs_scrub_cancel_dev(struct btrfs_root *root, struct btrfs_device *dev); |
3039 | int btrfs_scrub_cancel_devid(struct btrfs_root *root, u64 devid); | 3050 | int btrfs_scrub_cancel_devid(struct btrfs_root *root, u64 devid); |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 69ef456b32fa..6297a030ac50 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -61,7 +61,6 @@ static int btrfs_destroy_marked_extents(struct btrfs_root *root, | |||
61 | int mark); | 61 | int mark); |
62 | static int btrfs_destroy_pinned_extent(struct btrfs_root *root, | 62 | static int btrfs_destroy_pinned_extent(struct btrfs_root *root, |
63 | struct extent_io_tree *pinned_extents); | 63 | struct extent_io_tree *pinned_extents); |
64 | static int btrfs_cleanup_transaction(struct btrfs_root *root); | ||
65 | 64 | ||
66 | /* | 65 | /* |
67 | * end_io_wq structs are used to do processing in task context when an IO is | 66 | * end_io_wq structs are used to do processing in task context when an IO is |
@@ -2896,6 +2895,19 @@ int write_ctree_super(struct btrfs_trans_handle *trans, | |||
2896 | return ret; | 2895 | return ret; |
2897 | } | 2896 | } |
2898 | 2897 | ||
2898 | /* Kill all outstanding I/O */ | ||
2899 | void btrfs_abort_devices(struct btrfs_root *root) | ||
2900 | { | ||
2901 | struct list_head *head; | ||
2902 | struct btrfs_device *dev; | ||
2903 | mutex_lock(&root->fs_info->fs_devices->device_list_mutex); | ||
2904 | head = &root->fs_info->fs_devices->devices; | ||
2905 | list_for_each_entry_rcu(dev, head, dev_list) { | ||
2906 | blk_abort_queue(dev->bdev->bd_disk->queue); | ||
2907 | } | ||
2908 | mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); | ||
2909 | } | ||
2910 | |||
2899 | void btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root) | 2911 | void btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root) |
2900 | { | 2912 | { |
2901 | spin_lock(&fs_info->fs_roots_radix_lock); | 2913 | spin_lock(&fs_info->fs_roots_radix_lock); |
@@ -3536,13 +3548,43 @@ static int btrfs_destroy_pinned_extent(struct btrfs_root *root, | |||
3536 | return 0; | 3548 | return 0; |
3537 | } | 3549 | } |
3538 | 3550 | ||
3539 | static int btrfs_cleanup_transaction(struct btrfs_root *root) | 3551 | void btrfs_cleanup_one_transaction(struct btrfs_transaction *cur_trans, |
3552 | struct btrfs_root *root) | ||
3553 | { | ||
3554 | btrfs_destroy_delayed_refs(cur_trans, root); | ||
3555 | btrfs_block_rsv_release(root, &root->fs_info->trans_block_rsv, | ||
3556 | cur_trans->dirty_pages.dirty_bytes); | ||
3557 | |||
3558 | /* FIXME: cleanup wait for commit */ | ||
3559 | cur_trans->in_commit = 1; | ||
3560 | cur_trans->blocked = 1; | ||
3561 | if (waitqueue_active(&root->fs_info->transaction_blocked_wait)) | ||
3562 | wake_up(&root->fs_info->transaction_blocked_wait); | ||
3563 | |||
3564 | cur_trans->blocked = 0; | ||
3565 | if (waitqueue_active(&root->fs_info->transaction_wait)) | ||
3566 | wake_up(&root->fs_info->transaction_wait); | ||
3567 | |||
3568 | cur_trans->commit_done = 1; | ||
3569 | if (waitqueue_active(&cur_trans->commit_wait)) | ||
3570 | wake_up(&cur_trans->commit_wait); | ||
3571 | |||
3572 | btrfs_destroy_pending_snapshots(cur_trans); | ||
3573 | |||
3574 | btrfs_destroy_marked_extents(root, &cur_trans->dirty_pages, | ||
3575 | EXTENT_DIRTY); | ||
3576 | |||
3577 | /* | ||
3578 | memset(cur_trans, 0, sizeof(*cur_trans)); | ||
3579 | kmem_cache_free(btrfs_transaction_cachep, cur_trans); | ||
3580 | */ | ||
3581 | } | ||
3582 | |||
3583 | int btrfs_cleanup_transaction(struct btrfs_root *root) | ||
3540 | { | 3584 | { |
3541 | struct btrfs_transaction *t; | 3585 | struct btrfs_transaction *t; |
3542 | LIST_HEAD(list); | 3586 | LIST_HEAD(list); |
3543 | 3587 | ||
3544 | WARN_ON(1); | ||
3545 | |||
3546 | mutex_lock(&root->fs_info->transaction_kthread_mutex); | 3588 | mutex_lock(&root->fs_info->transaction_kthread_mutex); |
3547 | 3589 | ||
3548 | spin_lock(&root->fs_info->trans_lock); | 3590 | spin_lock(&root->fs_info->trans_lock); |
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h index 1608492d485f..a7ace1a2dd12 100644 --- a/fs/btrfs/disk-io.h +++ b/fs/btrfs/disk-io.h | |||
@@ -85,6 +85,10 @@ int btrfs_init_log_root_tree(struct btrfs_trans_handle *trans, | |||
85 | struct btrfs_fs_info *fs_info); | 85 | struct btrfs_fs_info *fs_info); |
86 | int btrfs_add_log_tree(struct btrfs_trans_handle *trans, | 86 | int btrfs_add_log_tree(struct btrfs_trans_handle *trans, |
87 | struct btrfs_root *root); | 87 | struct btrfs_root *root); |
88 | int btrfs_cleanup_transaction(struct btrfs_root *root); | ||
89 | void btrfs_cleanup_one_transaction(struct btrfs_transaction *trans, | ||
90 | struct btrfs_root *root); | ||
91 | void btrfs_abort_devices(struct btrfs_root *root); | ||
88 | 92 | ||
89 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | 93 | #ifdef CONFIG_DEBUG_LOCK_ALLOC |
90 | void btrfs_init_lockdep(void); | 94 | void btrfs_init_lockdep(void); |
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index a87678ead611..cba7a0bf3667 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c | |||
@@ -4410,7 +4410,7 @@ void btrfs_reloc_pre_snapshot(struct btrfs_trans_handle *trans, | |||
4410 | * called after snapshot is created. migrate block reservation | 4410 | * called after snapshot is created. migrate block reservation |
4411 | * and create reloc root for the newly created snapshot | 4411 | * and create reloc root for the newly created snapshot |
4412 | */ | 4412 | */ |
4413 | void btrfs_reloc_post_snapshot(struct btrfs_trans_handle *trans, | 4413 | int btrfs_reloc_post_snapshot(struct btrfs_trans_handle *trans, |
4414 | struct btrfs_pending_snapshot *pending) | 4414 | struct btrfs_pending_snapshot *pending) |
4415 | { | 4415 | { |
4416 | struct btrfs_root *root = pending->root; | 4416 | struct btrfs_root *root = pending->root; |
@@ -4420,7 +4420,7 @@ void btrfs_reloc_post_snapshot(struct btrfs_trans_handle *trans, | |||
4420 | int ret; | 4420 | int ret; |
4421 | 4421 | ||
4422 | if (!root->reloc_root) | 4422 | if (!root->reloc_root) |
4423 | return; | 4423 | return 0; |
4424 | 4424 | ||
4425 | rc = root->fs_info->reloc_ctl; | 4425 | rc = root->fs_info->reloc_ctl; |
4426 | rc->merging_rsv_size += rc->nodes_relocated; | 4426 | rc->merging_rsv_size += rc->nodes_relocated; |
@@ -4429,19 +4429,21 @@ void btrfs_reloc_post_snapshot(struct btrfs_trans_handle *trans, | |||
4429 | ret = btrfs_block_rsv_migrate(&pending->block_rsv, | 4429 | ret = btrfs_block_rsv_migrate(&pending->block_rsv, |
4430 | rc->block_rsv, | 4430 | rc->block_rsv, |
4431 | rc->nodes_relocated); | 4431 | rc->nodes_relocated); |
4432 | BUG_ON(ret); | 4432 | if (ret) |
4433 | return ret; | ||
4433 | } | 4434 | } |
4434 | 4435 | ||
4435 | new_root = pending->snap; | 4436 | new_root = pending->snap; |
4436 | reloc_root = create_reloc_root(trans, root->reloc_root, | 4437 | reloc_root = create_reloc_root(trans, root->reloc_root, |
4437 | new_root->root_key.objectid); | 4438 | new_root->root_key.objectid); |
4439 | if (IS_ERR(reloc_root)) | ||
4440 | return PTR_ERR(reloc_root); | ||
4438 | 4441 | ||
4439 | ret = __add_reloc_root(reloc_root); | 4442 | ret = __add_reloc_root(reloc_root); |
4440 | BUG_ON(ret < 0); | 4443 | BUG_ON(ret < 0); |
4441 | new_root->reloc_root = reloc_root; | 4444 | new_root->reloc_root = reloc_root; |
4442 | 4445 | ||
4443 | if (rc->create_reloc_tree) { | 4446 | if (rc->create_reloc_tree) |
4444 | ret = clone_backref_node(trans, rc, root, reloc_root); | 4447 | ret = clone_backref_node(trans, rc, root, reloc_root); |
4445 | BUG_ON(ret); | 4448 | return ret; |
4446 | } | ||
4447 | } | 4449 | } |
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index a2e8aa40f3f5..794cbb52f308 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c | |||
@@ -1680,9 +1680,8 @@ void btrfs_scrub_continue_super(struct btrfs_root *root) | |||
1680 | up_write(&root->fs_info->scrub_super_lock); | 1680 | up_write(&root->fs_info->scrub_super_lock); |
1681 | } | 1681 | } |
1682 | 1682 | ||
1683 | int btrfs_scrub_cancel(struct btrfs_root *root) | 1683 | int __btrfs_scrub_cancel(struct btrfs_fs_info *fs_info) |
1684 | { | 1684 | { |
1685 | struct btrfs_fs_info *fs_info = root->fs_info; | ||
1686 | 1685 | ||
1687 | mutex_lock(&fs_info->scrub_lock); | 1686 | mutex_lock(&fs_info->scrub_lock); |
1688 | if (!atomic_read(&fs_info->scrubs_running)) { | 1687 | if (!atomic_read(&fs_info->scrubs_running)) { |
@@ -1703,6 +1702,11 @@ int btrfs_scrub_cancel(struct btrfs_root *root) | |||
1703 | return 0; | 1702 | return 0; |
1704 | } | 1703 | } |
1705 | 1704 | ||
1705 | int btrfs_scrub_cancel(struct btrfs_root *root) | ||
1706 | { | ||
1707 | return __btrfs_scrub_cancel(root->fs_info); | ||
1708 | } | ||
1709 | |||
1706 | int btrfs_scrub_cancel_dev(struct btrfs_root *root, struct btrfs_device *dev) | 1710 | int btrfs_scrub_cancel_dev(struct btrfs_root *root, struct btrfs_device *dev) |
1707 | { | 1711 | { |
1708 | struct btrfs_fs_info *fs_info = root->fs_info; | 1712 | struct btrfs_fs_info *fs_info = root->fs_info; |
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 7fe69eef7607..0517bd70b04c 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
@@ -119,6 +119,8 @@ static void btrfs_handle_error(struct btrfs_fs_info *fs_info) | |||
119 | if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) { | 119 | if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) { |
120 | sb->s_flags |= MS_RDONLY; | 120 | sb->s_flags |= MS_RDONLY; |
121 | printk(KERN_INFO "btrfs is forced readonly\n"); | 121 | printk(KERN_INFO "btrfs is forced readonly\n"); |
122 | __btrfs_scrub_cancel(fs_info); | ||
123 | // WARN_ON(1); | ||
122 | } | 124 | } |
123 | } | 125 | } |
124 | 126 | ||
@@ -198,6 +200,34 @@ void btrfs_printk(struct btrfs_fs_info *fs_info, const char *fmt, ...) | |||
198 | } | 200 | } |
199 | 201 | ||
200 | /* | 202 | /* |
203 | * We only mark the transaction aborted and then set the file system read-only. | ||
204 | * This will prevent new transactions from starting or trying to join this | ||
205 | * one. | ||
206 | * | ||
207 | * This means that error recovery at the call site is limited to freeing | ||
208 | * any local memory allocations and passing the error code up without | ||
209 | * further cleanup. The transaction should complete as it normally would | ||
210 | * in the call path but will return -EIO. | ||
211 | * | ||
212 | * We'll complete the cleanup in btrfs_end_transaction and | ||
213 | * btrfs_commit_transaction. | ||
214 | */ | ||
215 | void __btrfs_abort_transaction(struct btrfs_trans_handle *trans, | ||
216 | struct btrfs_root *root, const char *function, | ||
217 | unsigned int line, int errno) | ||
218 | { | ||
219 | WARN_ON_ONCE(1); | ||
220 | trans->aborted = errno; | ||
221 | /* Nothing used. The other threads that have joined this | ||
222 | * transaction may be able to continue. */ | ||
223 | if (!trans->blocks_used) { | ||
224 | btrfs_printk(root->fs_info, "Aborting unused transaction.\n"); | ||
225 | return; | ||
226 | } | ||
227 | trans->transaction->aborted = errno; | ||
228 | __btrfs_std_error(root->fs_info, function, line, errno, NULL); | ||
229 | } | ||
230 | /* | ||
201 | * __btrfs_panic decodes unexpected, fatal errors from the caller, | 231 | * __btrfs_panic decodes unexpected, fatal errors from the caller, |
202 | * issues an alert, and either panics or BUGs, depending on mount options. | 232 | * issues an alert, and either panics or BUGs, depending on mount options. |
203 | */ | 233 | */ |
@@ -295,6 +325,7 @@ static match_table_t tokens = { | |||
295 | /* | 325 | /* |
296 | * Regular mount options parser. Everything that is needed only when | 326 | * Regular mount options parser. Everything that is needed only when |
297 | * reading in a new superblock is parsed here. | 327 | * reading in a new superblock is parsed here. |
328 | * XXX JDM: This needs to be cleaned up for remount. | ||
298 | */ | 329 | */ |
299 | int btrfs_parse_options(struct btrfs_root *root, char *options) | 330 | int btrfs_parse_options(struct btrfs_root *root, char *options) |
300 | { | 331 | { |
@@ -1096,11 +1127,20 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data) | |||
1096 | { | 1127 | { |
1097 | struct btrfs_fs_info *fs_info = btrfs_sb(sb); | 1128 | struct btrfs_fs_info *fs_info = btrfs_sb(sb); |
1098 | struct btrfs_root *root = fs_info->tree_root; | 1129 | struct btrfs_root *root = fs_info->tree_root; |
1130 | unsigned old_flags = sb->s_flags; | ||
1131 | unsigned long old_opts = fs_info->mount_opt; | ||
1132 | unsigned long old_compress_type = fs_info->compress_type; | ||
1133 | u64 old_max_inline = fs_info->max_inline; | ||
1134 | u64 old_alloc_start = fs_info->alloc_start; | ||
1135 | int old_thread_pool_size = fs_info->thread_pool_size; | ||
1136 | unsigned int old_metadata_ratio = fs_info->metadata_ratio; | ||
1099 | int ret; | 1137 | int ret; |
1100 | 1138 | ||
1101 | ret = btrfs_parse_options(root, data); | 1139 | ret = btrfs_parse_options(root, data); |
1102 | if (ret) | 1140 | if (ret) { |
1103 | return -EINVAL; | 1141 | ret = -EINVAL; |
1142 | goto restore; | ||
1143 | } | ||
1104 | 1144 | ||
1105 | if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) | 1145 | if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) |
1106 | return 0; | 1146 | return 0; |
@@ -1108,26 +1148,44 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data) | |||
1108 | if (*flags & MS_RDONLY) { | 1148 | if (*flags & MS_RDONLY) { |
1109 | sb->s_flags |= MS_RDONLY; | 1149 | sb->s_flags |= MS_RDONLY; |
1110 | 1150 | ||
1111 | ret = btrfs_commit_super(root); | 1151 | ret = btrfs_commit_super(root); |
1112 | WARN_ON(ret); | 1152 | if (ret) |
1153 | goto restore; | ||
1113 | } else { | 1154 | } else { |
1114 | if (fs_info->fs_devices->rw_devices == 0) | 1155 | if (fs_info->fs_devices->rw_devices == 0) |
1115 | return -EACCES; | 1156 | ret = -EACCES; |
1157 | goto restore; | ||
1116 | 1158 | ||
1117 | if (btrfs_super_log_root(fs_info->super_copy) != 0) | 1159 | if (btrfs_super_log_root(fs_info->super_copy) != 0) |
1118 | return -EINVAL; | 1160 | ret = -EINVAL; |
1161 | goto restore; | ||
1119 | 1162 | ||
1120 | ret = btrfs_cleanup_fs_roots(fs_info); | 1163 | ret = btrfs_cleanup_fs_roots(fs_info); |
1121 | WARN_ON(ret); | 1164 | if (ret) |
1165 | goto restore; | ||
1122 | 1166 | ||
1123 | /* recover relocation */ | 1167 | /* recover relocation */ |
1124 | ret = btrfs_recover_relocation(root); | 1168 | ret = btrfs_recover_relocation(root); |
1125 | WARN_ON(ret); | 1169 | if (ret) |
1170 | goto restore; | ||
1126 | 1171 | ||
1127 | sb->s_flags &= ~MS_RDONLY; | 1172 | sb->s_flags &= ~MS_RDONLY; |
1128 | } | 1173 | } |
1129 | 1174 | ||
1130 | return 0; | 1175 | return 0; |
1176 | |||
1177 | restore: | ||
1178 | /* We've hit an error - don't reset MS_RDONLY */ | ||
1179 | if (sb->s_flags & MS_RDONLY) | ||
1180 | old_flags |= MS_RDONLY; | ||
1181 | sb->s_flags = old_flags; | ||
1182 | fs_info->mount_opt = old_opts; | ||
1183 | fs_info->compress_type = old_compress_type; | ||
1184 | fs_info->max_inline = old_max_inline; | ||
1185 | fs_info->alloc_start = old_alloc_start; | ||
1186 | fs_info->thread_pool_size = old_thread_pool_size; | ||
1187 | fs_info->metadata_ratio = old_metadata_ratio; | ||
1188 | return ret; | ||
1131 | } | 1189 | } |
1132 | 1190 | ||
1133 | /* Used to sort the devices by max_avail(descending sort) */ | 1191 | /* Used to sort the devices by max_avail(descending sort) */ |
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index fb5cd5a4adba..5a4999aa8fef 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -31,7 +31,7 @@ | |||
31 | 31 | ||
32 | #define BTRFS_ROOT_TRANS_TAG 0 | 32 | #define BTRFS_ROOT_TRANS_TAG 0 |
33 | 33 | ||
34 | static noinline void put_transaction(struct btrfs_transaction *transaction) | 34 | void put_transaction(struct btrfs_transaction *transaction) |
35 | { | 35 | { |
36 | WARN_ON(atomic_read(&transaction->use_count) == 0); | 36 | WARN_ON(atomic_read(&transaction->use_count) == 0); |
37 | if (atomic_dec_and_test(&transaction->use_count)) { | 37 | if (atomic_dec_and_test(&transaction->use_count)) { |
@@ -58,6 +58,12 @@ static noinline int join_transaction(struct btrfs_root *root, int nofail) | |||
58 | 58 | ||
59 | spin_lock(&root->fs_info->trans_lock); | 59 | spin_lock(&root->fs_info->trans_lock); |
60 | loop: | 60 | loop: |
61 | /* The file system has been taken offline. No new transactions. */ | ||
62 | if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) { | ||
63 | spin_unlock(&root->fs_info->trans_lock); | ||
64 | return -EROFS; | ||
65 | } | ||
66 | |||
61 | if (root->fs_info->trans_no_join) { | 67 | if (root->fs_info->trans_no_join) { |
62 | if (!nofail) { | 68 | if (!nofail) { |
63 | spin_unlock(&root->fs_info->trans_lock); | 69 | spin_unlock(&root->fs_info->trans_lock); |
@@ -67,6 +73,8 @@ loop: | |||
67 | 73 | ||
68 | cur_trans = root->fs_info->running_transaction; | 74 | cur_trans = root->fs_info->running_transaction; |
69 | if (cur_trans) { | 75 | if (cur_trans) { |
76 | if (cur_trans->aborted) | ||
77 | return cur_trans->aborted; | ||
70 | atomic_inc(&cur_trans->use_count); | 78 | atomic_inc(&cur_trans->use_count); |
71 | atomic_inc(&cur_trans->num_writers); | 79 | atomic_inc(&cur_trans->num_writers); |
72 | cur_trans->num_joined++; | 80 | cur_trans->num_joined++; |
@@ -123,6 +131,7 @@ loop: | |||
123 | root->fs_info->generation++; | 131 | root->fs_info->generation++; |
124 | cur_trans->transid = root->fs_info->generation; | 132 | cur_trans->transid = root->fs_info->generation; |
125 | root->fs_info->running_transaction = cur_trans; | 133 | root->fs_info->running_transaction = cur_trans; |
134 | cur_trans->aborted = 0; | ||
126 | spin_unlock(&root->fs_info->trans_lock); | 135 | spin_unlock(&root->fs_info->trans_lock); |
127 | 136 | ||
128 | return 0; | 137 | return 0; |
@@ -318,6 +327,7 @@ again: | |||
318 | h->use_count = 1; | 327 | h->use_count = 1; |
319 | h->block_rsv = NULL; | 328 | h->block_rsv = NULL; |
320 | h->orig_rsv = NULL; | 329 | h->orig_rsv = NULL; |
330 | h->aborted = 0; | ||
321 | 331 | ||
322 | smp_mb(); | 332 | smp_mb(); |
323 | if (cur_trans->blocked && may_wait_transaction(root, type)) { | 333 | if (cur_trans->blocked && may_wait_transaction(root, type)) { |
@@ -440,6 +450,7 @@ int btrfs_should_end_transaction(struct btrfs_trans_handle *trans, | |||
440 | struct btrfs_transaction *cur_trans = trans->transaction; | 450 | struct btrfs_transaction *cur_trans = trans->transaction; |
441 | struct btrfs_block_rsv *rsv = trans->block_rsv; | 451 | struct btrfs_block_rsv *rsv = trans->block_rsv; |
442 | int updates; | 452 | int updates; |
453 | int err; | ||
443 | 454 | ||
444 | smp_mb(); | 455 | smp_mb(); |
445 | if (cur_trans->blocked || cur_trans->delayed_refs.flushing) | 456 | if (cur_trans->blocked || cur_trans->delayed_refs.flushing) |
@@ -453,8 +464,11 @@ int btrfs_should_end_transaction(struct btrfs_trans_handle *trans, | |||
453 | 464 | ||
454 | updates = trans->delayed_ref_updates; | 465 | updates = trans->delayed_ref_updates; |
455 | trans->delayed_ref_updates = 0; | 466 | trans->delayed_ref_updates = 0; |
456 | if (updates) | 467 | if (updates) { |
457 | btrfs_run_delayed_refs(trans, root, updates); | 468 | err = btrfs_run_delayed_refs(trans, root, updates); |
469 | if (err) /* Error code will also eval true */ | ||
470 | return err; | ||
471 | } | ||
458 | 472 | ||
459 | trans->block_rsv = rsv; | 473 | trans->block_rsv = rsv; |
460 | 474 | ||
@@ -525,6 +539,11 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, | |||
525 | if (throttle) | 539 | if (throttle) |
526 | btrfs_run_delayed_iputs(root); | 540 | btrfs_run_delayed_iputs(root); |
527 | 541 | ||
542 | if (trans->aborted || | ||
543 | root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) { | ||
544 | return -EIO; | ||
545 | } | ||
546 | |||
528 | return 0; | 547 | return 0; |
529 | } | 548 | } |
530 | 549 | ||
@@ -690,11 +709,13 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans, | |||
690 | ret = btrfs_update_root(trans, tree_root, | 709 | ret = btrfs_update_root(trans, tree_root, |
691 | &root->root_key, | 710 | &root->root_key, |
692 | &root->root_item); | 711 | &root->root_item); |
693 | BUG_ON(ret); | 712 | if (ret) |
713 | return ret; | ||
694 | 714 | ||
695 | old_root_used = btrfs_root_used(&root->root_item); | 715 | old_root_used = btrfs_root_used(&root->root_item); |
696 | ret = btrfs_write_dirty_block_groups(trans, root); | 716 | ret = btrfs_write_dirty_block_groups(trans, root); |
697 | BUG_ON(ret); | 717 | if (ret) |
718 | return ret; | ||
698 | } | 719 | } |
699 | 720 | ||
700 | if (root != root->fs_info->extent_root) | 721 | if (root != root->fs_info->extent_root) |
@@ -705,6 +726,10 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans, | |||
705 | 726 | ||
706 | /* | 727 | /* |
707 | * update all the cowonly tree roots on disk | 728 | * update all the cowonly tree roots on disk |
729 | * | ||
730 | * The error handling in this function may not be obvious. Any of the | ||
731 | * failures will cause the file system to go offline. We still need | ||
732 | * to clean up the delayed refs. | ||
708 | */ | 733 | */ |
709 | static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans, | 734 | static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans, |
710 | struct btrfs_root *root) | 735 | struct btrfs_root *root) |
@@ -715,22 +740,30 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans, | |||
715 | int ret; | 740 | int ret; |
716 | 741 | ||
717 | ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1); | 742 | ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1); |
718 | BUG_ON(ret); | 743 | if (ret) |
744 | return ret; | ||
719 | 745 | ||
720 | eb = btrfs_lock_root_node(fs_info->tree_root); | 746 | eb = btrfs_lock_root_node(fs_info->tree_root); |
721 | btrfs_cow_block(trans, fs_info->tree_root, eb, NULL, 0, &eb); | 747 | ret = btrfs_cow_block(trans, fs_info->tree_root, eb, NULL, |
748 | 0, &eb); | ||
722 | btrfs_tree_unlock(eb); | 749 | btrfs_tree_unlock(eb); |
723 | free_extent_buffer(eb); | 750 | free_extent_buffer(eb); |
724 | 751 | ||
752 | if (ret) | ||
753 | return ret; | ||
754 | |||
725 | ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1); | 755 | ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1); |
726 | BUG_ON(ret); | 756 | if (ret) |
757 | return ret; | ||
727 | 758 | ||
728 | while (!list_empty(&fs_info->dirty_cowonly_roots)) { | 759 | while (!list_empty(&fs_info->dirty_cowonly_roots)) { |
729 | next = fs_info->dirty_cowonly_roots.next; | 760 | next = fs_info->dirty_cowonly_roots.next; |
730 | list_del_init(next); | 761 | list_del_init(next); |
731 | root = list_entry(next, struct btrfs_root, dirty_list); | 762 | root = list_entry(next, struct btrfs_root, dirty_list); |
732 | 763 | ||
733 | update_cowonly_root(trans, root); | 764 | ret = update_cowonly_root(trans, root); |
765 | if (ret) | ||
766 | return ret; | ||
734 | } | 767 | } |
735 | 768 | ||
736 | down_write(&fs_info->extent_commit_sem); | 769 | down_write(&fs_info->extent_commit_sem); |
@@ -874,7 +907,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
874 | 907 | ||
875 | new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS); | 908 | new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS); |
876 | if (!new_root_item) { | 909 | if (!new_root_item) { |
877 | pending->error = -ENOMEM; | 910 | ret = pending->error = -ENOMEM; |
878 | goto fail; | 911 | goto fail; |
879 | } | 912 | } |
880 | 913 | ||
@@ -911,7 +944,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
911 | * insert the directory item | 944 | * insert the directory item |
912 | */ | 945 | */ |
913 | ret = btrfs_set_inode_index(parent_inode, &index); | 946 | ret = btrfs_set_inode_index(parent_inode, &index); |
914 | BUG_ON(ret); | 947 | BUG_ON(ret); /* -ENOMEM */ |
915 | ret = btrfs_insert_dir_item(trans, parent_root, | 948 | ret = btrfs_insert_dir_item(trans, parent_root, |
916 | dentry->d_name.name, dentry->d_name.len, | 949 | dentry->d_name.name, dentry->d_name.len, |
917 | parent_inode, &key, | 950 | parent_inode, &key, |
@@ -920,12 +953,14 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
920 | pending->error = -EEXIST; | 953 | pending->error = -EEXIST; |
921 | dput(parent); | 954 | dput(parent); |
922 | goto fail; | 955 | goto fail; |
923 | } | 956 | } else if (ret) |
957 | goto abort_trans; | ||
924 | 958 | ||
925 | btrfs_i_size_write(parent_inode, parent_inode->i_size + | 959 | btrfs_i_size_write(parent_inode, parent_inode->i_size + |
926 | dentry->d_name.len * 2); | 960 | dentry->d_name.len * 2); |
927 | ret = btrfs_update_inode(trans, parent_root, parent_inode); | 961 | ret = btrfs_update_inode(trans, parent_root, parent_inode); |
928 | BUG_ON(ret); | 962 | if (ret) |
963 | goto abort_trans; | ||
929 | 964 | ||
930 | /* | 965 | /* |
931 | * pull in the delayed directory update | 966 | * pull in the delayed directory update |
@@ -934,7 +969,8 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
934 | * snapshot | 969 | * snapshot |
935 | */ | 970 | */ |
936 | ret = btrfs_run_delayed_items(trans, root); | 971 | ret = btrfs_run_delayed_items(trans, root); |
937 | BUG_ON(ret); | 972 | if (ret) /* Transaction aborted */ |
973 | goto fail; | ||
938 | 974 | ||
939 | record_root_in_trans(trans, root); | 975 | record_root_in_trans(trans, root); |
940 | btrfs_set_root_last_snapshot(&root->root_item, trans->transid); | 976 | btrfs_set_root_last_snapshot(&root->root_item, trans->transid); |
@@ -949,10 +985,16 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
949 | btrfs_set_root_flags(new_root_item, root_flags); | 985 | btrfs_set_root_flags(new_root_item, root_flags); |
950 | 986 | ||
951 | old = btrfs_lock_root_node(root); | 987 | old = btrfs_lock_root_node(root); |
952 | btrfs_cow_block(trans, root, old, NULL, 0, &old); | 988 | ret = btrfs_cow_block(trans, root, old, NULL, 0, &old); |
989 | if (ret) | ||
990 | goto abort_trans; | ||
991 | |||
953 | btrfs_set_lock_blocking(old); | 992 | btrfs_set_lock_blocking(old); |
954 | 993 | ||
955 | btrfs_copy_root(trans, root, old, &tmp, objectid); | 994 | ret = btrfs_copy_root(trans, root, old, &tmp, objectid); |
995 | if (ret) | ||
996 | goto abort_trans; | ||
997 | |||
956 | btrfs_tree_unlock(old); | 998 | btrfs_tree_unlock(old); |
957 | free_extent_buffer(old); | 999 | free_extent_buffer(old); |
958 | 1000 | ||
@@ -966,7 +1008,8 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
966 | ret = btrfs_insert_root(trans, tree_root, &key, new_root_item); | 1008 | ret = btrfs_insert_root(trans, tree_root, &key, new_root_item); |
967 | btrfs_tree_unlock(tmp); | 1009 | btrfs_tree_unlock(tmp); |
968 | free_extent_buffer(tmp); | 1010 | free_extent_buffer(tmp); |
969 | BUG_ON(ret); | 1011 | if (ret) |
1012 | goto abort_trans; | ||
970 | 1013 | ||
971 | /* | 1014 | /* |
972 | * insert root back/forward references | 1015 | * insert root back/forward references |
@@ -975,19 +1018,28 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
975 | parent_root->root_key.objectid, | 1018 | parent_root->root_key.objectid, |
976 | btrfs_ino(parent_inode), index, | 1019 | btrfs_ino(parent_inode), index, |
977 | dentry->d_name.name, dentry->d_name.len); | 1020 | dentry->d_name.name, dentry->d_name.len); |
978 | BUG_ON(ret); | 1021 | if (ret) |
1022 | goto fail; | ||
979 | dput(parent); | 1023 | dput(parent); |
980 | 1024 | ||
981 | key.offset = (u64)-1; | 1025 | key.offset = (u64)-1; |
982 | pending->snap = btrfs_read_fs_root_no_name(root->fs_info, &key); | 1026 | pending->snap = btrfs_read_fs_root_no_name(root->fs_info, &key); |
983 | BUG_ON(IS_ERR(pending->snap)); | 1027 | if (IS_ERR(pending->snap)) |
1028 | goto abort_trans; | ||
984 | 1029 | ||
985 | btrfs_reloc_post_snapshot(trans, pending); | 1030 | ret = btrfs_reloc_post_snapshot(trans, pending); |
1031 | if (ret) | ||
1032 | goto abort_trans; | ||
1033 | ret = 0; | ||
986 | fail: | 1034 | fail: |
987 | kfree(new_root_item); | 1035 | kfree(new_root_item); |
988 | trans->block_rsv = rsv; | 1036 | trans->block_rsv = rsv; |
989 | btrfs_block_rsv_release(root, &pending->block_rsv, (u64)-1); | 1037 | btrfs_block_rsv_release(root, &pending->block_rsv, (u64)-1); |
990 | return 0; | 1038 | return ret; |
1039 | |||
1040 | abort_trans: | ||
1041 | btrfs_abort_transaction(trans, root, ret); | ||
1042 | goto fail; | ||
991 | } | 1043 | } |
992 | 1044 | ||
993 | /* | 1045 | /* |
@@ -1124,6 +1176,33 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans, | |||
1124 | return 0; | 1176 | return 0; |
1125 | } | 1177 | } |
1126 | 1178 | ||
1179 | |||
1180 | static void cleanup_transaction(struct btrfs_trans_handle *trans, | ||
1181 | struct btrfs_root *root) | ||
1182 | { | ||
1183 | struct btrfs_transaction *cur_trans = trans->transaction; | ||
1184 | |||
1185 | WARN_ON(trans->use_count > 1); | ||
1186 | |||
1187 | spin_lock(&root->fs_info->trans_lock); | ||
1188 | list_del_init(&cur_trans->list); | ||
1189 | spin_unlock(&root->fs_info->trans_lock); | ||
1190 | |||
1191 | btrfs_cleanup_one_transaction(trans->transaction, root); | ||
1192 | |||
1193 | put_transaction(cur_trans); | ||
1194 | put_transaction(cur_trans); | ||
1195 | |||
1196 | trace_btrfs_transaction_commit(root); | ||
1197 | |||
1198 | btrfs_scrub_continue(root); | ||
1199 | |||
1200 | if (current->journal_info == trans) | ||
1201 | current->journal_info = NULL; | ||
1202 | |||
1203 | kmem_cache_free(btrfs_trans_handle_cachep, trans); | ||
1204 | } | ||
1205 | |||
1127 | /* | 1206 | /* |
1128 | * btrfs_transaction state sequence: | 1207 | * btrfs_transaction state sequence: |
1129 | * in_commit = 0, blocked = 0 (initial) | 1208 | * in_commit = 0, blocked = 0 (initial) |
@@ -1135,10 +1214,10 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1135 | struct btrfs_root *root) | 1214 | struct btrfs_root *root) |
1136 | { | 1215 | { |
1137 | unsigned long joined = 0; | 1216 | unsigned long joined = 0; |
1138 | struct btrfs_transaction *cur_trans; | 1217 | struct btrfs_transaction *cur_trans = trans->transaction; |
1139 | struct btrfs_transaction *prev_trans = NULL; | 1218 | struct btrfs_transaction *prev_trans = NULL; |
1140 | DEFINE_WAIT(wait); | 1219 | DEFINE_WAIT(wait); |
1141 | int ret; | 1220 | int ret = -EIO; |
1142 | int should_grow = 0; | 1221 | int should_grow = 0; |
1143 | unsigned long now = get_seconds(); | 1222 | unsigned long now = get_seconds(); |
1144 | int flush_on_commit = btrfs_test_opt(root, FLUSHONCOMMIT); | 1223 | int flush_on_commit = btrfs_test_opt(root, FLUSHONCOMMIT); |
@@ -1148,13 +1227,18 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1148 | btrfs_trans_release_metadata(trans, root); | 1227 | btrfs_trans_release_metadata(trans, root); |
1149 | trans->block_rsv = NULL; | 1228 | trans->block_rsv = NULL; |
1150 | 1229 | ||
1230 | if (cur_trans->aborted) | ||
1231 | goto cleanup_transaction; | ||
1232 | |||
1151 | /* make a pass through all the delayed refs we have so far | 1233 | /* make a pass through all the delayed refs we have so far |
1152 | * any runnings procs may add more while we are here | 1234 | * any runnings procs may add more while we are here |
1153 | */ | 1235 | */ |
1154 | ret = btrfs_run_delayed_refs(trans, root, 0); | 1236 | ret = btrfs_run_delayed_refs(trans, root, 0); |
1155 | BUG_ON(ret); | 1237 | if (ret) |
1238 | goto cleanup_transaction; | ||
1156 | 1239 | ||
1157 | cur_trans = trans->transaction; | 1240 | cur_trans = trans->transaction; |
1241 | |||
1158 | /* | 1242 | /* |
1159 | * set the flushing flag so procs in this transaction have to | 1243 | * set the flushing flag so procs in this transaction have to |
1160 | * start sending their work down. | 1244 | * start sending their work down. |
@@ -1162,19 +1246,20 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1162 | cur_trans->delayed_refs.flushing = 1; | 1246 | cur_trans->delayed_refs.flushing = 1; |
1163 | 1247 | ||
1164 | ret = btrfs_run_delayed_refs(trans, root, 0); | 1248 | ret = btrfs_run_delayed_refs(trans, root, 0); |
1165 | BUG_ON(ret); | 1249 | if (ret) |
1250 | goto cleanup_transaction; | ||
1166 | 1251 | ||
1167 | spin_lock(&cur_trans->commit_lock); | 1252 | spin_lock(&cur_trans->commit_lock); |
1168 | if (cur_trans->in_commit) { | 1253 | if (cur_trans->in_commit) { |
1169 | spin_unlock(&cur_trans->commit_lock); | 1254 | spin_unlock(&cur_trans->commit_lock); |
1170 | atomic_inc(&cur_trans->use_count); | 1255 | atomic_inc(&cur_trans->use_count); |
1171 | btrfs_end_transaction(trans, root); | 1256 | ret = btrfs_end_transaction(trans, root); |
1172 | 1257 | ||
1173 | wait_for_commit(root, cur_trans); | 1258 | wait_for_commit(root, cur_trans); |
1174 | 1259 | ||
1175 | put_transaction(cur_trans); | 1260 | put_transaction(cur_trans); |
1176 | 1261 | ||
1177 | return 0; | 1262 | return ret; |
1178 | } | 1263 | } |
1179 | 1264 | ||
1180 | trans->transaction->in_commit = 1; | 1265 | trans->transaction->in_commit = 1; |
@@ -1218,7 +1303,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1218 | } | 1303 | } |
1219 | 1304 | ||
1220 | ret = btrfs_run_delayed_items(trans, root); | 1305 | ret = btrfs_run_delayed_items(trans, root); |
1221 | BUG_ON(ret); | 1306 | if (ret) |
1307 | goto cleanup_transaction; | ||
1222 | 1308 | ||
1223 | /* | 1309 | /* |
1224 | * rename don't use btrfs_join_transaction, so, once we | 1310 | * rename don't use btrfs_join_transaction, so, once we |
@@ -1260,13 +1346,22 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1260 | mutex_lock(&root->fs_info->reloc_mutex); | 1346 | mutex_lock(&root->fs_info->reloc_mutex); |
1261 | 1347 | ||
1262 | ret = btrfs_run_delayed_items(trans, root); | 1348 | ret = btrfs_run_delayed_items(trans, root); |
1263 | BUG_ON(ret); | 1349 | if (ret) { |
1350 | mutex_unlock(&root->fs_info->reloc_mutex); | ||
1351 | goto cleanup_transaction; | ||
1352 | } | ||
1264 | 1353 | ||
1265 | ret = create_pending_snapshots(trans, root->fs_info); | 1354 | ret = create_pending_snapshots(trans, root->fs_info); |
1266 | BUG_ON(ret); | 1355 | if (ret) { |
1356 | mutex_unlock(&root->fs_info->reloc_mutex); | ||
1357 | goto cleanup_transaction; | ||
1358 | } | ||
1267 | 1359 | ||
1268 | ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1); | 1360 | ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1); |
1269 | BUG_ON(ret); | 1361 | if (ret) { |
1362 | mutex_unlock(&root->fs_info->reloc_mutex); | ||
1363 | goto cleanup_transaction; | ||
1364 | } | ||
1270 | 1365 | ||
1271 | /* | 1366 | /* |
1272 | * make sure none of the code above managed to slip in a | 1367 | * make sure none of the code above managed to slip in a |
@@ -1293,7 +1388,10 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1293 | mutex_lock(&root->fs_info->tree_log_mutex); | 1388 | mutex_lock(&root->fs_info->tree_log_mutex); |
1294 | 1389 | ||
1295 | ret = commit_fs_roots(trans, root); | 1390 | ret = commit_fs_roots(trans, root); |
1296 | BUG_ON(ret); | 1391 | if (ret) { |
1392 | mutex_unlock(&root->fs_info->tree_log_mutex); | ||
1393 | goto cleanup_transaction; | ||
1394 | } | ||
1297 | 1395 | ||
1298 | /* commit_fs_roots gets rid of all the tree log roots, it is now | 1396 | /* commit_fs_roots gets rid of all the tree log roots, it is now |
1299 | * safe to free the root of tree log roots | 1397 | * safe to free the root of tree log roots |
@@ -1301,7 +1399,10 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1301 | btrfs_free_log_root_tree(trans, root->fs_info); | 1399 | btrfs_free_log_root_tree(trans, root->fs_info); |
1302 | 1400 | ||
1303 | ret = commit_cowonly_roots(trans, root); | 1401 | ret = commit_cowonly_roots(trans, root); |
1304 | BUG_ON(ret); | 1402 | if (ret) { |
1403 | mutex_unlock(&root->fs_info->tree_log_mutex); | ||
1404 | goto cleanup_transaction; | ||
1405 | } | ||
1305 | 1406 | ||
1306 | btrfs_prepare_extent_commit(trans, root); | 1407 | btrfs_prepare_extent_commit(trans, root); |
1307 | 1408 | ||
@@ -1335,8 +1436,18 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1335 | wake_up(&root->fs_info->transaction_wait); | 1436 | wake_up(&root->fs_info->transaction_wait); |
1336 | 1437 | ||
1337 | ret = btrfs_write_and_wait_transaction(trans, root); | 1438 | ret = btrfs_write_and_wait_transaction(trans, root); |
1338 | BUG_ON(ret); | 1439 | if (ret) { |
1339 | write_ctree_super(trans, root, 0); | 1440 | btrfs_error(root->fs_info, ret, |
1441 | "Error while writing out transaction."); | ||
1442 | mutex_unlock(&root->fs_info->tree_log_mutex); | ||
1443 | goto cleanup_transaction; | ||
1444 | } | ||
1445 | |||
1446 | ret = write_ctree_super(trans, root, 0); | ||
1447 | if (ret) { | ||
1448 | mutex_unlock(&root->fs_info->tree_log_mutex); | ||
1449 | goto cleanup_transaction; | ||
1450 | } | ||
1340 | 1451 | ||
1341 | /* | 1452 | /* |
1342 | * the super is written, we can safely allow the tree-loggers | 1453 | * the super is written, we can safely allow the tree-loggers |
@@ -1372,6 +1483,15 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1372 | btrfs_run_delayed_iputs(root); | 1483 | btrfs_run_delayed_iputs(root); |
1373 | 1484 | ||
1374 | return ret; | 1485 | return ret; |
1486 | |||
1487 | cleanup_transaction: | ||
1488 | btrfs_printk(root->fs_info, "Skipping commit of aborted transaction.\n"); | ||
1489 | // WARN_ON(1); | ||
1490 | if (current->journal_info == trans) | ||
1491 | current->journal_info = NULL; | ||
1492 | cleanup_transaction(trans, root); | ||
1493 | |||
1494 | return ret; | ||
1375 | } | 1495 | } |
1376 | 1496 | ||
1377 | /* | 1497 | /* |
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h index 02564e6230ac..fe27379e368b 100644 --- a/fs/btrfs/transaction.h +++ b/fs/btrfs/transaction.h | |||
@@ -43,6 +43,7 @@ struct btrfs_transaction { | |||
43 | wait_queue_head_t commit_wait; | 43 | wait_queue_head_t commit_wait; |
44 | struct list_head pending_snapshots; | 44 | struct list_head pending_snapshots; |
45 | struct btrfs_delayed_ref_root delayed_refs; | 45 | struct btrfs_delayed_ref_root delayed_refs; |
46 | int aborted; | ||
46 | }; | 47 | }; |
47 | 48 | ||
48 | struct btrfs_trans_handle { | 49 | struct btrfs_trans_handle { |
@@ -55,6 +56,7 @@ struct btrfs_trans_handle { | |||
55 | struct btrfs_transaction *transaction; | 56 | struct btrfs_transaction *transaction; |
56 | struct btrfs_block_rsv *block_rsv; | 57 | struct btrfs_block_rsv *block_rsv; |
57 | struct btrfs_block_rsv *orig_rsv; | 58 | struct btrfs_block_rsv *orig_rsv; |
59 | int aborted; | ||
58 | }; | 60 | }; |
59 | 61 | ||
60 | struct btrfs_pending_snapshot { | 62 | struct btrfs_pending_snapshot { |
@@ -114,4 +116,5 @@ int btrfs_wait_marked_extents(struct btrfs_root *root, | |||
114 | struct extent_io_tree *dirty_pages, int mark); | 116 | struct extent_io_tree *dirty_pages, int mark); |
115 | int btrfs_transaction_blocked(struct btrfs_fs_info *info); | 117 | int btrfs_transaction_blocked(struct btrfs_fs_info *info); |
116 | int btrfs_transaction_in_commit(struct btrfs_fs_info *info); | 118 | int btrfs_transaction_in_commit(struct btrfs_fs_info *info); |
119 | void put_transaction(struct btrfs_transaction *transaction); | ||
117 | #endif | 120 | #endif |