diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2022-07-22 06:57:05 -0400 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2023-10-22 17:09:37 -0400 |
commit | 0763c552e7ef024ce6dbc9cbc828b8715dff251c (patch) | |
tree | 8d4239967ad130502865800b8ba7db8c363c6305 | |
parent | 91f1b9fdd2c02a7375e46bb2628870f3c6116072 (diff) | |
download | linux-stable-0763c552e7ef024ce6dbc9cbc828b8715dff251c.tar.gz linux-stable-0763c552e7ef024ce6dbc9cbc828b8715dff251c.tar.bz2 linux-stable-0763c552e7ef024ce6dbc9cbc828b8715dff251c.zip |
bcachefs: fsck: Fix nested transaction handling
This uses the new trans->restart count to make sure we always correctly
return -BCH_ERR_transaction_restart_nested when we restart a nested
transaction - eliminating some other hacks and preparing for new
assertions.
Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
-rw-r--r-- | fs/bcachefs/fsck.c | 43 |
1 files changed, 23 insertions, 20 deletions
diff --git a/fs/bcachefs/fsck.c b/fs/bcachefs/fsck.c index ea264421fe8f..bb8cab7cb405 100644 --- a/fs/bcachefs/fsck.c +++ b/fs/bcachefs/fsck.c @@ -650,6 +650,7 @@ static int __walk_inode(struct btree_trans *trans, struct bch_fs *c = trans->c; struct btree_iter iter; struct bkey_s_c k; + u32 restart_count = trans->restart_count; unsigned i; int ret; @@ -677,6 +678,10 @@ static int __walk_inode(struct btree_trans *trans, w->cur_inum = pos.inode; w->first_this_inode = true; + + if (trans_was_restarted(trans, restart_count)) + return -BCH_ERR_transaction_restart_nested; + lookup_snapshot: for (i = 0; i < w->inodes.nr; i++) if (bch2_snapshot_is_ancestor(c, pos.snapshot, w->inodes.data[i].snapshot)) @@ -1115,7 +1120,8 @@ static int check_i_sectors(struct btree_trans *trans, struct inode_walker *w) { struct bch_fs *c = trans->c; struct inode_walker_entry *i; - int ret = 0, ret2 = 0; + u32 restart_count = trans->restart_count; + int ret = 0; s64 count2; darray_for_each(w->inodes, i) { @@ -1140,13 +1146,16 @@ static int check_i_sectors(struct btree_trans *trans, struct inode_walker *w) ret = write_inode(trans, &i->inode, i->snapshot); if (ret) break; - ret2 = -BCH_ERR_transaction_restart_nested; } } fsck_err: - if (ret) + if (ret) { bch_err(c, "error from check_i_sectors(): %s", bch2_err_str(ret)); - return ret ?: ret2; + return ret; + } + if (trans_was_restarted(trans, restart_count)) + return -BCH_ERR_transaction_restart_nested; + return 0; } static int check_extent(struct btree_trans *trans, struct btree_iter *iter, @@ -1182,14 +1191,7 @@ static int check_extent(struct btree_trans *trans, struct btree_iter *iter, goto err; } - if (!iter->path->should_be_locked) { - /* - * hack: check_i_sectors may have handled a transaction restart, - * it shouldn't be but we need to fix the new i_sectors check - * code and delete the old bch2_count_inode_sectors() first - */ - return -BCH_ERR_transaction_restart_nested; - } + BUG_ON(!iter->path->should_be_locked); #if 0 if (bkey_cmp(prev.k->k.p, bkey_start_pos(k.k)) > 0) { char buf1[200]; @@ -1336,7 +1338,8 @@ static int check_subdir_count(struct btree_trans *trans, struct inode_walker *w) { struct bch_fs *c = trans->c; struct inode_walker_entry *i; - int ret = 0, ret2 = 0; + u32 restart_count = trans->restart_count; + int ret = 0; s64 count2; darray_for_each(w->inodes, i) { @@ -1362,13 +1365,16 @@ static int check_subdir_count(struct btree_trans *trans, struct inode_walker *w) ret = write_inode(trans, &i->inode, i->snapshot); if (ret) break; - ret2 = -BCH_ERR_transaction_restart_nested; } } fsck_err: - if (ret) + if (ret) { bch_err(c, "error from check_subdir_count(): %s", bch2_err_str(ret)); - return ret ?: ret2; + return ret; + } + if (trans_was_restarted(trans, restart_count)) + return -BCH_ERR_transaction_restart_nested; + return 0; } static int check_dirent_target(struct btree_trans *trans, @@ -1526,10 +1532,7 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter, goto err; } - if (!iter->path->should_be_locked) { - /* hack: see check_extent() */ - return -BCH_ERR_transaction_restart_nested; - } + BUG_ON(!iter->path->should_be_locked); ret = __walk_inode(trans, dir, equiv); if (ret < 0) |