Re: Direct IO reads being split unexpected at page boundary, but in the middle of a fs block (bs > ps cases)
Qu Wenruo <[email protected]> Tue, 7 Oct 2025 13:00:58 +1030
| Newsgroups | org.kernel.vger.linux-bcachefs,org.kernel.vger.linux-btrfs,org.kernel.vger.linux-fsdevel |
|---|---|
| Message-ID | <[email protected]> |
=E5=9C=A8 2025/10/7 01:37, Matthew Wilcox =E5=86=99=E9=81=93: > On Wed, Oct 01, 2025 at 10:59:18AM +0930, Qu Wenruo wrote: >> Recently during the btrfs bs > ps direct IO enablement, I'm hitting a c= ase >> where: >> >> - The direct IO iov is properly aligned to fs block size (8K, 2 pages) >> They do not need to be large folio backed, regular incontiguous page= s >> are supported. >> >> - The btrfs now can handle sub-block pages >> But still require the bi_size and (bi_sector << 9) to be block size >> aligned. >> >> - The bio passed into iomap_dio_ops::submit_io is not block size >> aligned >> The bio only contains one page, not 2. >=20 > That seems like a bug in the VFS/iomap somewhere. Maybe try cc'ing the > people who know this code? >=20 Add xfs and bcachefs subsystem into CC. The root cause is that, function __bio_iov_iter_get_pages() can split=20 the iov. In my case, I hit the following dio during iomap_dio_bio_iter(); fsstress-1153 6..... 68530us : iomap_dio_bio_iter: length=3D81920= =20 nr_pages=3D20 enter fsstress-1153 6..... 68539us : iomap_dio_bio_iter: length=3D81920= =20 realsize=3D69632(17 pages) fsstress-1153 6..... 68540us : iomap_dio_bio_iter: nr_pages=3D3 for= =20 next Which bio_iov_iter_get_pages() split the 20 pages into two segments (17=20 + 3 pages). That 17/3 split is not meeting the btrfs' block size requirement (in my=20 case it's 8K block size). I'm seeing XFS having a comment related to bio_iov_iter_get_pages()=20 inside xfs_file_dio_write(), but there is no special checks other than=20 iov_iter_alignment() check, which btrfs is also doing. I guess since XFS do not need to bother data checksum thus such split is= =20 not a big deal? On the other hand, bcachefs is doing reverting to the block boundary=20 instead thus solved the problem. However btrfs is using iomap for direct IOs, thus we can not manually=20 revert the iov/bio just inside btrfs. So I guess in this case we need to add a callback for iomap, to get the=20 fs block size so that at least iomap_dio_bio_iter() can revert to the fs= =20 block boundary? Thanks, Qu