summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@linux.dev>2023-12-02 04:26:21 -0500
committerKent Overstreet <kent.overstreet@linux.dev>2024-01-16 16:48:40 -0500
commit88a5ca10326341ce8c5d67f6551c26d001914ef3 (patch)
treecd3e8f330a805e29733ca5e70eaafe3a8eadb398
parent3de03b1464ba1c93cb8dd312781cc85daff94498 (diff)
bch2_write_extent() refactoring
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r--fs/bcachefs/io_write.c97
1 files changed, 58 insertions, 39 deletions
diff --git a/fs/bcachefs/io_write.c b/fs/bcachefs/io_write.c
index 4f6c75377874..4f66e6926922 100644
--- a/fs/bcachefs/io_write.c
+++ b/fs/bcachefs/io_write.c
@@ -676,6 +676,13 @@ static void bch2_write_endio(struct bio *bio)
static inline bool use_block_checksums(struct bch_write_op *op,
struct bch_extent_crc_unpacked crc)
{
+ /*
+ * We don't need to carry around block checksums for the move path:
+ * they'll still be in the btree node key
+ */
+ if (op->flags & BCH_WRITE_MOVE)
+ return false;
+
if (!crc.csum_type ||
crc.compression_type ||
!op->opts.checksum_blocksize)
@@ -844,7 +851,6 @@ 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)
{
struct bch_fs *c = op->c;
@@ -853,23 +859,6 @@ static enum prep_encoded_ret {
if (!(op->flags & BCH_WRITE_DATA_ENCODED))
return PREP_ENCODED_OK;
- BUG_ON(bio_sectors(bio) != op->crc.compressed_size);
-
- /* Can we just write the entire extent as is? */
- if (op->crc.uncompressed_size == op->crc.live_size &&
- op->crc.uncompressed_size <= c->opts.encoded_extent_max >> 9 &&
- op->crc.compressed_size <= wp->sectors_free &&
- (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;
-
- return PREP_ENCODED_DO_WRITE;
- }
-
/*
* If the data is compressed and we couldn't write the entire extent as
* is, we have to decompress it:
@@ -918,6 +907,18 @@ static enum prep_encoded_ret {
return PREP_ENCODED_OK;
}
+static inline bool write_full_encoded_extent(struct bch_write_op *op, struct write_point *wp)
+{
+ struct bch_fs *c = op->c;
+
+ return (op->flags & BCH_WRITE_DATA_ENCODED) &&
+ op->crc.uncompressed_size == op->crc.live_size &&
+ op->crc.uncompressed_size <= c->opts.encoded_extent_max >> 9 &&
+ op->crc.compressed_size <= wp->sectors_free &&
+ (op->crc.compression_type == bch2_compression_opt_to_type(op->compression_opt) ||
+ op->incompressible);
+}
+
static int bch2_write_extent(struct bch_write_op *op, struct write_point *wp,
struct bio **_dst)
{
@@ -931,18 +932,17 @@ static int bch2_write_extent(struct bch_write_op *op, struct write_point *wp,
int ret, more = 0;
BUG_ON(!bio_sectors(src));
+ BUG_ON((op->flags & BCH_WRITE_DATA_ENCODED) &&
+ bio_sectors(bio) != op->crc.compressed_size);
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;
- goto err;
- case PREP_ENCODED_CHECKSUM_ERR:
- goto csum_err;
- case PREP_ENCODED_DO_WRITE:
+ if (write_full_encoded_extent(op, wp)) {
+ if (op->csum_type != op->crc.csum_type &&
+ bch2_write_rechecksum(c, op, op->csum_type) &&
+ !c->opts.no_data_io)
+ goto csum_err;
+
if (ec_buf) {
dst = bch2_write_bio_alloc(c, wp, src,
&page_alloc_failed,
@@ -954,6 +954,16 @@ static int bch2_write_extent(struct bch_write_op *op, struct write_point *wp,
goto do_write;
}
+ switch (bch2_write_prep_encoded_data(op, wp)) {
+ case PREP_ENCODED_OK:
+ break;
+ case PREP_ENCODED_ERR:
+ ret = -EIO;
+ goto err;
+ case PREP_ENCODED_CHECKSUM_ERR:
+ goto csum_err;
+ }
+
if (ec_buf ||
op->compression_opt ||
(op->csum_type &&
@@ -1021,9 +1031,14 @@ static int bch2_write_extent(struct bch_write_op *op, struct write_point *wp,
!crc_is_compressed(crc) &&
bch2_csum_type_is_encryption(op->crc.csum_type) ==
bch2_csum_type_is_encryption(op->csum_type)) {
- u8 compression_type = crc.compression_type;
- u16 nonce = crc.nonce;
/*
+ * Generate new checksum with rechecksum_bio():
+ *
+ * This verifies the new checksum against the old
+ * checksum (when splitting) by generating new checksums
+ * for each split, combining them, and comparing against
+ * the old checksum:
+ *
* Note: when we're using rechecksum(), we need to be
* checksumming @src because it has all the data our
* existing checksum covers - if we bounced (because we
@@ -1034,21 +1049,26 @@ static int bch2_write_extent(struct bch_write_op *op, struct write_point *wp,
* because part of the reason for bouncing is so the
* data can't be modified (by userspace) while it's in
* flight.
+ *
+ * We have to save and restore the compression_type for
+ * incompressible data:
*/
+ u8 compression_type = crc.compression_type;
+ u16 nonce = crc.nonce;
if (bch2_rechecksum_bio(c, src, version, op->crc,
&crc, &op->crc,
src_len >> 9,
bio_sectors(src) - (src_len >> 9),
op->csum_type))
goto csum_err;
+ crc.compression_type = compression_type;
+ crc.nonce = nonce;
+ } else {
/*
- * rchecksum_bio sets compression_type on crc from op->crc,
- * this isn't always correct as sometimes we're changing
- * an extent from uncompressed to incompressible.
+ * We can't generate the new checksum with
+ * rechecksum(), but we still want to update op->crc
+ * with a checksum that refers to the remaining data:
*/
- crc.compression_type = compression_type;
- crc.nonce = nonce;
- } else {
if ((op->flags & BCH_WRITE_DATA_ENCODED) &&
bch2_rechecksum_bio(c, src, version, op->crc,
NULL, &op->crc,
@@ -1057,16 +1077,15 @@ static int bch2_write_extent(struct bch_write_op *op, struct write_point *wp,
op->crc.csum_type))
goto csum_err;
- crc.compressed_size = dst_len >> 9;
- crc.uncompressed_size = src_len >> 9;
- crc.live_size = src_len >> 9;
-
swap(dst->bi_iter.bi_size, dst_len);
ret = bch2_encrypt_bio(c, op->csum_type,
extent_nonce(version, crc), dst);
if (ret)
goto err;
+ crc.compressed_size = dst_len >> 9;
+ crc.uncompressed_size = src_len >> 9;
+ crc.live_size = src_len >> 9;
crc.csum = bch2_checksum_bio(c, op->csum_type,
extent_nonce(version, crc), dst);
crc.csum_type = op->csum_type;