Skip to content

Commit 49b25e0

Browse files
jeffmahoneykdave
authored andcommitted
btrfs: enhance transaction abort infrastructure
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
1 parent 4da3511 commit 49b25e0

File tree

8 files changed

+300
-56
lines changed

8 files changed

+300
-56
lines changed

fs/btrfs/ctree.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2968,6 +2968,16 @@ void btrfs_printk(struct btrfs_fs_info *fs_info, const char *fmt, ...);
29682968
void __btrfs_std_error(struct btrfs_fs_info *fs_info, const char *function,
29692969
unsigned int line, int errno, const char *fmt, ...);
29702970

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+
29712981
#define btrfs_std_error(fs_info, errno) \
29722982
do { \
29732983
if ((errno)) \
@@ -3024,7 +3034,7 @@ void btrfs_reloc_cow_block(struct btrfs_trans_handle *trans,
30243034
void btrfs_reloc_pre_snapshot(struct btrfs_trans_handle *trans,
30253035
struct btrfs_pending_snapshot *pending,
30263036
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,
30283038
struct btrfs_pending_snapshot *pending);
30293039

30303040
/* scrub.c */
@@ -3034,6 +3044,7 @@ void btrfs_scrub_pause(struct btrfs_root *root);
30343044
void btrfs_scrub_pause_super(struct btrfs_root *root);
30353045
void btrfs_scrub_continue(struct btrfs_root *root);
30363046
void btrfs_scrub_continue_super(struct btrfs_root *root);
3047+
int __btrfs_scrub_cancel(struct btrfs_fs_info *info);
30373048
int btrfs_scrub_cancel(struct btrfs_root *root);
30383049
int btrfs_scrub_cancel_dev(struct btrfs_root *root, struct btrfs_device *dev);
30393050
int btrfs_scrub_cancel_devid(struct btrfs_root *root, u64 devid);

fs/btrfs/disk-io.c

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ static int btrfs_destroy_marked_extents(struct btrfs_root *root,
6161
int mark);
6262
static int btrfs_destroy_pinned_extent(struct btrfs_root *root,
6363
struct extent_io_tree *pinned_extents);
64-
static int btrfs_cleanup_transaction(struct btrfs_root *root);
6564

6665
/*
6766
* 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,
28962895
return ret;
28972896
}
28982897

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+
28992911
void btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root)
29002912
{
29012913
spin_lock(&fs_info->fs_roots_radix_lock);
@@ -3536,13 +3548,43 @@ static int btrfs_destroy_pinned_extent(struct btrfs_root *root,
35363548
return 0;
35373549
}
35383550

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)
35403584
{
35413585
struct btrfs_transaction *t;
35423586
LIST_HEAD(list);
35433587

3544-
WARN_ON(1);
3545-
35463588
mutex_lock(&root->fs_info->transaction_kthread_mutex);
35473589

35483590
spin_lock(&root->fs_info->trans_lock);

fs/btrfs/disk-io.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ int btrfs_init_log_root_tree(struct btrfs_trans_handle *trans,
8585
struct btrfs_fs_info *fs_info);
8686
int btrfs_add_log_tree(struct btrfs_trans_handle *trans,
8787
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);
8892

8993
#ifdef CONFIG_DEBUG_LOCK_ALLOC
9094
void btrfs_init_lockdep(void);

fs/btrfs/relocation.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4410,7 +4410,7 @@ void btrfs_reloc_pre_snapshot(struct btrfs_trans_handle *trans,
44104410
* called after snapshot is created. migrate block reservation
44114411
* and create reloc root for the newly created snapshot
44124412
*/
4413-
void btrfs_reloc_post_snapshot(struct btrfs_trans_handle *trans,
4413+
int btrfs_reloc_post_snapshot(struct btrfs_trans_handle *trans,
44144414
struct btrfs_pending_snapshot *pending)
44154415
{
44164416
struct btrfs_root *root = pending->root;
@@ -4420,7 +4420,7 @@ void btrfs_reloc_post_snapshot(struct btrfs_trans_handle *trans,
44204420
int ret;
44214421

44224422
if (!root->reloc_root)
4423-
return;
4423+
return 0;
44244424

44254425
rc = root->fs_info->reloc_ctl;
44264426
rc->merging_rsv_size += rc->nodes_relocated;
@@ -4429,19 +4429,21 @@ void btrfs_reloc_post_snapshot(struct btrfs_trans_handle *trans,
44294429
ret = btrfs_block_rsv_migrate(&pending->block_rsv,
44304430
rc->block_rsv,
44314431
rc->nodes_relocated);
4432-
BUG_ON(ret);
4432+
if (ret)
4433+
return ret;
44334434
}
44344435

44354436
new_root = pending->snap;
44364437
reloc_root = create_reloc_root(trans, root->reloc_root,
44374438
new_root->root_key.objectid);
4439+
if (IS_ERR(reloc_root))
4440+
return PTR_ERR(reloc_root);
44384441

44394442
ret = __add_reloc_root(reloc_root);
44404443
BUG_ON(ret < 0);
44414444
new_root->reloc_root = reloc_root;
44424445

4443-
if (rc->create_reloc_tree) {
4446+
if (rc->create_reloc_tree)
44444447
ret = clone_backref_node(trans, rc, root, reloc_root);
4445-
BUG_ON(ret);
4446-
}
4448+
return ret;
44474449
}

fs/btrfs/scrub.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1680,9 +1680,8 @@ void btrfs_scrub_continue_super(struct btrfs_root *root)
16801680
up_write(&root->fs_info->scrub_super_lock);
16811681
}
16821682

1683-
int btrfs_scrub_cancel(struct btrfs_root *root)
1683+
int __btrfs_scrub_cancel(struct btrfs_fs_info *fs_info)
16841684
{
1685-
struct btrfs_fs_info *fs_info = root->fs_info;
16861685

16871686
mutex_lock(&fs_info->scrub_lock);
16881687
if (!atomic_read(&fs_info->scrubs_running)) {
@@ -1703,6 +1702,11 @@ int btrfs_scrub_cancel(struct btrfs_root *root)
17031702
return 0;
17041703
}
17051704

1705+
int btrfs_scrub_cancel(struct btrfs_root *root)
1706+
{
1707+
return __btrfs_scrub_cancel(root->fs_info);
1708+
}
1709+
17061710
int btrfs_scrub_cancel_dev(struct btrfs_root *root, struct btrfs_device *dev)
17071711
{
17081712
struct btrfs_fs_info *fs_info = root->fs_info;

fs/btrfs/super.c

Lines changed: 66 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ static void btrfs_handle_error(struct btrfs_fs_info *fs_info)
119119
if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) {
120120
sb->s_flags |= MS_RDONLY;
121121
printk(KERN_INFO "btrfs is forced readonly\n");
122+
__btrfs_scrub_cancel(fs_info);
123+
// WARN_ON(1);
122124
}
123125
}
124126

@@ -197,6 +199,34 @@ void btrfs_printk(struct btrfs_fs_info *fs_info, const char *fmt, ...)
197199
printk("%sBTRFS %s (device %s): %pV", lvl, type, sb->s_id, &vaf);
198200
}
199201

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+
}
200230
/*
201231
* __btrfs_panic decodes unexpected, fatal errors from the caller,
202232
* issues an alert, and either panics or BUGs, depending on mount options.
@@ -295,6 +325,7 @@ static match_table_t tokens = {
295325
/*
296326
* Regular mount options parser. Everything that is needed only when
297327
* reading in a new superblock is parsed here.
328+
* XXX JDM: This needs to be cleaned up for remount.
298329
*/
299330
int btrfs_parse_options(struct btrfs_root *root, char *options)
300331
{
@@ -1096,38 +1127,65 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
10961127
{
10971128
struct btrfs_fs_info *fs_info = btrfs_sb(sb);
10981129
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;
10991137
int ret;
11001138

11011139
ret = btrfs_parse_options(root, data);
1102-
if (ret)
1103-
return -EINVAL;
1140+
if (ret) {
1141+
ret = -EINVAL;
1142+
goto restore;
1143+
}
11041144

11051145
if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
11061146
return 0;
11071147

11081148
if (*flags & MS_RDONLY) {
11091149
sb->s_flags |= MS_RDONLY;
11101150

1111-
ret = btrfs_commit_super(root);
1112-
WARN_ON(ret);
1151+
ret = btrfs_commit_super(root);
1152+
if (ret)
1153+
goto restore;
11131154
} else {
11141155
if (fs_info->fs_devices->rw_devices == 0)
1115-
return -EACCES;
1156+
ret = -EACCES;
1157+
goto restore;
11161158

11171159
if (btrfs_super_log_root(fs_info->super_copy) != 0)
1118-
return -EINVAL;
1160+
ret = -EINVAL;
1161+
goto restore;
11191162

11201163
ret = btrfs_cleanup_fs_roots(fs_info);
1121-
WARN_ON(ret);
1164+
if (ret)
1165+
goto restore;
11221166

11231167
/* recover relocation */
11241168
ret = btrfs_recover_relocation(root);
1125-
WARN_ON(ret);
1169+
if (ret)
1170+
goto restore;
11261171

11271172
sb->s_flags &= ~MS_RDONLY;
11281173
}
11291174

11301175
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;
11311189
}
11321190

11331191
/* Used to sort the devices by max_avail(descending sort) */

0 commit comments

Comments
 (0)