mirror of
https://github.com/torvalds/linux.git
synced 2024-11-21 19:41:42 +00:00
bcachefs: Rework logged op error handling
Initially it was thought that we just wanted to ignore errors from logged op replay, but it turns out we do need to catch -EROFS, or we'll go into an infinite loop. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
1f73cb4d34
commit
0f25eb4b60
@ -224,13 +224,14 @@ void bch2_logged_op_truncate_to_text(struct printbuf *out, struct bch_fs *c, str
|
||||
|
||||
static int truncate_set_isize(struct btree_trans *trans,
|
||||
subvol_inum inum,
|
||||
u64 new_i_size)
|
||||
u64 new_i_size,
|
||||
bool warn)
|
||||
{
|
||||
struct btree_iter iter = { NULL };
|
||||
struct bch_inode_unpacked inode_u;
|
||||
int ret;
|
||||
|
||||
ret = bch2_inode_peek(trans, &iter, &inode_u, inum, BTREE_ITER_intent) ?:
|
||||
ret = __bch2_inode_peek(trans, &iter, &inode_u, inum, BTREE_ITER_intent, warn) ?:
|
||||
(inode_u.bi_size = new_i_size, 0) ?:
|
||||
bch2_inode_write(trans, &iter, &inode_u);
|
||||
|
||||
@ -247,10 +248,11 @@ static int __bch2_resume_logged_op_truncate(struct btree_trans *trans,
|
||||
struct bkey_i_logged_op_truncate *op = bkey_i_to_logged_op_truncate(op_k);
|
||||
subvol_inum inum = { le32_to_cpu(op->v.subvol), le64_to_cpu(op->v.inum) };
|
||||
u64 new_i_size = le64_to_cpu(op->v.new_i_size);
|
||||
bool warn_errors = i_sectors_delta != NULL;
|
||||
int ret;
|
||||
|
||||
ret = commit_do(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc,
|
||||
truncate_set_isize(trans, inum, new_i_size));
|
||||
truncate_set_isize(trans, inum, new_i_size, i_sectors_delta != NULL));
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
@ -263,7 +265,7 @@ static int __bch2_resume_logged_op_truncate(struct btree_trans *trans,
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
ret = 0;
|
||||
err:
|
||||
bch2_logged_op_finish(trans, op_k);
|
||||
if (warn_errors)
|
||||
bch_err_fn(c, ret);
|
||||
return ret;
|
||||
}
|
||||
@ -288,9 +290,14 @@ int bch2_truncate(struct bch_fs *c, subvol_inum inum, u64 new_i_size, u64 *i_sec
|
||||
* resume only proceeding in one of the snapshots
|
||||
*/
|
||||
down_read(&c->snapshot_create_lock);
|
||||
int ret = bch2_trans_run(c,
|
||||
bch2_logged_op_start(trans, &op.k_i) ?:
|
||||
__bch2_resume_logged_op_truncate(trans, &op.k_i, i_sectors_delta));
|
||||
struct btree_trans *trans = bch2_trans_get(c);
|
||||
int ret = bch2_logged_op_start(trans, &op.k_i);
|
||||
if (ret)
|
||||
goto out;
|
||||
ret = __bch2_resume_logged_op_truncate(trans, &op.k_i, i_sectors_delta);
|
||||
ret = bch2_logged_op_finish(trans, &op.k_i) ?: ret;
|
||||
out:
|
||||
bch2_trans_put(trans);
|
||||
up_read(&c->snapshot_create_lock);
|
||||
|
||||
return ret;
|
||||
@ -308,7 +315,8 @@ void bch2_logged_op_finsert_to_text(struct printbuf *out, struct bch_fs *c, stru
|
||||
prt_printf(out, " src_offset=%llu", le64_to_cpu(op.v->src_offset));
|
||||
}
|
||||
|
||||
static int adjust_i_size(struct btree_trans *trans, subvol_inum inum, u64 offset, s64 len)
|
||||
static int adjust_i_size(struct btree_trans *trans, subvol_inum inum,
|
||||
u64 offset, s64 len, bool warn)
|
||||
{
|
||||
struct btree_iter iter;
|
||||
struct bch_inode_unpacked inode_u;
|
||||
@ -317,7 +325,7 @@ static int adjust_i_size(struct btree_trans *trans, subvol_inum inum, u64 offset
|
||||
offset <<= 9;
|
||||
len <<= 9;
|
||||
|
||||
ret = bch2_inode_peek(trans, &iter, &inode_u, inum, BTREE_ITER_intent);
|
||||
ret = __bch2_inode_peek(trans, &iter, &inode_u, inum, BTREE_ITER_intent, warn);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -357,12 +365,22 @@ static int __bch2_resume_logged_op_finsert(struct btree_trans *trans,
|
||||
u64 len = abs(shift);
|
||||
u64 pos = le64_to_cpu(op->v.pos);
|
||||
bool insert = shift > 0;
|
||||
u32 snapshot;
|
||||
bool warn_errors = i_sectors_delta != NULL;
|
||||
int ret = 0;
|
||||
|
||||
ret = bch2_inum_opts_get(trans, inum, &opts);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* check for missing subvolume before fpunch, as in resume we don't want
|
||||
* it to be a fatal error
|
||||
*/
|
||||
ret = __bch2_subvolume_get_snapshot(trans, inum.subvol, &snapshot, warn_errors);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
bch2_trans_iter_init(trans, &iter, BTREE_ID_extents,
|
||||
POS(inum.inum, 0),
|
||||
BTREE_ITER_intent);
|
||||
@ -373,7 +391,7 @@ case LOGGED_OP_FINSERT_start:
|
||||
|
||||
if (insert) {
|
||||
ret = commit_do(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc,
|
||||
adjust_i_size(trans, inum, src_offset, len) ?:
|
||||
adjust_i_size(trans, inum, src_offset, len, warn_errors) ?:
|
||||
bch2_logged_op_update(trans, &op->k_i));
|
||||
if (ret)
|
||||
goto err;
|
||||
@ -396,11 +414,11 @@ case LOGGED_OP_FINSERT_shift_extents:
|
||||
struct bkey_i delete, *copy;
|
||||
struct bkey_s_c k;
|
||||
struct bpos src_pos = POS(inum.inum, src_offset);
|
||||
u32 snapshot;
|
||||
|
||||
bch2_trans_begin(trans);
|
||||
|
||||
ret = bch2_subvolume_get_snapshot(trans, inum.subvol, &snapshot);
|
||||
ret = __bch2_subvolume_get_snapshot(trans, inum.subvol, &snapshot,
|
||||
warn_errors);
|
||||
if (ret)
|
||||
goto btree_err;
|
||||
|
||||
@ -463,12 +481,12 @@ btree_err:
|
||||
|
||||
if (!insert) {
|
||||
ret = commit_do(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc,
|
||||
adjust_i_size(trans, inum, src_offset, shift) ?:
|
||||
adjust_i_size(trans, inum, src_offset, shift, warn_errors) ?:
|
||||
bch2_logged_op_update(trans, &op->k_i));
|
||||
} else {
|
||||
/* We need an inode update to update bi_journal_seq for fsync: */
|
||||
ret = commit_do(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc,
|
||||
adjust_i_size(trans, inum, 0, 0) ?:
|
||||
adjust_i_size(trans, inum, 0, 0, warn_errors) ?:
|
||||
bch2_logged_op_update(trans, &op->k_i));
|
||||
}
|
||||
|
||||
@ -477,9 +495,9 @@ case LOGGED_OP_FINSERT_finish:
|
||||
break;
|
||||
}
|
||||
err:
|
||||
bch_err_fn(c, ret);
|
||||
bch2_logged_op_finish(trans, op_k);
|
||||
bch2_trans_iter_exit(trans, &iter);
|
||||
if (warn_errors)
|
||||
bch_err_fn(c, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -508,9 +526,14 @@ int bch2_fcollapse_finsert(struct bch_fs *c, subvol_inum inum,
|
||||
* resume only proceeding in one of the snapshots
|
||||
*/
|
||||
down_read(&c->snapshot_create_lock);
|
||||
int ret = bch2_trans_run(c,
|
||||
bch2_logged_op_start(trans, &op.k_i) ?:
|
||||
__bch2_resume_logged_op_finsert(trans, &op.k_i, i_sectors_delta));
|
||||
struct btree_trans *trans = bch2_trans_get(c);
|
||||
int ret = bch2_logged_op_start(trans, &op.k_i);
|
||||
if (ret)
|
||||
goto out;
|
||||
ret = __bch2_resume_logged_op_finsert(trans, &op.k_i, i_sectors_delta);
|
||||
ret = bch2_logged_op_finish(trans, &op.k_i) ?: ret;
|
||||
out:
|
||||
bch2_trans_put(trans);
|
||||
up_read(&c->snapshot_create_lock);
|
||||
|
||||
return ret;
|
||||
|
@ -34,8 +34,6 @@ static int resume_logged_op(struct btree_trans *trans, struct btree_iter *iter,
|
||||
struct bkey_s_c k)
|
||||
{
|
||||
struct bch_fs *c = trans->c;
|
||||
const struct bch_logged_op_fn *fn = logged_op_fn(k.k->type);
|
||||
struct bkey_buf sk;
|
||||
u32 restart_count = trans->restart_count;
|
||||
struct printbuf buf = PRINTBUF;
|
||||
int ret = 0;
|
||||
@ -46,14 +44,16 @@ static int resume_logged_op(struct btree_trans *trans, struct btree_iter *iter,
|
||||
(bch2_bkey_val_to_text(&buf, c, k),
|
||||
buf.buf));
|
||||
|
||||
if (!fn)
|
||||
return 0;
|
||||
|
||||
struct bkey_buf sk;
|
||||
bch2_bkey_buf_init(&sk);
|
||||
bch2_bkey_buf_reassemble(&sk, c, k);
|
||||
|
||||
const struct bch_logged_op_fn *fn = logged_op_fn(sk.k->k.type);
|
||||
if (fn)
|
||||
fn->resume(trans, sk.k);
|
||||
|
||||
ret = bch2_logged_op_finish(trans, sk.k);
|
||||
|
||||
bch2_bkey_buf_exit(&sk, c);
|
||||
fsck_err:
|
||||
printbuf_exit(&buf);
|
||||
@ -93,7 +93,7 @@ int bch2_logged_op_start(struct btree_trans *trans, struct bkey_i *k)
|
||||
__bch2_logged_op_start(trans, k));
|
||||
}
|
||||
|
||||
void bch2_logged_op_finish(struct btree_trans *trans, struct bkey_i *k)
|
||||
int bch2_logged_op_finish(struct btree_trans *trans, struct bkey_i *k)
|
||||
{
|
||||
int ret = commit_do(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc,
|
||||
bch2_btree_delete(trans, BTREE_ID_logged_ops, k->k.p, 0));
|
||||
@ -113,4 +113,6 @@ void bch2_logged_op_finish(struct btree_trans *trans, struct bkey_i *k)
|
||||
buf.buf, bch2_err_str(ret));
|
||||
printbuf_exit(&buf);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -15,6 +15,6 @@ static inline int bch2_logged_op_update(struct btree_trans *trans, struct bkey_i
|
||||
|
||||
int bch2_resume_logged_ops(struct bch_fs *);
|
||||
int bch2_logged_op_start(struct btree_trans *, struct bkey_i *);
|
||||
void bch2_logged_op_finish(struct btree_trans *, struct bkey_i *);
|
||||
int bch2_logged_op_finish(struct btree_trans *, struct bkey_i *);
|
||||
|
||||
#endif /* _BCACHEFS_LOGGED_OPS_H */
|
||||
|
Loading…
Reference in New Issue
Block a user