Provide a splice_read stub for f2fs.  This does some checks and tracing
before proceeding and will switch from direct-I/O to buffered I/O if forced
or if misaligned.  It also updates the iostats after doing a buffered I/O.

[Note: I wonder if I should only do the tracing if I call
filemap_splice_read() as direct_splice_read() will call
f2fs_file_read_iter().]

Signed-off-by: David Howells <[email protected]>
cc: Christoph Hellwig <[email protected]>
cc: Al Viro <[email protected]>
cc: Jens Axboe <[email protected]>
cc: Jaegeuk Kim <[email protected]>
cc: Chao Yu <[email protected]>
cc: [email protected]
cc: [email protected]
cc: [email protected]
cc: [email protected]
---
 fs/f2fs/file.c | 68 ++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 60 insertions(+), 8 deletions(-)

diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 5ac53d2627d2..3723387f4a87 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -4367,22 +4367,23 @@ static ssize_t f2fs_dio_read_iter(struct kiocb *iocb, 
struct iov_iter *to)
        return ret;
 }
 
-static void f2fs_trace_rw_file_path(struct kiocb *iocb, size_t count, int rw)
+static void f2fs_trace_rw_file_path(struct file *file, loff_t pos, size_t 
count,
+                                   int rw)
 {
-       struct inode *inode = file_inode(iocb->ki_filp);
+       struct inode *inode = file_inode(file);
        char *buf, *path;
 
        buf = f2fs_getname(F2FS_I_SB(inode));
        if (!buf)
                return;
-       path = dentry_path_raw(file_dentry(iocb->ki_filp), buf, PATH_MAX);
+       path = dentry_path_raw(file_dentry(file), buf, PATH_MAX);
        if (IS_ERR(path))
                goto free_buf;
        if (rw == WRITE)
-               trace_f2fs_datawrite_start(inode, iocb->ki_pos, count,
+               trace_f2fs_datawrite_start(inode, pos, count,
                                current->pid, path, current->comm);
        else
-               trace_f2fs_dataread_start(inode, iocb->ki_pos, count,
+               trace_f2fs_dataread_start(inode, pos, count,
                                current->pid, path, current->comm);
 free_buf:
        f2fs_putname(buf);
@@ -4398,7 +4399,8 @@ static ssize_t f2fs_file_read_iter(struct kiocb *iocb, 
struct iov_iter *to)
                return -EOPNOTSUPP;
 
        if (trace_f2fs_dataread_start_enabled())
-               f2fs_trace_rw_file_path(iocb, iov_iter_count(to), READ);
+               f2fs_trace_rw_file_path(iocb->ki_filp, iocb->ki_pos,
+                                       iov_iter_count(to), READ);
 
        if (f2fs_should_use_dio(inode, iocb, to)) {
                ret = f2fs_dio_read_iter(iocb, to);
@@ -4413,6 +4415,55 @@ static ssize_t f2fs_file_read_iter(struct kiocb *iocb, 
struct iov_iter *to)
        return ret;
 }
 
+static ssize_t f2fs_file_splice_read(struct file *in, loff_t *ppos,
+                                    struct pipe_inode_info *pipe,
+                                    size_t len, unsigned int flags)
+{
+       struct inode *inode = file_inode(in);
+       const loff_t pos = *ppos;
+       ssize_t ret;
+
+       if (!f2fs_is_compress_backend_ready(inode))
+               return -EOPNOTSUPP;
+
+       if (trace_f2fs_dataread_start_enabled())
+               f2fs_trace_rw_file_path(in, pos, len, READ);
+
+       if (in->f_flags & O_DIRECT) {
+               if (f2fs_force_buffered_io(inode, READ))
+                       goto buffered;
+
+               /*
+                * Direct I/O not aligned to the disk's logical_block_size will
+                * be attempted, but will fail with -EINVAL.
+                *
+                * f2fs additionally requires that direct I/O be aligned to the
+                * filesystem block size, which is often a stricter
+                * requirement.  However, f2fs traditionally falls back to
+                * buffered I/O on requests that are logical_block_size-aligned
+                * but not fs-block aligned.
+                *
+                * The below logic implements this behavior.
+                */
+               if (!IS_ALIGNED(pos, i_blocksize(inode)) &&
+                   IS_ALIGNED(pos, 
bdev_logical_block_size(inode->i_sb->s_bdev)))
+                       goto buffered;
+               ret = direct_splice_read(in, ppos, pipe, len, flags);
+               goto done;
+       }
+
+buffered:
+       ret = filemap_splice_read(in, ppos, pipe, len, flags);
+       if (ret > 0)
+               f2fs_update_iostat(F2FS_I_SB(inode), inode,
+                                  APP_BUFFERED_READ_IO, ret);
+
+done:
+       if (trace_f2fs_dataread_end_enabled())
+               trace_f2fs_dataread_end(inode, pos, ret);
+       return ret;
+}
+
 static ssize_t f2fs_write_checks(struct kiocb *iocb, struct iov_iter *from)
 {
        struct file *file = iocb->ki_filp;
@@ -4714,7 +4765,8 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, 
struct iov_iter *from)
                ret = preallocated;
        } else {
                if (trace_f2fs_datawrite_start_enabled())
-                       f2fs_trace_rw_file_path(iocb, orig_count, WRITE);
+                       f2fs_trace_rw_file_path(iocb->ki_filp, iocb->ki_pos,
+                                               orig_count, WRITE);
 
                /* Do the actual write. */
                ret = dio ?
@@ -4919,7 +4971,7 @@ const struct file_operations f2fs_file_operations = {
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = f2fs_compat_ioctl,
 #endif
-       .splice_read    = generic_file_splice_read,
+       .splice_read    = f2fs_file_splice_read,
        .splice_write   = iter_file_splice_write,
        .fadvise        = f2fs_file_fadvise,
 };



_______________________________________________
Linux-f2fs-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

Reply via email to