From 3dc463b32160b4b76d9edf631b5bcef768922769 Mon Sep 17 00:00:00 2001 From: Chhatoi Pritam Baral Date: Mon, 13 Nov 2017 13:59:20 +0530 Subject: [PATCH] Linux 4.14 compat: vfs_read/vfs_write unexported kernel_read/kernel_write have always wrapped vfs_read/vfs_write, respectively, with a safety net around casting to user pointers too. kernel_read was always exported, going back to Linux's very first git check-in. kernel_write was exported in 3.9. Linux 4.14 unexported vfs_read & vfs_write, after replacing all modular calls to these functions with kernel_read & kernel_write, respectively. Linux 4.14 also changed the signatures of kernel_read & kernel_write to more closely match vfs_read & vfs_write. Signed-off-by: Pritam Baral --- config/spl-build.m4 | 16 ++++++++++++++ module/spl/spl-vnode.c | 48 +++++++++++++++++++++++++++++++++--------- 2 files changed, 54 insertions(+), 10 deletions(-) diff --git a/config/spl-build.m4 b/config/spl-build.m4 index 8e9dc99f..b5f2dfbd 100644 --- a/config/spl-build.m4 +++ b/config/spl-build.m4 @@ -52,6 +52,7 @@ 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 ]) AC_DEFUN([SPL_AC_MODULE_SYMVERS], [ @@ -1594,3 +1595,18 @@ AC_DEFUN([SPL_AC_WAIT_QUEUE_HEAD_ENTRY], [ AC_MSG_RESULT(no) ]) ]) + +dnl # +dnl # 3.9 API introduction +dnl # kernel_write() as an improvement upon (and wrapper around) vfs_write() +dnl # +AC_DEFUN([SPL_AC_KERNEL_WRITE], [ + AC_MSG_CHECKING([whether kernel_write() is exported]) + SPL_CHECK_SYMBOL_EXPORT([kernel_write], + [],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_KERNEL_WRITE, 1, [yes]) + ],[ + AC_MSG_RESULT(no) + ]) +]) diff --git a/module/spl/spl-vnode.c b/module/spl/spl-vnode.c index 0e4c386a..05a3c1fd 100644 --- a/module/spl/spl-vnode.c +++ b/module/spl/spl-vnode.c @@ -29,6 +29,7 @@ #include #include #include +#include vnode_t *rootdir = (vnode_t *)0xabcd1234; EXPORT_SYMBOL(rootdir); @@ -207,12 +208,46 @@ vn_openat(const char *path, uio_seg_t seg, int flags, int mode, } /* vn_openat() */ EXPORT_SYMBOL(vn_openat); +static ssize_t +spl_kernel_write(struct file *file, const void *buf, size_t count, loff_t *pos) +{ +#if defined(HAVE_KERNEL_WRITE) + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0) + return kernel_write(file, buf, count, pos); +#else + return kernel_write(file, (char *)buf, count, *pos); +#endif /* LINUX_VERSION_CODE */ + +#else // We have to use the older vfs_write API + mm_segment_t old_fs; + ssize_t ret; + + old_fs = get_fs(); + set_fs(get_ds()); + /* The cast to a user pointer is valid due to the set_fs() */ + ret = vfs_write(file, (__force const char __user *)buf, count, pos); + set_fs(old_fs); + + return ret; +#endif /* HAVE_KERNEL_WRITE */ +} + +static ssize_t +spl_kernel_read(struct file *file, void *buf, size_t count, loff_t *pos) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0) + return kernel_read(file, buf, count, pos); +#else /* kernel_read had a different API before 4.14.0, but it's been available since the earliest git release of Linux */ + return kernel_read(file, *pos, (char *)buf, count); +#endif +} + 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; int rc; @@ -228,18 +263,11 @@ vn_rdwr(uio_rw_t uio, vnode_t *vp, void *addr, ssize_t len, offset_t 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)