An asynchronous iomap direct write can remain in flight after the inode lock is released. A buffered write can then dirty page cache before the direct write completes its post-I/O invalidation, causing the invalidation to fail and record -EIO in the mapping error sequence. The pre-write checks can also zero post-EOF page cache while an earlier direct write is still active. Wait for in-flight DIO before post-EOF page-cache operations and before buffered writes. Return -EAGAIN for a NOWAIT write that would need the blocking post-EOF operation. Fixes: a1e09b03e6f5 ("f2fs: use iomap for direct I/O") Cc: stable@vger.kernel.org Signed-off-by: Jiale Yao --- fs/f2fs/file.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 0c759cc99054..d3d0ebf2f6c3 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -5328,6 +5328,7 @@ static ssize_t f2fs_write_checks(struct kiocb *iocb, struct iov_iter *from) { struct file *file = iocb->ki_filp; struct inode *inode = file_inode(file); + loff_t end_pos; ssize_t count; int err; @@ -5345,8 +5346,14 @@ static ssize_t f2fs_write_checks(struct kiocb *iocb, struct iov_iter *from) if (err) return err; - err = f2fs_zero_post_eof_page(inode, - iocb->ki_pos + iov_iter_count(from), true, true); + end_pos = iocb->ki_pos + iov_iter_count(from); + if (end_pos > i_size_read(inode)) { + if (iocb->ki_flags & IOCB_NOWAIT) + return -EAGAIN; + inode_dio_wait(inode); + } + + err = f2fs_zero_post_eof_page(inode, end_pos, true, true); if (err) return err; return count; @@ -5436,6 +5443,8 @@ static ssize_t f2fs_buffered_write_iter(struct kiocb *iocb, if (iocb->ki_flags & IOCB_NOWAIT) return -EOPNOTSUPP; + inode_dio_wait(inode); + ret = generic_perform_write(iocb, from); if (ret > 0) { -- 2.34.1