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,
|
static int truncate_set_isize(struct btree_trans *trans,
|
||||||
subvol_inum inum,
|
subvol_inum inum,
|
||||||
u64 new_i_size)
|
u64 new_i_size,
|
||||||
|
bool warn)
|
||||||
{
|
{
|
||||||
struct btree_iter iter = { NULL };
|
struct btree_iter iter = { NULL };
|
||||||
struct bch_inode_unpacked inode_u;
|
struct bch_inode_unpacked inode_u;
|
||||||
int ret;
|
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) ?:
|
(inode_u.bi_size = new_i_size, 0) ?:
|
||||||
bch2_inode_write(trans, &iter, &inode_u);
|
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);
|
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) };
|
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);
|
u64 new_i_size = le64_to_cpu(op->v.new_i_size);
|
||||||
|
bool warn_errors = i_sectors_delta != NULL;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = commit_do(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc,
|
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)
|
if (ret)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
@ -263,8 +265,8 @@ static int __bch2_resume_logged_op_truncate(struct btree_trans *trans,
|
|||||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||||
ret = 0;
|
ret = 0;
|
||||||
err:
|
err:
|
||||||
bch2_logged_op_finish(trans, op_k);
|
if (warn_errors)
|
||||||
bch_err_fn(c, ret);
|
bch_err_fn(c, ret);
|
||||||
return 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
|
* resume only proceeding in one of the snapshots
|
||||||
*/
|
*/
|
||||||
down_read(&c->snapshot_create_lock);
|
down_read(&c->snapshot_create_lock);
|
||||||
int ret = bch2_trans_run(c,
|
struct btree_trans *trans = bch2_trans_get(c);
|
||||||
bch2_logged_op_start(trans, &op.k_i) ?:
|
int ret = bch2_logged_op_start(trans, &op.k_i);
|
||||||
__bch2_resume_logged_op_truncate(trans, &op.k_i, i_sectors_delta));
|
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);
|
up_read(&c->snapshot_create_lock);
|
||||||
|
|
||||||
return ret;
|
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));
|
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 btree_iter iter;
|
||||||
struct bch_inode_unpacked inode_u;
|
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;
|
offset <<= 9;
|
||||||
len <<= 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)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@ -357,12 +365,22 @@ static int __bch2_resume_logged_op_finsert(struct btree_trans *trans,
|
|||||||
u64 len = abs(shift);
|
u64 len = abs(shift);
|
||||||
u64 pos = le64_to_cpu(op->v.pos);
|
u64 pos = le64_to_cpu(op->v.pos);
|
||||||
bool insert = shift > 0;
|
bool insert = shift > 0;
|
||||||
|
u32 snapshot;
|
||||||
|
bool warn_errors = i_sectors_delta != NULL;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
ret = bch2_inum_opts_get(trans, inum, &opts);
|
ret = bch2_inum_opts_get(trans, inum, &opts);
|
||||||
if (ret)
|
if (ret)
|
||||||
return 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,
|
bch2_trans_iter_init(trans, &iter, BTREE_ID_extents,
|
||||||
POS(inum.inum, 0),
|
POS(inum.inum, 0),
|
||||||
BTREE_ITER_intent);
|
BTREE_ITER_intent);
|
||||||
@ -373,7 +391,7 @@ case LOGGED_OP_FINSERT_start:
|
|||||||
|
|
||||||
if (insert) {
|
if (insert) {
|
||||||
ret = commit_do(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc,
|
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));
|
bch2_logged_op_update(trans, &op->k_i));
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err;
|
goto err;
|
||||||
@ -396,11 +414,11 @@ case LOGGED_OP_FINSERT_shift_extents:
|
|||||||
struct bkey_i delete, *copy;
|
struct bkey_i delete, *copy;
|
||||||
struct bkey_s_c k;
|
struct bkey_s_c k;
|
||||||
struct bpos src_pos = POS(inum.inum, src_offset);
|
struct bpos src_pos = POS(inum.inum, src_offset);
|
||||||
u32 snapshot;
|
|
||||||
|
|
||||||
bch2_trans_begin(trans);
|
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)
|
if (ret)
|
||||||
goto btree_err;
|
goto btree_err;
|
||||||
|
|
||||||
@ -463,12 +481,12 @@ btree_err:
|
|||||||
|
|
||||||
if (!insert) {
|
if (!insert) {
|
||||||
ret = commit_do(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc,
|
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));
|
bch2_logged_op_update(trans, &op->k_i));
|
||||||
} else {
|
} else {
|
||||||
/* We need an inode update to update bi_journal_seq for fsync: */
|
/* We need an inode update to update bi_journal_seq for fsync: */
|
||||||
ret = commit_do(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc,
|
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));
|
bch2_logged_op_update(trans, &op->k_i));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -477,9 +495,9 @@ case LOGGED_OP_FINSERT_finish:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
err:
|
err:
|
||||||
bch_err_fn(c, ret);
|
|
||||||
bch2_logged_op_finish(trans, op_k);
|
|
||||||
bch2_trans_iter_exit(trans, &iter);
|
bch2_trans_iter_exit(trans, &iter);
|
||||||
|
if (warn_errors)
|
||||||
|
bch_err_fn(c, ret);
|
||||||
return 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
|
* resume only proceeding in one of the snapshots
|
||||||
*/
|
*/
|
||||||
down_read(&c->snapshot_create_lock);
|
down_read(&c->snapshot_create_lock);
|
||||||
int ret = bch2_trans_run(c,
|
struct btree_trans *trans = bch2_trans_get(c);
|
||||||
bch2_logged_op_start(trans, &op.k_i) ?:
|
int ret = bch2_logged_op_start(trans, &op.k_i);
|
||||||
__bch2_resume_logged_op_finsert(trans, &op.k_i, i_sectors_delta));
|
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);
|
up_read(&c->snapshot_create_lock);
|
||||||
|
|
||||||
return ret;
|
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 bkey_s_c k)
|
||||||
{
|
{
|
||||||
struct bch_fs *c = trans->c;
|
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;
|
u32 restart_count = trans->restart_count;
|
||||||
struct printbuf buf = PRINTBUF;
|
struct printbuf buf = PRINTBUF;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
@ -46,13 +44,15 @@ static int resume_logged_op(struct btree_trans *trans, struct btree_iter *iter,
|
|||||||
(bch2_bkey_val_to_text(&buf, c, k),
|
(bch2_bkey_val_to_text(&buf, c, k),
|
||||||
buf.buf));
|
buf.buf));
|
||||||
|
|
||||||
if (!fn)
|
struct bkey_buf sk;
|
||||||
return 0;
|
|
||||||
|
|
||||||
bch2_bkey_buf_init(&sk);
|
bch2_bkey_buf_init(&sk);
|
||||||
bch2_bkey_buf_reassemble(&sk, c, k);
|
bch2_bkey_buf_reassemble(&sk, c, k);
|
||||||
|
|
||||||
fn->resume(trans, sk.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);
|
bch2_bkey_buf_exit(&sk, c);
|
||||||
fsck_err:
|
fsck_err:
|
||||||
@ -93,7 +93,7 @@ int bch2_logged_op_start(struct btree_trans *trans, struct bkey_i *k)
|
|||||||
__bch2_logged_op_start(trans, 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,
|
int ret = commit_do(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc,
|
||||||
bch2_btree_delete(trans, BTREE_ID_logged_ops, k->k.p, 0));
|
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));
|
buf.buf, bch2_err_str(ret));
|
||||||
printbuf_exit(&buf);
|
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_resume_logged_ops(struct bch_fs *);
|
||||||
int bch2_logged_op_start(struct btree_trans *, struct bkey_i *);
|
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 */
|
#endif /* _BCACHEFS_LOGGED_OPS_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user