[PATCH] bcachefs: allow direct io fallback to buffer io for unaligned length or offset

Hongbo Li
2024-06-20T13:19:15Z

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 <lihongbo22@huawei.com>
---
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