Skip to content

Commit c3be7eb

Browse files
johnpgarryaxboe
authored andcommitted
fs/block: Check for IOCB_DIRECT in generic_atomic_write_valid()
Currently FMODE_CAN_ATOMIC_WRITE is set if the bdev can atomic write and the file is open for direct IO. This does not work if the file is not opened for direct IO, yet fcntl(O_DIRECT) is used on the fd later. Change to check for direct IO on a per-IO basis in generic_atomic_write_valid(). Since we want to report -EOPNOTSUPP for non-direct IO for an atomic write, change to return an error code. Relocate the block fops atomic write checks to the common write path, as to catch non-direct IO. Fixes: c34fc6f ("fs: Initial atomic write support") Reviewed-by: Christoph Hellwig <[email protected]> Reviewed-by: Darrick J. Wong <[email protected]> Signed-off-by: John Garry <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jens Axboe <[email protected]>
1 parent 9a8dbda commit c3be7eb

File tree

3 files changed

+19
-14
lines changed

3 files changed

+19
-14
lines changed

block/fops.c

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,8 @@ static blk_opf_t dio_bio_write_op(struct kiocb *iocb)
3636
}
3737

3838
static bool blkdev_dio_invalid(struct block_device *bdev, struct kiocb *iocb,
39-
struct iov_iter *iter, bool is_atomic)
39+
struct iov_iter *iter)
4040
{
41-
if (is_atomic && !generic_atomic_write_valid(iocb, iter))
42-
return true;
43-
4441
return iocb->ki_pos & (bdev_logical_block_size(bdev) - 1) ||
4542
!bdev_iter_is_aligned(bdev, iter);
4643
}
@@ -368,13 +365,12 @@ static ssize_t __blkdev_direct_IO_async(struct kiocb *iocb,
368365
static ssize_t blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
369366
{
370367
struct block_device *bdev = I_BDEV(iocb->ki_filp->f_mapping->host);
371-
bool is_atomic = iocb->ki_flags & IOCB_ATOMIC;
372368
unsigned int nr_pages;
373369

374370
if (!iov_iter_count(iter))
375371
return 0;
376372

377-
if (blkdev_dio_invalid(bdev, iocb, iter, is_atomic))
373+
if (blkdev_dio_invalid(bdev, iocb, iter))
378374
return -EINVAL;
379375

380376
nr_pages = bio_iov_vecs_to_alloc(iter, BIO_MAX_VECS + 1);
@@ -383,7 +379,7 @@ static ssize_t blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
383379
return __blkdev_direct_IO_simple(iocb, iter, bdev,
384380
nr_pages);
385381
return __blkdev_direct_IO_async(iocb, iter, bdev, nr_pages);
386-
} else if (is_atomic) {
382+
} else if (iocb->ki_flags & IOCB_ATOMIC) {
387383
return -EINVAL;
388384
}
389385
return __blkdev_direct_IO(iocb, iter, bdev, bio_max_segs(nr_pages));
@@ -625,7 +621,7 @@ static int blkdev_open(struct inode *inode, struct file *filp)
625621
if (!bdev)
626622
return -ENXIO;
627623

628-
if (bdev_can_atomic_write(bdev) && filp->f_flags & O_DIRECT)
624+
if (bdev_can_atomic_write(bdev))
629625
filp->f_mode |= FMODE_CAN_ATOMIC_WRITE;
630626

631627
ret = bdev_open(bdev, mode, filp->private_data, NULL, filp);
@@ -700,6 +696,12 @@ static ssize_t blkdev_write_iter(struct kiocb *iocb, struct iov_iter *from)
700696
if ((iocb->ki_flags & (IOCB_NOWAIT | IOCB_DIRECT)) == IOCB_NOWAIT)
701697
return -EOPNOTSUPP;
702698

699+
if (iocb->ki_flags & IOCB_ATOMIC) {
700+
ret = generic_atomic_write_valid(iocb, from);
701+
if (ret)
702+
return ret;
703+
}
704+
703705
size -= iocb->ki_pos;
704706
if (iov_iter_count(from) > size) {
705707
shorted = iov_iter_count(from) - size;

fs/read_write.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1830,18 +1830,21 @@ int generic_file_rw_checks(struct file *file_in, struct file *file_out)
18301830
return 0;
18311831
}
18321832

1833-
bool generic_atomic_write_valid(struct kiocb *iocb, struct iov_iter *iter)
1833+
int generic_atomic_write_valid(struct kiocb *iocb, struct iov_iter *iter)
18341834
{
18351835
size_t len = iov_iter_count(iter);
18361836

18371837
if (!iter_is_ubuf(iter))
1838-
return false;
1838+
return -EINVAL;
18391839

18401840
if (!is_power_of_2(len))
1841-
return false;
1841+
return -EINVAL;
18421842

18431843
if (!IS_ALIGNED(iocb->ki_pos, len))
1844-
return false;
1844+
return -EINVAL;
18451845

1846-
return true;
1846+
if (!(iocb->ki_flags & IOCB_DIRECT))
1847+
return -EOPNOTSUPP;
1848+
1849+
return 0;
18471850
}

include/linux/fs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3721,6 +3721,6 @@ static inline bool vfs_empty_path(int dfd, const char __user *path)
37213721
return !c;
37223722
}
37233723

3724-
bool generic_atomic_write_valid(struct kiocb *iocb, struct iov_iter *iter);
3724+
int generic_atomic_write_valid(struct kiocb *iocb, struct iov_iter *iter);
37253725

37263726
#endif /* _LINUX_FS_H */

0 commit comments

Comments
 (0)