Support fallback to buffered I/O if the operation being performed on unaligned length or offset. This may change the behavior for direct I/O in some cases.
[Before] For length which aligned with 256 bytes (not SECTOR aligned) will read failed under direct I/O. [After] For length which aligned with 256 bytes (not SECTOR aligned) will read the data successfully under direct I/O because it will fallback to buffer I/O. Signed-off-by: Hongbo Li <[email protected]> --- fs/bcachefs/errcode.h | 1 + fs/bcachefs/fs-io-direct.c | 19 +++++++++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/fs/bcachefs/errcode.h b/fs/bcachefs/errcode.h index a268af3e52bf..ff0bbeadec79 100644 --- a/fs/bcachefs/errcode.h +++ b/fs/bcachefs/errcode.h @@ -9,6 +9,7 @@ x(BCH_ERR_mount_option, option_name) \ x(BCH_ERR_mount_option, option_value) \ x(BCH_ERR_mount_option, option_not_bool) \ + x(EINVAL, EINVAL_fallback_buffer_read) \ x(ENOMEM, ENOMEM_stripe_buf) \ x(ENOMEM, ENOMEM_replicas_table) \ x(ENOMEM, ENOMEM_cpu_replicas) \ diff --git a/fs/bcachefs/fs-io-direct.c b/fs/bcachefs/fs-io-direct.c index 049b61bc9a5b..bae29696b89e 100644 --- a/fs/bcachefs/fs-io-direct.c +++ b/fs/bcachefs/fs-io-direct.c @@ -77,9 +77,9 @@ static int bch2_direct_IO_read(struct kiocb *req, struct iov_iter *iter) bch2_inode_opts_get(&opts, c, &inode->ei_inode); - /* bios must be 512 byte aligned: */ + /* bios must be 512 byte aligned, otherwise fallback to buffer read. */ if ((offset|iter->count) & (SECTOR_SIZE - 1)) - return -EINVAL; + return -BCH_ERR_EINVAL_fallback_buffer_read; ret = min_t(loff_t, iter->count, max_t(loff_t, 0, i_size_read(&inode->v) - offset)); @@ -201,13 +201,20 @@ ssize_t bch2_read_iter(struct kiocb *iocb, struct iov_iter *iter) ret = bch2_direct_IO_read(iocb, iter); blk_finish_plug(&plug); + if (ret == -BCH_ERR_EINVAL_fallback_buffer_read) { + iocb->ki_flags &= ~IOCB_DIRECT; + goto fallback_buffer_read; + } if (ret >= 0) iocb->ki_pos += ret; - } else { - bch2_pagecache_add_get(inode); - ret = generic_file_read_iter(iocb, iter); - bch2_pagecache_add_put(inode); + goto out; } + +fallback_buffer_read: + bch2_pagecache_add_get(inode); + ret = generic_file_read_iter(iocb, iter); + bch2_pagecache_add_put(inode); + out: return bch2_err_class(ret); } -- 2.34.1
