Skip to content

Commit 00d8252

Browse files
Christoph Hellwigkdave
authored andcommitted
btrfs: fix direct I/O read repair for split bios
When a bio is split in btrfs_submit_direct, dip->file_offset contains the file offset for the first bio. But this means the start value used in btrfs_check_read_dio_bio is incorrect for subsequent bios. Add a file_offset field to struct btrfs_bio to pass along the correct offset. Given that check_data_csum only uses start of an error message this means problems with this miscalculation will only show up when I/O fails or checksums mismatch. The logic was removed in f4f39fc ("btrfs: remove btrfs_bio::logical member") but we need it due to the bio splitting. CC: stable@vger.kernel.org # 5.16+ Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com> Reviewed-by: Naohiro Aota <naohiro.aota@wdc.com> Reviewed-by: Qu Wenruo <wqu@suse.com> Reviewed-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me> Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: David Sterba <dsterba@suse.com>
1 parent 50f1cff commit 00d8252

3 files changed

Lines changed: 9 additions & 8 deletions

File tree

fs/btrfs/extent_io.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2658,6 +2658,7 @@ int btrfs_repair_one_sector(struct inode *inode,
26582658

26592659
repair_bio = btrfs_bio_alloc(1);
26602660
repair_bbio = btrfs_bio(repair_bio);
2661+
repair_bbio->file_offset = start;
26612662
repair_bio->bi_opf = REQ_OP_READ;
26622663
repair_bio->bi_end_io = failed_bio->bi_end_io;
26632664
repair_bio->bi_iter.bi_sector = failrec->logical >> 9;

fs/btrfs/inode.c

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7809,8 +7809,6 @@ static blk_status_t btrfs_check_read_dio_bio(struct btrfs_dio_private *dip,
78097809
const bool csum = !(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM);
78107810
struct bio_vec bvec;
78117811
struct bvec_iter iter;
7812-
const u64 orig_file_offset = dip->file_offset;
7813-
u64 start = orig_file_offset;
78147812
u32 bio_offset = 0;
78157813
blk_status_t err = BLK_STS_OK;
78167814

@@ -7820,6 +7818,8 @@ static blk_status_t btrfs_check_read_dio_bio(struct btrfs_dio_private *dip,
78207818
nr_sectors = BTRFS_BYTES_TO_BLKS(fs_info, bvec.bv_len);
78217819
pgoff = bvec.bv_offset;
78227820
for (i = 0; i < nr_sectors; i++) {
7821+
u64 start = bbio->file_offset + bio_offset;
7822+
78237823
ASSERT(pgoff < PAGE_SIZE);
78247824
if (uptodate &&
78257825
(!csum || !check_data_csum(inode, bbio,
@@ -7832,17 +7832,13 @@ static blk_status_t btrfs_check_read_dio_bio(struct btrfs_dio_private *dip,
78327832
} else {
78337833
int ret;
78347834

7835-
ASSERT((start - orig_file_offset) < UINT_MAX);
7836-
ret = btrfs_repair_one_sector(inode,
7837-
&bbio->bio,
7838-
start - orig_file_offset,
7839-
bvec.bv_page, pgoff,
7835+
ret = btrfs_repair_one_sector(inode, &bbio->bio,
7836+
bio_offset, bvec.bv_page, pgoff,
78407837
start, bbio->mirror_num,
78417838
submit_dio_repair_bio);
78427839
if (ret)
78437840
err = errno_to_blk_status(ret);
78447841
}
7845-
start += sectorsize;
78467842
ASSERT(bio_offset + sectorsize > bio_offset);
78477843
bio_offset += sectorsize;
78487844
pgoff += sectorsize;
@@ -8045,6 +8041,7 @@ static void btrfs_submit_direct(const struct iomap_iter *iter,
80458041
bio = btrfs_bio_clone_partial(dio_bio, clone_offset, clone_len);
80468042
bio->bi_private = dip;
80478043
bio->bi_end_io = btrfs_end_dio_bio;
8044+
btrfs_bio(bio)->file_offset = file_offset;
80488045

80498046
if (bio_op(bio) == REQ_OP_ZONE_APPEND) {
80508047
status = extract_ordered_extent(BTRFS_I(inode), bio,

fs/btrfs/volumes.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,9 @@ struct btrfs_fs_devices {
328328
struct btrfs_bio {
329329
unsigned int mirror_num;
330330

331+
/* for direct I/O */
332+
u64 file_offset;
333+
331334
/* @device is for stripe IO submission. */
332335
struct btrfs_device *device;
333336
u8 *csum;

0 commit comments

Comments
 (0)