Commit 127d90d2 authored by Kent Overstreet's avatar Kent Overstreet
Browse files

bcachefs: bch2_write_prep_encoded_data() now returns errcode



Prep work for killing off EIO and replacing them with proper private
error codes.

Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 2fe20830
Loading
Loading
Loading
Loading
+71 −88
Original line number Diff line number Diff line
@@ -434,6 +434,12 @@ void bch2_write_op_error(struct bch_write_op *op, u64 offset, const char *fmt, .
	printbuf_exit(&buf);
}

static void bch2_write_csum_err_msg(struct bch_write_op *op)
{
	bch2_write_op_error(op, op->pos.offset,
			    "error verifying existing checksum while rewriting existing data (memory corruption?)");
}

void bch2_submit_wbio_replicas(struct bch_write_bio *wbio, struct bch_fs *c,
			       enum bch_data_type type,
			       const struct bkey_i *k,
@@ -809,7 +815,6 @@ static int bch2_write_rechecksum(struct bch_fs *c,
{
	struct bio *bio = &op->wbio.bio;
	struct bch_extent_crc_unpacked new_crc;
	int ret;

	/* bch2_rechecksum_bio() can't encrypt or decrypt data: */

@@ -817,7 +822,7 @@ static int bch2_write_rechecksum(struct bch_fs *c,
	    bch2_csum_type_is_encryption(new_csum_type))
		new_csum_type = op->crc.csum_type;

	ret = bch2_rechecksum_bio(c, bio, op->version, op->crc,
	int ret = bch2_rechecksum_bio(c, bio, op->version, op->crc,
				      NULL, &new_crc,
				      op->crc.offset, op->crc.live_size,
				      new_csum_type);
@@ -830,44 +835,12 @@ static int bch2_write_rechecksum(struct bch_fs *c,
	return 0;
}

static int bch2_write_decrypt(struct bch_write_op *op)
{
	struct bch_fs *c = op->c;
	struct nonce nonce = extent_nonce(op->version, op->crc);
	struct bch_csum csum;
	int ret;

	if (!bch2_csum_type_is_encryption(op->crc.csum_type))
		return 0;

	/*
	 * If we need to decrypt data in the write path, we'll no longer be able
	 * to verify the existing checksum (poly1305 mac, in this case) after
	 * it's decrypted - this is the last point we'll be able to reverify the
	 * checksum:
	 */
	csum = bch2_checksum_bio(c, op->crc.csum_type, nonce, &op->wbio.bio);
	if (bch2_crc_cmp(op->crc.csum, csum) && !c->opts.no_data_io)
		return -EIO;

	ret = bch2_encrypt_bio(c, op->crc.csum_type, nonce, &op->wbio.bio);
	op->crc.csum_type = 0;
	op->crc.csum = (struct bch_csum) { 0, 0 };
	return ret;
}

static enum prep_encoded_ret {
	PREP_ENCODED_OK,
	PREP_ENCODED_ERR,
	PREP_ENCODED_CHECKSUM_ERR,
	PREP_ENCODED_DO_WRITE,
} bch2_write_prep_encoded_data(struct bch_write_op *op, struct write_point *wp)
static noinline int bch2_write_prep_encoded_data(struct bch_write_op *op, struct write_point *wp)
{
	struct bch_fs *c = op->c;
	struct bio *bio = &op->wbio.bio;

	if (!(op->flags & BCH_WRITE_data_encoded))
		return PREP_ENCODED_OK;
	struct nonce nonce = extent_nonce(op->version, op->crc);
	int ret = 0;

	BUG_ON(bio_sectors(bio) != op->crc.compressed_size);

@@ -878,12 +851,13 @@ static enum prep_encoded_ret {
	    (op->crc.compression_type == bch2_compression_opt_to_type(op->compression_opt) ||
	     op->incompressible)) {
		if (!crc_is_compressed(op->crc) &&
		    op->csum_type != op->crc.csum_type &&
		    bch2_write_rechecksum(c, op, op->csum_type) &&
		    !c->opts.no_data_io)
			return PREP_ENCODED_CHECKSUM_ERR;
		    op->csum_type != op->crc.csum_type) {
			ret = bch2_write_rechecksum(c, op, op->csum_type);
			if (ret)
				return ret;
		}

		return PREP_ENCODED_DO_WRITE;
		return 1;
	}

	/*
@@ -891,20 +865,23 @@ static enum prep_encoded_ret {
	 * is, we have to decompress it:
	 */
	if (crc_is_compressed(op->crc)) {
		struct bch_csum csum;

		if (bch2_write_decrypt(op))
			return PREP_ENCODED_CHECKSUM_ERR;

		/* Last point we can still verify checksum: */
		csum = bch2_checksum_bio(c, op->crc.csum_type,
					 extent_nonce(op->version, op->crc),
					 bio);
		struct bch_csum csum = bch2_checksum_bio(c, op->crc.csum_type, nonce, bio);
		if (bch2_crc_cmp(op->crc.csum, csum) && !c->opts.no_data_io)
			return PREP_ENCODED_CHECKSUM_ERR;
			goto csum_err;

		if (bch2_bio_uncompress_inplace(op, bio))
			return PREP_ENCODED_ERR;
		if (bch2_csum_type_is_encryption(op->crc.csum_type)) {
			ret = bch2_encrypt_bio(c, op->crc.csum_type, nonce, bio);
			if (ret)
				return ret;

			op->crc.csum_type = 0;
			op->crc.csum = (struct bch_csum) { 0, 0 };
		}

		ret = bch2_bio_uncompress_inplace(op, bio);
		if (ret)
			return ret;
	}

	/*
@@ -916,22 +893,34 @@ static enum prep_encoded_ret {
	 * If the data is checksummed and we're only writing a subset,
	 * rechecksum and adjust bio to point to currently live data:
	 */
	if ((op->crc.live_size != op->crc.uncompressed_size ||
	     op->crc.csum_type != op->csum_type) &&
	    bch2_write_rechecksum(c, op, op->csum_type) &&
	    !c->opts.no_data_io)
		return PREP_ENCODED_CHECKSUM_ERR;
	if (op->crc.live_size != op->crc.uncompressed_size ||
	    op->crc.csum_type != op->csum_type) {
		ret = bch2_write_rechecksum(c, op, op->csum_type);
		if (ret)
			return ret;
	}

	/*
	 * If we want to compress the data, it has to be decrypted:
	 */
	if ((op->compression_opt ||
	     bch2_csum_type_is_encryption(op->crc.csum_type) !=
	     bch2_csum_type_is_encryption(op->csum_type)) &&
	    bch2_write_decrypt(op))
		return PREP_ENCODED_CHECKSUM_ERR;
	if (bch2_csum_type_is_encryption(op->crc.csum_type) &&
	    (op->compression_opt || op->crc.csum_type != op->csum_type)) {
		struct bch_csum csum = bch2_checksum_bio(c, op->crc.csum_type, nonce, bio);
		if (bch2_crc_cmp(op->crc.csum, csum) && !c->opts.no_data_io)
			goto csum_err;

		ret = bch2_encrypt_bio(c, op->crc.csum_type, nonce, bio);
		if (ret)
			return ret;

		op->crc.csum_type = 0;
		op->crc.csum = (struct bch_csum) { 0, 0 };
	}

	return PREP_ENCODED_OK;
	return 0;
csum_err:
	bch2_write_csum_err_msg(op);
	return -EIO;
}

static int bch2_write_extent(struct bch_write_op *op, struct write_point *wp,
@@ -950,16 +939,11 @@ static int bch2_write_extent(struct bch_write_op *op, struct write_point *wp,

	ec_buf = bch2_writepoint_ec_buf(c, wp);

	switch (bch2_write_prep_encoded_data(op, wp)) {
	case PREP_ENCODED_OK:
		break;
	case PREP_ENCODED_ERR:
		ret = -EIO;
	if (unlikely(op->flags & BCH_WRITE_data_encoded)) {
		ret = bch2_write_prep_encoded_data(op, wp);
		if (ret < 0)
			goto err;
	case PREP_ENCODED_CHECKSUM_ERR:
		goto csum_err;
	case PREP_ENCODED_DO_WRITE:
		/* XXX look for bug here */
		if (ret) {
			if (ec_buf) {
				dst = bch2_write_bio_alloc(c, wp, src,
							   &page_alloc_failed,
@@ -970,6 +954,7 @@ static int bch2_write_extent(struct bch_write_op *op, struct write_point *wp,
			init_append_extent(op, wp, op->version, op->crc);
			goto do_write;
		}
	}

	if (ec_buf ||
	    op->compression_opt ||
@@ -1141,9 +1126,7 @@ static int bch2_write_extent(struct bch_write_op *op, struct write_point *wp,
	*_dst = dst;
	return more;
csum_err:
	bch2_write_op_error(op, op->pos.offset,
			    "error verifying existing checksum while rewriting existing data (memory corruption?)");

	bch2_write_csum_err_msg(op);
	ret = -EIO;
err:
	if (to_wbio(dst)->bounce)