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


Reply via email to