Skip to content
This repository has been archived by the owner on Feb 26, 2020. It is now read-only.

Linux 4.14 compat: vfs_read/vfs_write => kernel_read/kernel_write #666

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
16 changes: 16 additions & 0 deletions config/spl-build.m4
Original file line number Diff line number Diff line change
Expand Up @@ -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], [
Expand Down Expand Up @@ -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)
])
])
48 changes: 38 additions & 10 deletions module/spl/spl-vnode.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <sys/kmem_cache.h>
#include <linux/falloc.h>
#include <linux/file_compat.h>
#include <linux/version.h>

vnode_t *rootdir = (vnode_t *)0xabcd1234;
EXPORT_SYMBOL(rootdir);
Expand Down Expand Up @@ -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;

Expand All @@ -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)
Expand Down