From 7043281906b204dee38d333c79a632dfe98b29c0 Mon Sep 17 00:00:00 2001 From: Chunwei Chen Date: Wed, 18 May 2016 14:30:20 -0700 Subject: [PATCH] Linux 4.7 compat: use iterate_shared for concurrent readdir Register iterate_shared if it exists so the kernel will used shared lock and allowing concurrent readdir. Also, use shared lock when doing llseek with SEEK_DATA or SEEK_HOLE to allow concurrent seeking. Signed-off-by: Chunwei Chen Signed-off-by: Brian Behlendorf Closes #4664 Closes #4665 --- config/kernel-vfs-iterate.m4 | 49 +++++++++++++++++++++++++----------- include/sys/zpl.h | 2 +- module/zfs/zpl_ctldir.c | 18 ++++++++----- module/zfs/zpl_file.c | 10 +++++--- 4 files changed, 54 insertions(+), 25 deletions(-) diff --git a/config/kernel-vfs-iterate.m4 b/config/kernel-vfs-iterate.m4 index c2c65622ca..7b1599e132 100644 --- a/config/kernel-vfs-iterate.m4 +++ b/config/kernel-vfs-iterate.m4 @@ -1,8 +1,8 @@ -dnl # -dnl # 3.11 API change -dnl # AC_DEFUN([ZFS_AC_KERNEL_VFS_ITERATE], [ - AC_MSG_CHECKING([whether fops->iterate() is available]) + dnl # + dnl # 4.7 API change + dnl # + AC_MSG_CHECKING([whether fops->iterate_shared() is available]) ZFS_LINUX_TRY_COMPILE([ #include int iterate(struct file *filp, struct dir_context * context) @@ -10,34 +10,55 @@ AC_DEFUN([ZFS_AC_KERNEL_VFS_ITERATE], [ static const struct file_operations fops __attribute__ ((unused)) = { - .iterate = iterate, + .iterate_shared = iterate, }; ],[ ],[ AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_VFS_ITERATE, 1, - [fops->iterate() is available]) + AC_DEFINE(HAVE_VFS_ITERATE_SHARED, 1, + [fops->iterate_shared() is available]) ],[ AC_MSG_RESULT(no) - AC_MSG_CHECKING([whether fops->readdir() is available]) + dnl # + dnl # 3.11 API change + dnl # + AC_MSG_CHECKING([whether fops->iterate() is available]) ZFS_LINUX_TRY_COMPILE([ #include - int readdir(struct file *filp, void *entry, filldir_t func) + int iterate(struct file *filp, struct dir_context * context) { return 0; } static const struct file_operations fops __attribute__ ((unused)) = { - .readdir = readdir, + .iterate = iterate, }; ],[ ],[ AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_VFS_READDIR, 1, - [fops->readdir() is available]) + AC_DEFINE(HAVE_VFS_ITERATE, 1, + [fops->iterate() is available]) ],[ - AC_MSG_ERROR(no; file a bug report with ZFSOnLinux) - ]) + AC_MSG_RESULT(no) + AC_MSG_CHECKING([whether fops->readdir() is available]) + ZFS_LINUX_TRY_COMPILE([ + #include + int readdir(struct file *filp, void *entry, filldir_t func) + { return 0; } + + static const struct file_operations fops + __attribute__ ((unused)) = { + .readdir = readdir, + }; + ],[ + ],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_VFS_READDIR, 1, + [fops->readdir() is available]) + ],[ + AC_MSG_ERROR(no; file a bug report with ZFSOnLinux) + ]) + ]) ]) ]) diff --git a/include/sys/zpl.h b/include/sys/zpl.h index 54b35e02de..c6085481bb 100644 --- a/include/sys/zpl.h +++ b/include/sys/zpl.h @@ -123,7 +123,7 @@ extern const struct inode_operations zpl_ops_snapdirs; extern const struct file_operations zpl_fops_shares; extern const struct inode_operations zpl_ops_shares; -#ifdef HAVE_VFS_ITERATE +#if defined(HAVE_VFS_ITERATE) || defined(HAVE_VFS_ITERATE_SHARED) #define DIR_CONTEXT_INIT(_dirent, _actor, _pos) { \ .actor = _actor, \ diff --git a/module/zfs/zpl_ctldir.c b/module/zfs/zpl_ctldir.c index dd02e9e994..069834eae6 100644 --- a/module/zfs/zpl_ctldir.c +++ b/module/zfs/zpl_ctldir.c @@ -81,7 +81,7 @@ out: return (error); } -#if !defined(HAVE_VFS_ITERATE) +#if !defined(HAVE_VFS_ITERATE) && !defined(HAVE_VFS_ITERATE_SHARED) static int zpl_root_readdir(struct file *filp, void *dirent, filldir_t filldir) { @@ -144,7 +144,9 @@ const struct file_operations zpl_fops_root = { .open = zpl_common_open, .llseek = generic_file_llseek, .read = generic_read_dir, -#ifdef HAVE_VFS_ITERATE +#ifdef HAVE_VFS_ITERATE_SHARED + .iterate_shared = zpl_root_iterate, +#elif defined(HAVE_VFS_ITERATE) .iterate = zpl_root_iterate, #else .readdir = zpl_root_readdir, @@ -285,7 +287,7 @@ out: return (error); } -#if !defined(HAVE_VFS_ITERATE) +#if !defined(HAVE_VFS_ITERATE) && !defined(HAVE_VFS_ITERATE_SHARED) static int zpl_snapdir_readdir(struct file *filp, void *dirent, filldir_t filldir) { @@ -385,7 +387,9 @@ const struct file_operations zpl_fops_snapdir = { .open = zpl_common_open, .llseek = generic_file_llseek, .read = generic_read_dir, -#ifdef HAVE_VFS_ITERATE +#ifdef HAVE_VFS_ITERATE_SHARED + .iterate_shared = zpl_snapdir_iterate, +#elif defined(HAVE_VFS_ITERATE) .iterate = zpl_snapdir_iterate, #else .readdir = zpl_snapdir_readdir, @@ -472,7 +476,7 @@ out: return (error); } -#if !defined(HAVE_VFS_ITERATE) +#if !defined(HAVE_VFS_ITERATE) && !defined(HAVE_VFS_ITERATE_SHARED) static int zpl_shares_readdir(struct file *filp, void *dirent, filldir_t filldir) { @@ -525,7 +529,9 @@ const struct file_operations zpl_fops_shares = { .open = zpl_common_open, .llseek = generic_file_llseek, .read = generic_read_dir, -#ifdef HAVE_VFS_ITERATE +#ifdef HAVE_VFS_ITERATE_SHARED + .iterate_shared = zpl_shares_iterate, +#elif defined(HAVE_VFS_ITERATE) .iterate = zpl_shares_iterate, #else .readdir = zpl_shares_readdir, diff --git a/module/zfs/zpl_file.c b/module/zfs/zpl_file.c index 5c430c7ca8..a629b59dc9 100644 --- a/module/zfs/zpl_file.c +++ b/module/zfs/zpl_file.c @@ -93,7 +93,7 @@ zpl_iterate(struct file *filp, struct dir_context *ctx) return (error); } -#if !defined(HAVE_VFS_ITERATE) +#if !defined(HAVE_VFS_ITERATE) && !defined(HAVE_VFS_ITERATE_SHARED) static int zpl_readdir(struct file *filp, void *dirent, filldir_t filldir) { @@ -419,13 +419,13 @@ zpl_llseek(struct file *filp, loff_t offset, int whence) loff_t maxbytes = ip->i_sb->s_maxbytes; loff_t error; - spl_inode_lock(ip); + spl_inode_lock_shared(ip); cookie = spl_fstrans_mark(); error = -zfs_holey(ip, whence, &offset); spl_fstrans_unmark(cookie); if (error == 0) error = lseek_execute(filp, ip, offset, maxbytes); - spl_inode_unlock(ip); + spl_inode_unlock_shared(ip); return (error); } @@ -851,7 +851,9 @@ const struct file_operations zpl_file_operations = { const struct file_operations zpl_dir_file_operations = { .llseek = generic_file_llseek, .read = generic_read_dir, -#ifdef HAVE_VFS_ITERATE +#ifdef HAVE_VFS_ITERATE_SHARED + .iterate_shared = zpl_iterate, +#elif defined(HAVE_VFS_ITERATE) .iterate = zpl_iterate, #else .readdir = zpl_readdir,