]> git.proxmox.com Git - mirror_spl.git/commitdiff
Linux 4.14 compat: vfs_read & vfs_write
authorBrian Behlendorf <behlendorf1@llnl.gov>
Thu, 16 Nov 2017 01:19:23 +0000 (17:19 -0800)
committerTony Hutter <hutter2@llnl.gov>
Thu, 16 Nov 2017 18:47:57 +0000 (12:47 -0600)
The kernel_read & kernel_write functions have always wrapped the
vfs_read & vfs_write functions respectively.  However, they could
not be used by vn_rdwr() since the offset wasn't passed as a
pointer.  This prevented us from being able to properly update
the file offset.

Linux 4.14 unexported vfs_read & vfs_write but also changed the
signature of kernel_read & kernel_write to provide the needed
functionality.  Use these updated functions when available.

Reviewed-by: Pritam Baral <pritam@pritambaral.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #656
Closes #667

config/spl-build.m4
include/linux/file_compat.h
module/spl/spl-vnode.c

index b2a50bf164b9908235587c6e00e786c5dc06583d..accf6759bfbe54b31135702f8f16c2a3b8702bd1 100644 (file)
@@ -54,6 +54,8 @@ AC_DEFUN([SPL_AC_CONFIG_KERNEL], [
        SPL_AC_KMEM_CACHE_CREATE_USERCOPY
        SPL_AC_WAIT_QUEUE_ENTRY_T
        SPL_AC_WAIT_QUEUE_HEAD_ENTRY
+       SPL_AC_KERNEL_WRITE
+       SPL_AC_KERNEL_READ
 ])
 
 AC_DEFUN([SPL_AC_MODULE_SYMVERS], [
@@ -1695,3 +1697,61 @@ AC_DEFUN([SPL_AC_WAIT_QUEUE_HEAD_ENTRY], [
                AC_MSG_RESULT(no)
        ])
 ])
+
+dnl #
+dnl # 4.14 API change
+dnl # kernel_write() which was introduced in 3.9 was updated to take
+dnl # the offset as a pointer which is needed by vn_rdwr().
+dnl #
+AC_DEFUN([SPL_AC_KERNEL_WRITE], [
+       AC_MSG_CHECKING([whether kernel_write() takes loff_t pointer])
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="-Werror"
+       SPL_LINUX_TRY_COMPILE([
+               #include <linux/fs.h>
+       ],[
+               struct file *file = NULL;
+               const void *buf = NULL;
+               size_t count = 0;
+               loff_t *pos = NULL;
+               ssize_t ret;
+
+               ret = kernel_write(file, buf, count, pos);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_KERNEL_WRITE_PPOS, 1,
+                   [kernel_write() take loff_t pointer])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+       EXTRA_KCFLAGS="$tmp_flags"
+])
+
+dnl #
+dnl # 4.14 API change
+dnl # kernel_read() which has existed for forever was updated to take
+dnl # the offset as a pointer which is needed by vn_rdwr().
+dnl #
+AC_DEFUN([SPL_AC_KERNEL_READ], [
+       AC_MSG_CHECKING([whether kernel_read() takes loff_t pointer])
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="-Werror"
+       SPL_LINUX_TRY_COMPILE([
+               #include <linux/fs.h>
+       ],[
+               struct file *file = NULL;
+               void *buf = NULL;
+               size_t count = 0;
+               loff_t *pos = NULL;
+               ssize_t ret;
+
+               ret = kernel_read(file, buf, count, pos);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_KERNEL_READ_PPOS, 1,
+                   [kernel_read() take loff_t pointer])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+       EXTRA_KCFLAGS="$tmp_flags"
+])
index 916514566a23807fcd83ca4431f48ab72151259a..2fd6e5fc8779035b601f218210e4d567398c344d 100644 (file)
@@ -26,6 +26,7 @@
 #define _SPL_FILE_COMPAT_H
 
 #include <linux/fs.h>
+#include <linux/uaccess.h>
 #ifdef HAVE_FDTABLE_HEADER
 #include <linux/fdtable.h>
 #endif
@@ -70,6 +71,46 @@ spl_filp_fallocate(struct file *fp, int mode, loff_t offset, loff_t len)
        return (error);
 }
 
+static inline ssize_t
+spl_kernel_write(struct file *file, const void *buf, size_t count, loff_t *pos)
+{
+#if defined(HAVE_KERNEL_WRITE_PPOS)
+       return (kernel_write(file, buf, count, pos));
+#else
+       mm_segment_t saved_fs;
+       ssize_t ret;
+
+       saved_fs = get_fs();
+       set_fs(get_ds());
+
+       ret = vfs_write(file, (__force const char __user *)buf, count, pos);
+
+       set_fs(saved_fs);
+
+       return (ret);
+#endif
+}
+
+static inline ssize_t
+spl_kernel_read(struct file *file, void *buf, size_t count, loff_t *pos)
+{
+#if defined(HAVE_KERNEL_READ_PPOS)
+       return (kernel_read(file, buf, count, pos));
+#else
+       mm_segment_t saved_fs;
+       ssize_t ret;
+
+       saved_fs = get_fs();
+       set_fs(get_ds());
+
+       ret = vfs_read(file, (void __user *)buf, count, pos);
+
+       set_fs(saved_fs);
+
+       return (ret);
+#endif
+}
+
 #ifdef HAVE_2ARGS_VFS_FSYNC
 #define        spl_filp_fsync(fp, sync)        vfs_fsync(fp, sync)
 #else
index 346e63c0f1613a4af068338595db08de59fdc439..ca19d7343ca0fc0a4e7c0b12fb1d154c79cd4e0f 100644 (file)
@@ -211,35 +211,22 @@ int
 vn_rdwr(uio_rw_t uio, vnode_t *vp, void *addr, ssize_t len, offset_t off,
        uio_seg_t seg, int ioflag, rlim64_t x2, void *x3, ssize_t *residp)
 {
-       loff_t offset;
-       mm_segment_t saved_fs;
-       struct file *fp;
+       struct file *fp = vp->v_file;
+       loff_t offset = off;
        int rc;
 
        ASSERT(uio == UIO_WRITE || uio == UIO_READ);
-       ASSERT(vp);
-       ASSERT(vp->v_file);
        ASSERT(seg == UIO_SYSSPACE);
        ASSERT((ioflag & ~FAPPEND) == 0);
 
-       fp = vp->v_file;
-
-       offset = off;
        if (ioflag & FAPPEND)
                offset = fp->f_pos;
 
-       /* Writable user data segment must be briefly increased for this
-        * process so we can use the user space read call paths to write
-        * in to memory allocated by the kernel. */
-       saved_fs = get_fs();
-        set_fs(get_ds());
-
        if (uio & UIO_WRITE)
-               rc = vfs_write(fp, addr, len, &offset);
+               rc = spl_kernel_write(fp, addr, len, &offset);
        else
-               rc = vfs_read(fp, addr, len, &offset);
+               rc = spl_kernel_read(fp, addr, len, &offset);
 
-       set_fs(saved_fs);
        fp->f_pos = offset;
 
        if (rc < 0)