]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
btrfs: add extra ASSERT()s to catch unaligned bios
authorQu Wenruo <wqu@suse.com>
Mon, 15 Sep 2025 09:03:50 +0000 (18:33 +0930)
committerDavid Sterba <dsterba@suse.com>
Tue, 23 Sep 2025 06:49:25 +0000 (08:49 +0200)
Btrfs uses btrfs_bio to handle read/write of logical address, for the
incoming bs > ps support, btrfs has extra requirements:

- One folio must contain at least one fs block
- No fs block can cross folio boundaries

This requirement is not hard to maintain, thanks to the address space's
minimal folio order.

But not all btrfs bios are generated through address space, e.g.
compression and scrub.

To catch possible unaligned bios, introduce a helper,
assert_bbio_alginment(), for each btrfs_bio in btrfs_submit_bbio().

This will check the following things:

- bv_offset is aligned to block size
- bv_len is aligned to block size

With a btrfs bio passing above checks, unless it's empty it will ensure
the requirements for bs > ps support.

Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/bio.c

index 909b208f9ef3c8f35caca6c17299d34d200d540a..db2deaa4aad4e2f10d4d18dbd47d2cd627144b66 100644 (file)
@@ -779,11 +779,38 @@ end_bbio:
        return true;
 }
 
+static void assert_bbio_alignment(struct btrfs_bio *bbio)
+{
+#ifdef CONFIG_BTRFS_ASSERT
+       struct btrfs_fs_info *fs_info = bbio->fs_info;
+       struct bio_vec bvec;
+       struct bvec_iter iter;
+       const u32 blocksize = fs_info->sectorsize;
+
+       /* Metadata has no extra bs > ps alignment requirement. */
+       if (!is_data_bbio(bbio))
+               return;
+
+       bio_for_each_bvec(bvec, &bbio->bio, iter)
+               ASSERT(IS_ALIGNED(bvec.bv_offset, blocksize) &&
+                      IS_ALIGNED(bvec.bv_len, blocksize),
+               "root=%llu inode=%llu logical=%llu length=%u index=%u bv_offset=%u bv_len=%u",
+               btrfs_root_id(bbio->inode->root),
+               btrfs_ino(bbio->inode),
+               bbio->bio.bi_iter.bi_sector << SECTOR_SHIFT,
+               bbio->bio.bi_iter.bi_size, iter.bi_idx,
+               bvec.bv_offset,
+               bvec.bv_len);
+#endif
+}
+
 void btrfs_submit_bbio(struct btrfs_bio *bbio, int mirror_num)
 {
        /* If bbio->inode is not populated, its file_offset must be 0. */
        ASSERT(bbio->inode || bbio->file_offset == 0);
 
+       assert_bbio_alignment(bbio);
+
        while (!btrfs_submit_chunk(bbio, mirror_num))
                ;
 }