Others: Cc: Johannes Thumshirn <jth@xxxxxxxxxx> Cc: linux-xfs@xxxxxxxxxxxxxxx Cc: linux-fsdevel@xxxxxxxxxxxxxxx Cc: linux-ext4@xxxxxxxxxxxxxxx Cc: cluster-devel@xxxxxxxxxx Fixes: 60263d5889e6d ("iomap: fall back to buffered writes for invalidation failures") Reported-by: syzbot+0ed9f769264276638893@xxxxxxxxxxxxxxxxxxxxxxxxx Signed-off-by: Lee Jones <lee.jones@xxxxxxxxxx> --- fs/ext4/file.c | 2 -- fs/gfs2/file.c | 3 +-- fs/iomap/direct-io.c | 16 +++++----------- fs/iomap/trace.h | 1 - fs/xfs/xfs_file.c | 4 ++-- fs/zonefs/super.c | 7 ++----- 6 files changed, 10 insertions(+), 23 deletions(-) diff --git a/fs/ext4/file.c b/fs/ext4/file.c index 3ed8c048fb12c..cb347c3b35535 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -551,8 +551,6 @@ static ssize_t ext4_dio_write_iter(struct kiocb *iocb, struct iov_iter *from) iomap_ops = &ext4_iomap_overwrite_ops; ret = iomap_dio_rw(iocb, from, iomap_ops, &ext4_dio_write_ops, is_sync_kiocb(iocb) || unaligned_io || extend); - if (ret == -ENOTBLK) - ret = 0; if (extend) ret = ext4_handle_inode_extension(inode, offset, ret, count); diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index b39b339feddc9..847adb97380d3 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -835,8 +835,7 @@ static ssize_t gfs2_file_direct_write(struct kiocb *iocb, struct iov_iter *from, ret = iomap_dio_rw(iocb, from, &gfs2_iomap_ops, NULL, is_sync_kiocb(iocb)); - if (ret == -ENOTBLK) - ret = 0; + out: gfs2_glock_dq(gh); out_uninit: diff --git a/fs/iomap/direct-io.c b/fs/iomap/direct-io.c index 933f234d5becd..ddcd06c0c452d 100644 --- a/fs/iomap/direct-io.c +++ b/fs/iomap/direct-io.c @@ -10,7 +10,6 @@ #include <linux/backing-dev.h> #include <linux/uio.h> #include <linux/task_io_accounting_ops.h> -#include "trace.h" #include "../internal.h" @@ -413,9 +412,6 @@ iomap_dio_actor(struct inode *inode, loff_t pos, loff_t length, * can be mapped into multiple disjoint IOs and only a subset of the IOs issued * may be pure data writes. In that case, we still need to do a full data sync * completion. - * - * Returns -ENOTBLK In case of a page invalidation invalidation failure for - * writes. The callers needs to fall back to buffered I/O in this case. */ struct iomap_dio * __iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter, @@ -493,15 +489,13 @@ __iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter, if (iov_iter_rw(iter) == WRITE) { /* * Try to invalidate cache pages for the range we are writing. - * If this invalidation fails, let the caller fall back to - * buffered I/O. + * If this invalidation fails, tough, the write will still work, + * but racing two incompatible write paths is a pretty crazy + * thing to do, so we don't support it 100%. */ if (invalidate_inode_pages2_range(mapping, pos >> PAGE_SHIFT, - end >> PAGE_SHIFT)) { - trace_iomap_dio_invalidate_fail(inode, pos, count); - ret = -ENOTBLK; - goto out_free_dio; - } + end >> PAGE_SHIFT)) + dio_warn_stale_pagecache(iocb->ki_filp); if (!wait_for_completion && !inode->i_sb->s_dio_done_wq) { ret = sb_init_dio_done_wq(inode->i_sb); diff --git a/fs/iomap/trace.h b/fs/iomap/trace.h index fdc7ae388476f..5693a39d52fb6 100644 --- a/fs/iomap/trace.h +++ b/fs/iomap/trace.h @@ -74,7 +74,6 @@ DEFINE_EVENT(iomap_range_class, name, \ DEFINE_RANGE_EVENT(iomap_writepage); DEFINE_RANGE_EVENT(iomap_releasepage); DEFINE_RANGE_EVENT(iomap_invalidatepage); -DEFINE_RANGE_EVENT(iomap_dio_invalidate_fail); #define IOMAP_TYPE_STRINGS \ { IOMAP_HOLE, "HOLE" }, \ diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 5b0f93f738372..43e2c057214d9 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -589,8 +589,8 @@ xfs_file_dio_aio_write( xfs_iunlock(ip, iolock); /* - * No fallback to buffered IO after short writes for XFS, direct I/O - * will either complete fully or return an error. + * No fallback to buffered IO on errors for XFS, direct IO will either + * complete fully or fail. */ ASSERT(ret < 0 || ret == count); return ret; diff --git a/fs/zonefs/super.c b/fs/zonefs/super.c index bec47f2d074be..d54fbef3db4df 100644 --- a/fs/zonefs/super.c +++ b/fs/zonefs/super.c @@ -851,11 +851,8 @@ static ssize_t zonefs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) if (iocb->ki_pos >= ZONEFS_I(inode)->i_max_size) return -EFBIG; - if (iocb->ki_flags & IOCB_DIRECT) { - ssize_t ret = zonefs_file_dio_write(iocb, from); - if (ret != -ENOTBLK) - return ret; - } + if (iocb->ki_flags & IOCB_DIRECT) + return zonefs_file_dio_write(iocb, from); return zonefs_file_buffered_write(iocb, from); } -- 2.35.0.263.gb82422642f-goog