diff --git a/fs/btrfs/bio.c b/fs/btrfs/bio.c index 0ce48bf26002ad..54cfab7394d377 100644 --- a/fs/btrfs/bio.c +++ b/fs/btrfs/bio.c @@ -686,6 +686,10 @@ static bool btrfs_submit_chunk(struct btrfs_bio *bbio, int mirror_num) ret = btrfs_bio_csum(bbio); if (ret) goto fail_put_bio; + } else if (use_append) { + ret = btrfs_alloc_dummy_sum(bbio); + if (ret) + goto fail_put_bio; } } diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index 2e7d5ec6c9a68c..0cb4a9921d21ed 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c @@ -830,6 +830,29 @@ blk_status_t btrfs_csum_one_bio(struct btrfs_bio *bbio) return 0; } +/* + * Nodatasum I/O on zoned file systems still requires an btrfs_ordered_sum to + * record the updated logical address on Zone Append completion. + * Allocate just the structure with an empty sums array here for that case. + */ +blk_status_t btrfs_alloc_dummy_sum(struct btrfs_bio *bbio) +{ + struct btrfs_ordered_extent *ordered = + btrfs_lookup_ordered_extent(bbio->inode, bbio->file_offset); + + if (WARN_ON_ONCE(!ordered)) + return BLK_STS_IOERR; + + bbio->sums = kmalloc(sizeof(*bbio->sums), GFP_NOFS); + if (!bbio->sums) + return BLK_STS_RESOURCE; + bbio->sums->len = bbio->bio.bi_iter.bi_size; + bbio->sums->logical = bbio->bio.bi_iter.bi_sector << SECTOR_SHIFT; + btrfs_add_ordered_sum(ordered, bbio->sums); + btrfs_put_ordered_extent(ordered); + return 0; +} + /* * Remove one checksum overlapping a range. * diff --git a/fs/btrfs/file-item.h b/fs/btrfs/file-item.h index 6be8725cd57474..4ec669b690080a 100644 --- a/fs/btrfs/file-item.h +++ b/fs/btrfs/file-item.h @@ -50,6 +50,7 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_ordered_sum *sums); blk_status_t btrfs_csum_one_bio(struct btrfs_bio *bbio); +blk_status_t btrfs_alloc_dummy_sum(struct btrfs_bio *bbio); int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, struct list_head *list, int search_commit, bool nowait); diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c index 24c997c51e1e9a..b55b0d4ee86f85 100644 --- a/fs/btrfs/zoned.c +++ b/fs/btrfs/zoned.c @@ -1667,14 +1667,15 @@ void btrfs_record_physical_zoned(struct btrfs_bio *bbio) void btrfs_rewrite_logical_zoned(struct btrfs_ordered_extent *ordered) { - struct extent_map_tree *em_tree = &BTRFS_I(ordered->inode)->extent_tree; + struct btrfs_inode *inode = BTRFS_I(ordered->inode); + struct extent_map_tree *em_tree = &inode->extent_tree; struct extent_map *em; struct btrfs_ordered_sum *sum = list_first_entry(&ordered->list, typeof(*sum), list); u64 logical = sum->logical; if (ordered->disk_bytenr == logical) - return; + goto out; ordered->disk_bytenr = logical; @@ -1684,6 +1685,19 @@ void btrfs_rewrite_logical_zoned(struct btrfs_ordered_extent *ordered) em->block_start = logical; free_extent_map(em); write_unlock(&em_tree->lock); + +out: + /* + * If we end up here for nodatasum I/O, the btrfs_ordered_sum structures + * were allocated by btrfs_alloc_dummy_sum only to record the logical + * addresses and don't contain actual checksums. We thus must free them + * here so that we don't attempt to log the csums later. + */ + if ((inode->flags & BTRFS_INODE_NODATASUM) || + test_bit(BTRFS_FS_STATE_NO_CSUMS, &inode->root->fs_info->fs_state)) { + list_del(&sum->list); + kfree(sum); + } } bool btrfs_check_meta_write_pointer(struct btrfs_fs_info *fs_info,