Commit 0f25eb4b authored by Kent Overstreet's avatar Kent Overstreet
Browse files

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: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 1f73cb4d
Loading
Loading
Loading
Loading
+43 −20
Original line number Diff line number Diff line
@@ -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 @@ case LOGGED_OP_FINSERT_shift_extents:

	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;
+9 −7
Original line number Diff line number Diff line
@@ -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;
}
+1 −1
Original line number Diff line number Diff line
@@ -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 */