Fix dio_bio_cleanup() to advance the head index into the list of pages past the pages it has released, as __blockdev_direct_IO() will call it twice if do_direct_IO() fails. The issue was causing: WARNING: CPU: 6 PID: 2220 at mm/gup.c:76 try_get_folio This can be triggered by setting up a clean pair of UDF filesystems on loopback devices and running the generic/451 xfstest with them as the scratch and test partitions. Something like the following: fallocate /mnt2/udf_scratch -l 1G fallocate /mnt2/udf_test -l 1G mknod /dev/lo0 b 7 0 mknod /dev/lo1 b 7 1 losetup lo0 /mnt2/udf_scratch losetup lo1 /mnt2/udf_test mkfs -t udf /dev/lo0 mkfs -t udf /dev/lo1 cd xfstests ./check generic/451 with xfstests configured by putting the following into local.config: export FSTYP=udf export DISABLE_UDF_TEST=1 export TEST_DEV=/dev/lo1 export TEST_DIR=/xfstest.test export SCRATCH_DEV=/dev/lo0 export SCRATCH_MNT=/xfstest.scratch Fixes: 1ccf164ec866 ("block: Use iov_iter_extract_pages() and page pinning in direct-io.c") Reported-by: kernel test robot <oliver.sang@xxxxxxxxx> Closes: https://lore.kernel.org/oe-lkp/202306120931.a9606b88-oliver.sang@xxxxxxxxx Signed-off-by: David Howells <dhowells@xxxxxxxxxx> cc: Christoph Hellwig <hch@xxxxxxxxxxxxx> cc: David Hildenbrand <david@xxxxxxxxxx> cc: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> cc: Jens Axboe <axboe@xxxxxxxxx> cc: Al Viro <viro@xxxxxxxxxxxxxxxxxx> cc: Matthew Wilcox <willy@xxxxxxxxxxxxx> cc: Jan Kara <jack@xxxxxxx> cc: Jeff Layton <jlayton@xxxxxxxxxx> cc: Jason Gunthorpe <jgg@xxxxxxxxxx> cc: Logan Gunthorpe <logang@xxxxxxxxxxxx> cc: Hillf Danton <hdanton@xxxxxxxx> cc: Christian Brauner <brauner@xxxxxxxxxx> cc: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx> cc: linux-fsdevel@xxxxxxxxxxxxxxx cc: linux-block@xxxxxxxxxxxxxxx cc: linux-kernel@xxxxxxxxxxxxxxx cc: linux-mm@xxxxxxxxx --- fs/direct-io.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/direct-io.c b/fs/direct-io.c index 0643f1bb4b59..2ceb378b93c0 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -459,6 +459,7 @@ static inline void dio_cleanup(struct dio *dio, struct dio_submit *sdio) if (dio->is_pinned) unpin_user_pages(dio->pages + sdio->head, sdio->tail - sdio->head); + sdio->head = sdio->tail; } /*