Skip to content

Commit 41b21af

Browse files
krisman-at-collaborajankara
authored andcommitted
direct-io: defer alignment check until after the EOF check
Prior to commit 9fe55ee ("Fix race when checking i_size on direct i/o read"), an unaligned direct read past end of file would trigger EOF, since generic_file_aio_read detected this read-at-EOF condition and skipped the direct IO read entirely, returning 0. After that change, the read now reaches dio_generic, which detects the misalignment and returns EINVAL. This consolidates the generic direct-io to follow the same behavior of filesystems. Apparently, this fix will only affect ocfs2 since other filesystems do this verification before calling do_blockdev_direct_IO, with the exception of f2fs, which has the same bug, but is fixed in the next patch. it can be verified by a read loop on a file that does a partial read before EOF (On file that doesn't end at an aligned address). The following code fails on an unaligned file on filesystems without prior validation without this patch, but not on btrfs, ext4, and xfs. while (done < total) { ssize_t delta = pread(fd, buf + done, total - done, off + done); if (!delta) break; ... } Fix this regression by moving the misalignment check to after the EOF check added by commit 74cedf9 ("direct-io: Fix negative return from dio read beyond eof"). Based on a patch by Jamie Liu. Link: https://lore.kernel.org/r/[email protected] Reported-by: Jamie Liu <[email protected]> Reviewed-by: Jan Kara <[email protected]> Reviewed-by: Jens Axboe <[email protected]> Signed-off-by: Gabriel Krisman Bertazi <[email protected]> Signed-off-by: Jan Kara <[email protected]>
1 parent 0a9164c commit 41b21af

File tree

1 file changed

+8
-8
lines changed

1 file changed

+8
-8
lines changed

fs/direct-io.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1165,14 +1165,6 @@ do_blockdev_direct_IO(struct kiocb *iocb, struct inode *inode,
11651165
* the early prefetch in the caller enough time.
11661166
*/
11671167

1168-
if (align & blocksize_mask) {
1169-
if (bdev)
1170-
blkbits = blksize_bits(bdev_logical_block_size(bdev));
1171-
blocksize_mask = (1 << blkbits) - 1;
1172-
if (align & blocksize_mask)
1173-
return -EINVAL;
1174-
}
1175-
11761168
/* watch out for a 0 len io from a tricksy fs */
11771169
if (iov_iter_rw(iter) == READ && !count)
11781170
return 0;
@@ -1200,6 +1192,14 @@ do_blockdev_direct_IO(struct kiocb *iocb, struct inode *inode,
12001192
goto fail_dio;
12011193
}
12021194

1195+
if (align & blocksize_mask) {
1196+
if (bdev)
1197+
blkbits = blksize_bits(bdev_logical_block_size(bdev));
1198+
blocksize_mask = (1 << blkbits) - 1;
1199+
if (align & blocksize_mask)
1200+
goto fail_dio;
1201+
}
1202+
12031203
if (dio->flags & DIO_LOCKING && iov_iter_rw(iter) == READ) {
12041204
struct address_space *mapping = iocb->ki_filp->f_mapping;
12051205

0 commit comments

Comments
 (0)