From 742e22b576390375a2d07847faa2b606a40f72c4 Mon Sep 17 00:00:00 2001 From: Brian Behlendorf Date: Fri, 5 Mar 2021 15:09:00 -0800 Subject: [PATCH 01/18] Linux 5.12 compat: inode_owner_or_capable() The inode_owner_or_capable() function was updated in the 5.12 kernel to support idmapped mounts. As part of this change the user namespace is now passed as the first argument. For non-idmapped mounts, which are currently not supported, the initial user namespace may be passed which will result in identical behavior as before. Signed-off-by: Brian Behlendorf --- config/kernel-is_owner_or_cap.m4 | 23 +++++++++++++++++++++-- include/os/linux/zfs/sys/zpl.h | 8 ++++++++ module/os/linux/zfs/policy.c | 2 +- module/os/linux/zfs/zpl_file.c | 2 +- module/os/linux/zfs/zpl_xattr.c | 4 ++-- 5 files changed, 33 insertions(+), 6 deletions(-) diff --git a/config/kernel-is_owner_or_cap.m4 b/config/kernel-is_owner_or_cap.m4 index 3df6163da270..3c3c6ad2240f 100644 --- a/config/kernel-is_owner_or_cap.m4 +++ b/config/kernel-is_owner_or_cap.m4 @@ -11,13 +11,32 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_INODE_OWNER_OR_CAPABLE], [ struct inode *ip = NULL; (void) inode_owner_or_capable(ip); ]) + + ZFS_LINUX_TEST_SRC([inode_owner_or_capable_idmapped], [ + #include + ],[ + struct inode *ip = NULL; + (void) inode_owner_or_capable(&init_user_ns, ip); + ]) ]) AC_DEFUN([ZFS_AC_KERNEL_INODE_OWNER_OR_CAPABLE], [ AC_MSG_CHECKING([whether inode_owner_or_capable() exists]) ZFS_LINUX_TEST_RESULT([inode_owner_or_capable], [ AC_MSG_RESULT(yes) - ],[ - ZFS_LINUX_TEST_ERROR([capability]) + AC_DEFINE(HAVE_INODE_OWNER_OR_CAPABLE, 1, + [inode_owner_or_capable() exists]) + ], [ + AC_MSG_RESULT(no) + + AC_MSG_CHECKING( + [whether inode_owner_or_capable() takes user_ns]) + ZFS_LINUX_TEST_RESULT([inode_owner_or_capable_idmapped], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_INODE_OWNER_OR_CAPABLE_IDMAPPED, 1, + [inode_owner_or_capable() takes user_ns]) + ],[ + ZFS_LINUX_TEST_ERROR([capability]) + ]) ]) ]) diff --git a/include/os/linux/zfs/sys/zpl.h b/include/os/linux/zfs/sys/zpl.h index b0bb9c29c0b4..da7d7e3aa52b 100644 --- a/include/os/linux/zfs/sys/zpl.h +++ b/include/os/linux/zfs/sys/zpl.h @@ -171,4 +171,12 @@ zpl_dir_emit_dots(struct file *file, zpl_dir_context_t *ctx) timespec_trunc(ts, (ip)->i_sb->s_time_gran) #endif +#if defined(HAVE_INODE_OWNER_OR_CAPABLE) +#define zpl_inode_owner_or_capable(ns, ip) inode_owner_or_capable(ip) +#elif defined(HAVE_INODE_OWNER_OR_CAPABLE_IDMAPPED) +#define zpl_inode_owner_or_capable(ns, ip) inode_owner_or_capable(ns, ip) +#else +#error "Unsupported kernel" +#endif + #endif /* _SYS_ZPL_H */ diff --git a/module/os/linux/zfs/policy.c b/module/os/linux/zfs/policy.c index 8780d7f6c70a..bbccb2e572d9 100644 --- a/module/os/linux/zfs/policy.c +++ b/module/os/linux/zfs/policy.c @@ -124,7 +124,7 @@ secpolicy_vnode_any_access(const cred_t *cr, struct inode *ip, uid_t owner) if (crgetfsuid(cr) == owner) return (0); - if (inode_owner_or_capable(ip)) + if (zpl_inode_owner_or_capable(kcred->user_ns, ip)) return (0); #if defined(CONFIG_USER_NS) diff --git a/module/os/linux/zfs/zpl_file.c b/module/os/linux/zfs/zpl_file.c index 970db4a8b73a..ea6993ffa4b0 100644 --- a/module/os/linux/zfs/zpl_file.c +++ b/module/os/linux/zfs/zpl_file.c @@ -869,7 +869,7 @@ __zpl_ioctl_setflags(struct inode *ip, uint32_t ioctl_flags, xvattr_t *xva) !capable(CAP_LINUX_IMMUTABLE)) return (-EACCES); - if (!inode_owner_or_capable(ip)) + if (!zpl_inode_owner_or_capable(kcred->user_ns, ip)) return (-EACCES); xva_init(xva); diff --git a/module/os/linux/zfs/zpl_xattr.c b/module/os/linux/zfs/zpl_xattr.c index 83812f2dcba8..971cd6ad031e 100644 --- a/module/os/linux/zfs/zpl_xattr.c +++ b/module/os/linux/zfs/zpl_xattr.c @@ -1233,7 +1233,7 @@ __zpl_xattr_acl_set_access(struct inode *ip, const char *name, if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIX) return (-EOPNOTSUPP); - if (!inode_owner_or_capable(ip)) + if (!zpl_inode_owner_or_capable(kcred->user_ns, ip)) return (-EPERM); if (value) { @@ -1273,7 +1273,7 @@ __zpl_xattr_acl_set_default(struct inode *ip, const char *name, if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIX) return (-EOPNOTSUPP); - if (!inode_owner_or_capable(ip)) + if (!zpl_inode_owner_or_capable(kcred->user_ns, ip)) return (-EPERM); if (value) { From b2ae2cc83f6520ca69a80ea3a97218db4776d8d1 Mon Sep 17 00:00:00 2001 From: Coleman Kane Date: Mon, 8 Mar 2021 14:12:42 -0500 Subject: [PATCH 02/18] Add autoconf test for xattr user_namespace arg In Linux 5.12, the filesystem API was modified to add a "struct user_namespace *" parameter to a number of handlers. One of these is the "set" member of the "struct xatter_handler" type. A new argument of type "struct user_namespace*" was inserted, which breaks compatibilty with older module code, in commit e65ce2a50cf6af216bea6fd80d771fcbb4c0aaa1. This modification was made to a bunch of other filesystem operation handlers/structs as well. Signed-off-by: Coleman Kane --- config/kernel-xattr-handler.m4 | 79 +++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 26 deletions(-) diff --git a/config/kernel-xattr-handler.m4 b/config/kernel-xattr-handler.m4 index 137bf4a8aff0..4fd59ba4c9e6 100644 --- a/config/kernel-xattr-handler.m4 +++ b/config/kernel-xattr-handler.m4 @@ -152,6 +152,21 @@ dnl # dnl # Supported xattr handler set() interfaces checked newest to oldest. dnl # AC_DEFUN([ZFS_AC_KERNEL_SRC_XATTR_HANDLER_SET], [ + ZFS_LINUX_TEST_SRC([xattr_handler_set_dentry_inode_user_ns], [ + #include + + int set(const struct xattr_handler *handler, + struct user_namespace *mnt_userns, + struct dentry *dentry, struct inode *inode, + const char *name, const void *buffer, + size_t size, int flags) + { return 0; } + static const struct xattr_handler + xops __attribute__ ((unused)) = { + .set = set, + }; + ],[]) + ZFS_LINUX_TEST_SRC([xattr_handler_set_dentry_inode], [ #include @@ -194,45 +209,57 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_XATTR_HANDLER_SET], [ AC_DEFUN([ZFS_AC_KERNEL_XATTR_HANDLER_SET], [ dnl # - dnl # 4.7 API change, - dnl # The xattr_handler->set() callback was changed to take both - dnl # dentry and inode. + dnl # 5.12 API change, + dnl # The xattr_handler->set() callback was changed to 8 arguments, and + dnl # struct user_namespace* was inserted as arg #2 dnl # - AC_MSG_CHECKING([whether xattr_handler->set() wants dentry and inode]) - ZFS_LINUX_TEST_RESULT([xattr_handler_set_dentry_inode], [ + AC_MSG_CHECKING([whether xattr_handler->set() wants dentry, inode, and user_namespace]) + ZFS_LINUX_TEST_RESULT([xattr_handler_set_dentry_inode_user_ns], [ AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_XATTR_SET_DENTRY_INODE, 1, - [xattr_handler->set() wants both dentry and inode]) + AC_DEFINE(HAVE_XATTR_SET_DENTRY_INODE_USER_NS, 1, + [xattr_handler->set() wants dentry, inode, and user_namespace]) ],[ dnl # - dnl # 4.4 API change, - dnl # The xattr_handler->set() callback was changed to take a - dnl # xattr_handler, and handler_flags argument was removed and - dnl # should be accessed by handler->flags. + dnl # 4.7 API change, + dnl # The xattr_handler->set() callback was changed to take both + dnl # dentry and inode. dnl # - AC_MSG_RESULT(no) - AC_MSG_CHECKING( - [whether xattr_handler->set() wants xattr_handler]) - ZFS_LINUX_TEST_RESULT([xattr_handler_set_xattr_handler], [ + AC_MSG_CHECKING([whether xattr_handler->set() wants dentry and inode]) + ZFS_LINUX_TEST_RESULT([xattr_handler_set_dentry_inode], [ AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_XATTR_SET_HANDLER, 1, - [xattr_handler->set() wants xattr_handler]) + AC_DEFINE(HAVE_XATTR_SET_DENTRY_INODE, 1, + [xattr_handler->set() wants both dentry and inode]) ],[ dnl # - dnl # 2.6.33 API change, - dnl # The xattr_handler->set() callback was changed - dnl # to take a dentry instead of an inode, and a - dnl # handler_flags argument was added. + dnl # 4.4 API change, + dnl # The xattr_handler->set() callback was changed to take a + dnl # xattr_handler, and handler_flags argument was removed and + dnl # should be accessed by handler->flags. dnl # AC_MSG_RESULT(no) AC_MSG_CHECKING( - [whether xattr_handler->set() wants dentry]) - ZFS_LINUX_TEST_RESULT([xattr_handler_set_dentry], [ + [whether xattr_handler->set() wants xattr_handler]) + ZFS_LINUX_TEST_RESULT([xattr_handler_set_xattr_handler], [ AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_XATTR_SET_DENTRY, 1, - [xattr_handler->set() wants dentry]) + AC_DEFINE(HAVE_XATTR_SET_HANDLER, 1, + [xattr_handler->set() wants xattr_handler]) ],[ - ZFS_LINUX_TEST_ERROR([xattr set()]) + dnl # + dnl # 2.6.33 API change, + dnl # The xattr_handler->set() callback was changed + dnl # to take a dentry instead of an inode, and a + dnl # handler_flags argument was added. + dnl # + AC_MSG_RESULT(no) + AC_MSG_CHECKING( + [whether xattr_handler->set() wants dentry]) + ZFS_LINUX_TEST_RESULT([xattr_handler_set_dentry], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_XATTR_SET_DENTRY, 1, + [xattr_handler->set() wants dentry]) + ],[ + ZFS_LINUX_TEST_ERROR([xattr set()]) + ]) ]) ]) ]) From d65b206544bd187520730255aee4d163b050cdb0 Mon Sep 17 00:00:00 2001 From: Coleman Kane Date: Sat, 13 Mar 2021 09:29:57 -0500 Subject: [PATCH 03/18] Support setattr_prepare with user_namespace arg Kernel 5.12 introduced a struct user_namespace* argument to a lot of filesystem code to support idmapped mounts. Exchanged the setattr_prepare() function for a zpl_setattr_prepare() macro that accepts the user_namespace from kcred->user_ns, and updated the refs in the source code appropriately. Signed-off-by: Coleman Kane --- config/kernel-setattr-prepare.m4 | 47 ++++++++++++++++------ include/os/linux/kernel/linux/vfs_compat.h | 2 +- include/os/linux/zfs/sys/zpl.h | 7 ++++ module/os/linux/zfs/zpl_inode.c | 2 +- 4 files changed, 44 insertions(+), 14 deletions(-) diff --git a/config/kernel-setattr-prepare.m4 b/config/kernel-setattr-prepare.m4 index 45408c45c69b..7fe81bacfec1 100644 --- a/config/kernel-setattr-prepare.m4 +++ b/config/kernel-setattr-prepare.m4 @@ -1,27 +1,50 @@ -dnl # -dnl # 4.9 API change -dnl # The inode_change_ok() function has been renamed setattr_prepare() -dnl # and updated to take a dentry rather than an inode. -dnl # AC_DEFUN([ZFS_AC_KERNEL_SRC_SETATTR_PREPARE], [ + dnl # + dnl # 4.9 API change + dnl # The inode_change_ok() function has been renamed setattr_prepare() + dnl # and updated to take a dentry rather than an inode. + dnl # ZFS_LINUX_TEST_SRC([setattr_prepare], [ #include ], [ struct dentry *dentry = NULL; struct iattr *attr = NULL; int error __attribute__ ((unused)) = - setattr_prepare(dentry, attr); + setattr_prepare(dentry, attr); + ]) + + dnl # + dnl # 5.12 API change + dnl # The setattr_prepare() function has been changed to accept a new argument + dnl # for struct user_namespace* + dnl # + ZFS_LINUX_TEST_SRC([setattr_prepare_userns], [ + #include + ], [ + struct dentry *dentry = NULL; + struct iattr *attr = NULL; + struct user_namespace *userns = NULL; + int error __attribute__ ((unused)) = + setattr_prepare(userns, dentry, attr); ]) ]) AC_DEFUN([ZFS_AC_KERNEL_SETATTR_PREPARE], [ - AC_MSG_CHECKING([whether setattr_prepare() is available]) - ZFS_LINUX_TEST_RESULT_SYMBOL([setattr_prepare], - [setattr_prepare], [fs/attr.c], [ + AC_MSG_CHECKING([whether setattr_prepare() is available and accepts struct user_namespace*]) + ZFS_LINUX_TEST_RESULT_SYMBOL([setattr_prepare_userns], + [setattr_prepare_userns], [fs/attr.c], [ AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_SETATTR_PREPARE, 1, - [setattr_prepare() is available]) + AC_DEFINE(HAVE_SETATTR_PREPARE_USERNS, 1, + [setattr_prepare() accepts user_namespace]) ], [ - AC_MSG_RESULT(no) + AC_MSG_CHECKING([whether setattr_prepare() is available, doesn't accept user_namespace]) + ZFS_LINUX_TEST_RESULT_SYMBOL([setattr_prepare], + [setattr_prepare], [fs/attr.c], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_SETATTR_PREPARE_NO_USERNS, 1, + [setattr_prepare() is available, doesn't accept user_namespace]) + ], [ + AC_MSG_RESULT(no) + ]) ]) ]) diff --git a/include/os/linux/kernel/linux/vfs_compat.h b/include/os/linux/kernel/linux/vfs_compat.h index c35e80d31cd7..da1f08e443ec 100644 --- a/include/os/linux/kernel/linux/vfs_compat.h +++ b/include/os/linux/kernel/linux/vfs_compat.h @@ -343,7 +343,7 @@ static inline void zfs_gid_write(struct inode *ip, gid_t gid) /* * 4.9 API change */ -#ifndef HAVE_SETATTR_PREPARE +#if !(defined(HAVE_SETATTR_PREPARE_NO_USERNS) || defined(HAVE_SETATTR_PREPARE_USERNS)) static inline int setattr_prepare(struct dentry *dentry, struct iattr *ia) { diff --git a/include/os/linux/zfs/sys/zpl.h b/include/os/linux/zfs/sys/zpl.h index da7d7e3aa52b..2e5a1f0aff4d 100644 --- a/include/os/linux/zfs/sys/zpl.h +++ b/include/os/linux/zfs/sys/zpl.h @@ -179,4 +179,11 @@ zpl_dir_emit_dots(struct file *file, zpl_dir_context_t *ctx) #error "Unsupported kernel" #endif +#if defined(HAVE_SETATTR_PREPARE_USERNS) +#define zpl_setattr_prepare(ns, dentry, ia) setattr_prepare(ns, dentry, ia) +#else + /* Use kernel-provided version, or our own from linux/vfs_compat.h */ +#define zpl_setattr_prepare(ns, dentry, ia) setattr_prepare(dentry, ia) +#endif + #endif /* _SYS_ZPL_H */ diff --git a/module/os/linux/zfs/zpl_inode.c b/module/os/linux/zfs/zpl_inode.c index e79d334edc9b..3b009908a5c5 100644 --- a/module/os/linux/zfs/zpl_inode.c +++ b/module/os/linux/zfs/zpl_inode.c @@ -367,7 +367,7 @@ zpl_setattr(struct dentry *dentry, struct iattr *ia) int error; fstrans_cookie_t cookie; - error = setattr_prepare(dentry, ia); + error = zpl_setattr_prepare(kcred->user_ns, dentry, ia); if (error) return (error); From 56aa180b837b3e4a37b0c3a3ef500ee4ed6c082f Mon Sep 17 00:00:00 2001 From: Coleman Kane Date: Sat, 13 Mar 2021 09:47:06 -0500 Subject: [PATCH 04/18] Add missing "no" in compatibility check for setattr_prepare Signed-off-by: Coleman Kane --- config/kernel-setattr-prepare.m4 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config/kernel-setattr-prepare.m4 b/config/kernel-setattr-prepare.m4 index 7fe81bacfec1..9ae7d35660ad 100644 --- a/config/kernel-setattr-prepare.m4 +++ b/config/kernel-setattr-prepare.m4 @@ -37,6 +37,8 @@ AC_DEFUN([ZFS_AC_KERNEL_SETATTR_PREPARE], [ AC_DEFINE(HAVE_SETATTR_PREPARE_USERNS, 1, [setattr_prepare() accepts user_namespace]) ], [ + AC_MSG_RESULT(no) + AC_MSG_CHECKING([whether setattr_prepare() is available, doesn't accept user_namespace]) ZFS_LINUX_TEST_RESULT_SYMBOL([setattr_prepare], [setattr_prepare], [fs/attr.c], [ From 62f80b72f59b3bd44cd06d6a189190e7fccfbbf2 Mon Sep 17 00:00:00 2001 From: Coleman Kane Date: Sat, 13 Mar 2021 10:18:37 -0500 Subject: [PATCH 05/18] Fix copypasta in the setattr_prepare() version tests The first arg to ZFS_LINUX_TEST_RESULT_SYMBOL is the base .ko filename, used earlier in the test definition, but the second argument is the name of the symbol we're looking for being exported. While the filename changed to define a new test result, the exported symbol name didn't, as the function has the same name on kernel 5.12 as it does for linux<5.12. Signed-off-by: Coleman Kane --- config/kernel-setattr-prepare.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/kernel-setattr-prepare.m4 b/config/kernel-setattr-prepare.m4 index 9ae7d35660ad..24245aa53448 100644 --- a/config/kernel-setattr-prepare.m4 +++ b/config/kernel-setattr-prepare.m4 @@ -32,7 +32,7 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_SETATTR_PREPARE], [ AC_DEFUN([ZFS_AC_KERNEL_SETATTR_PREPARE], [ AC_MSG_CHECKING([whether setattr_prepare() is available and accepts struct user_namespace*]) ZFS_LINUX_TEST_RESULT_SYMBOL([setattr_prepare_userns], - [setattr_prepare_userns], [fs/attr.c], [ + [setattr_prepare], [fs/attr.c], [ AC_MSG_RESULT(yes) AC_DEFINE(HAVE_SETATTR_PREPARE_USERNS, 1, [setattr_prepare() accepts user_namespace]) From a544adeee0e4610aafa9035544b28b087a8654e4 Mon Sep 17 00:00:00 2001 From: Coleman Kane Date: Sat, 13 Mar 2021 10:24:03 -0500 Subject: [PATCH 06/18] Support inode_operations->getattr w/ user_namespace Kernel 5.12 added the struct user_namespace* arg to the getattr method in the struct inode_operations definition, to support idmapped io operations. This change modifies the configure tests, as well as implements the appropriate macro definition to handle the linux 5.12 API change, for the getattr handler. Signed-off-by: Coleman Kane --- config/kernel-inode-getattr.m4 | 63 +++++++++++++++++----- include/os/linux/kernel/linux/vfs_compat.h | 8 +++ 2 files changed, 59 insertions(+), 12 deletions(-) diff --git a/config/kernel-inode-getattr.m4 b/config/kernel-inode-getattr.m4 index 48391d66f8bd..f62e82f5230a 100644 --- a/config/kernel-inode-getattr.m4 +++ b/config/kernel-inode-getattr.m4 @@ -1,8 +1,29 @@ -dnl # -dnl # Linux 4.11 API -dnl # See torvalds/linux@a528d35 -dnl # AC_DEFUN([ZFS_AC_KERNEL_SRC_INODE_GETATTR], [ + dnl # + dnl # Linux 5.12 API + dnl # The getattr I/O operations handler type was extended to require + dnl # a struct user_namespace* as its first arg, to support idmapped + dnl # mounts. + dnl # + ZFS_LINUX_TEST_SRC([inode_operations_getattr_userns], [ + #include + + int test_getattr( + struct user_namespace *userns, + const struct path *p, struct kstat *k, + u32 request_mask, unsigned int query_flags) + { return 0; } + + static const struct inode_operations + iops __attribute__ ((unused)) = { + .getattr = test_getattr, + }; + ],[]) + + dnl # + dnl # Linux 4.11 API + dnl # See torvalds/linux@a528d35 + dnl # ZFS_LINUX_TEST_SRC([inode_operations_getattr_path], [ #include @@ -33,21 +54,39 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_INODE_GETATTR], [ ]) AC_DEFUN([ZFS_AC_KERNEL_INODE_GETATTR], [ - AC_MSG_CHECKING([whether iops->getattr() takes a path]) - ZFS_LINUX_TEST_RESULT([inode_operations_getattr_path], [ + dnl # + dnl # Kernel 5.12 test + dnl # + AC_MSG_CHECKING([whether iops->getattr() takes user_namespace]) + ZFS_LINUX_TEST_RESULT([inode_operations_getattr_userns], [ AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_PATH_IOPS_GETATTR, 1, - [iops->getattr() takes a path]) + AC_DEFINE(HAVE_USERNS_IOPS_GETATTR, 1, + [iops->getattr() takes struct user_namespace*]) ],[ AC_MSG_RESULT(no) - AC_MSG_CHECKING([whether iops->getattr() takes a vfsmount]) - ZFS_LINUX_TEST_RESULT([inode_operations_getattr_vfsmount], [ + dnl # + dnl # Kernel 4.11 test + dnl # + AC_MSG_CHECKING([whether iops->getattr() takes a path]) + ZFS_LINUX_TEST_RESULT([inode_operations_getattr_path], [ AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_VFSMOUNT_IOPS_GETATTR, 1, - [iops->getattr() takes a vfsmount]) + AC_DEFINE(HAVE_PATH_IOPS_GETATTR, 1, + [iops->getattr() takes a path]) ],[ AC_MSG_RESULT(no) + + dnl # + dnl # Kernel < 4.11 test + dnl # + AC_MSG_CHECKING([whether iops->getattr() takes a vfsmount]) + ZFS_LINUX_TEST_RESULT([inode_operations_getattr_vfsmount], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_VFSMOUNT_IOPS_GETATTR, 1, + [iops->getattr() takes a vfsmount]) + ],[ + AC_MSG_RESULT(no) + ]) ]) ]) ]) diff --git a/include/os/linux/kernel/linux/vfs_compat.h b/include/os/linux/kernel/linux/vfs_compat.h index da1f08e443ec..3c651b7df887 100644 --- a/include/os/linux/kernel/linux/vfs_compat.h +++ b/include/os/linux/kernel/linux/vfs_compat.h @@ -389,6 +389,14 @@ func(const struct path *path, struct kstat *stat, u32 request_mask, \ { \ return (func##_impl(path, stat, request_mask, query_flags)); \ } +#elif defined(HAVE_USERNS_IOPS_GETATTR) +#define ZPL_GETATTR_WRAPPER(func) \ +static int \ +func(struct user_namespace *user_ns,const struct path *path, \ + struct kstat *stat, u32 request_mask, unsigned int query_flags) \ +{ \ + return (func##_impl(user_ns, path, stat, request_mask, query_flags)); \ +} #else #error #endif From 0ff5d72c28888f77ade0cb9da31b5f832bb2d23a Mon Sep 17 00:00:00 2001 From: Coleman Kane Date: Sat, 13 Mar 2021 11:56:38 -0500 Subject: [PATCH 07/18] zpl_*_getattr_impl functions updated for user_namespace change A bunch of the implementation functions for the getattr handler in different parts of the driver need to be updated to match the Linux 5.12 idmapped capability. This adds a new first argument to all of them that is the struct user_namespace* argument, if support for it is detected in the kernel during configure. Signed-off-by: Coleman Kane --- module/os/linux/zfs/zpl_ctldir.c | 24 +++++++++++++++++++++--- module/os/linux/zfs/zpl_inode.c | 6 ++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/module/os/linux/zfs/zpl_ctldir.c b/module/os/linux/zfs/zpl_ctldir.c index e6420f19ed87..3044e70c8dcf 100644 --- a/module/os/linux/zfs/zpl_ctldir.c +++ b/module/os/linux/zfs/zpl_ctldir.c @@ -101,8 +101,14 @@ zpl_root_readdir(struct file *filp, void *dirent, filldir_t filldir) */ /* ARGSUSED */ static int +#ifdef HAVE_USERNS_IOPS_GETATTR +zpl_root_getattr_impl(struct user_namespace *user_ns, + const struct path *path, struct kstat *stat, u32 request_mask, + unsigned int query_flags) +#else zpl_root_getattr_impl(const struct path *path, struct kstat *stat, - u32 request_mask, unsigned int query_flags) + u32 request_mask, unsigned int query_flags) +#endif { struct inode *ip = path->dentry->d_inode; @@ -363,8 +369,14 @@ zpl_snapdir_mkdir(struct inode *dip, struct dentry *dentry, umode_t mode) */ /* ARGSUSED */ static int +#ifdef HAVE_USERNS_IOPS_GETATTR +zpl_snapdir_getattr_impl(struct user_namespace *user_ns, + const struct path *path, struct kstat *stat, u32 request_mask, + unsigned int query_flags) +#else zpl_snapdir_getattr_impl(const struct path *path, struct kstat *stat, - u32 request_mask, unsigned int query_flags) + u32 request_mask, unsigned int query_flags) +#endif { struct inode *ip = path->dentry->d_inode; zfsvfs_t *zfsvfs = ITOZSB(ip); @@ -495,8 +507,14 @@ zpl_shares_readdir(struct file *filp, void *dirent, filldir_t filldir) /* ARGSUSED */ static int +#ifdef HAVE_USERNS_IOPS_GETATTR +zpl_shares_getattr_impl(struct user_namespace *user_ns, + const struct path *path, struct kstat *stat, u32 request_mask, + unsigned int query_flags) +#else zpl_shares_getattr_impl(const struct path *path, struct kstat *stat, - u32 request_mask, unsigned int query_flags) + u32 request_mask, unsigned int query_flags) +#endif { struct inode *ip = path->dentry->d_inode; zfsvfs_t *zfsvfs = ITOZSB(ip); diff --git a/module/os/linux/zfs/zpl_inode.c b/module/os/linux/zfs/zpl_inode.c index 3b009908a5c5..9c986dfdb64a 100644 --- a/module/os/linux/zfs/zpl_inode.c +++ b/module/os/linux/zfs/zpl_inode.c @@ -338,8 +338,14 @@ zpl_rmdir(struct inode *dir, struct dentry *dentry) } static int +#ifdef HAVE_USERNS_IOPS_GETATTR +zpl_getattr_impl(struct user_namespace *user_ns, + const struct path *path, struct kstat *stat, u32 request_mask, + unsigned int query_flags) +#else zpl_getattr_impl(const struct path *path, struct kstat *stat, u32 request_mask, unsigned int query_flags) +#endif { int error; fstrans_cookie_t cookie; From c48a6181ef69c2dedb932102ed7cff2cbb332583 Mon Sep 17 00:00:00 2001 From: Coleman Kane Date: Sat, 13 Mar 2021 12:00:25 -0500 Subject: [PATCH 08/18] Fix zfs_getattr_fast to chase 5.12 API user_namespace addition The zfs_getattr_fast() function also needs to accept and use the user_namespace argument, introduced in kernel 5.12, and as well every place that calls generic_fillattr() needs to adopt the new API. This commit adds M4 code to config/ that detects the newer generic_fillattr() API, and conditionally compiles code elsewhere accordingly. Signed-off-by: Coleman Kane --- config/kernel-generic_fillattr.m4 | 28 +++++++++++++++++++++++++ config/kernel.m4 | 2 ++ include/os/linux/zfs/sys/zfs_vnops_os.h | 5 +++++ module/os/linux/zfs/zfs_vnops_os.c | 9 ++++++++ module/os/linux/zfs/zpl_ctldir.c | 16 ++++++++++++++ 5 files changed, 60 insertions(+) create mode 100644 config/kernel-generic_fillattr.m4 diff --git a/config/kernel-generic_fillattr.m4 b/config/kernel-generic_fillattr.m4 new file mode 100644 index 000000000000..50c8031305b3 --- /dev/null +++ b/config/kernel-generic_fillattr.m4 @@ -0,0 +1,28 @@ +dnl # +dnl # 5.12 API +dnl # +dnl # generic_fillattr in linux/fs.h now requires a struct user_namespace* +dnl # as the first arg, to support idmapped mounts. +dnl # +AC_DEFUN([ZFS_AC_KERNEL_SRC_GENERIC_FILLATTR_USERNS], [ + ZFS_LINUX_TEST_SRC([generic_fillattr_userns], [ + #include + ],[ + struct user_namespace *userns = NULL; + struct inode *in = NULL; + struct kstat *k = NULL; + generic_fillattr(userns, in, k); + ]) +]) + +AC_DEFUN([ZFS_AC_KERNEL_GENERIC_FILLATTR_USERNS], [ + AC_MSG_CHECKING([whether generic_fillattr requres struct user_namespace*]) + ZFS_LINUX_TEST_RESULT([generic_fillattr_userns], [ + AC_MSG_RESULT([yes]) + AC_DEFINE(HAVE_GENERIC_FILLATTR_USERNS, 1, + [generic_fillattr requires struct user_namespace*]) + ],[ + AC_MSG_RESULT([no]) + ]) +]) + diff --git a/config/kernel.m4 b/config/kernel.m4 index f31be845f5d9..b73b7b695157 100644 --- a/config/kernel.m4 +++ b/config/kernel.m4 @@ -125,6 +125,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [ ZFS_AC_KERNEL_SRC_KSTRTOUL ZFS_AC_KERNEL_SRC_PERCPU ZFS_AC_KERNEL_SRC_CPU_HOTPLUG + ZFS_AC_KERNEL_SRC_GENERIC_FILLATTR_USERNS AC_MSG_CHECKING([for available kernel interfaces]) ZFS_LINUX_TEST_COMPILE_ALL([kabi]) @@ -223,6 +224,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [ ZFS_AC_KERNEL_KSTRTOUL ZFS_AC_KERNEL_PERCPU ZFS_AC_KERNEL_CPU_HOTPLUG + ZFS_AC_KERNEL_GENERIC_FILLATTR_USERNS ]) dnl # diff --git a/include/os/linux/zfs/sys/zfs_vnops_os.h b/include/os/linux/zfs/sys/zfs_vnops_os.h index ef76de3e2981..f42e11759eeb 100644 --- a/include/os/linux/zfs/sys/zfs_vnops_os.h +++ b/include/os/linux/zfs/sys/zfs_vnops_os.h @@ -54,7 +54,12 @@ extern int zfs_mkdir(znode_t *dzp, char *dirname, vattr_t *vap, extern int zfs_rmdir(znode_t *dzp, char *name, znode_t *cwd, cred_t *cr, int flags); extern int zfs_readdir(struct inode *ip, zpl_dir_context_t *ctx, cred_t *cr); +#ifdef HAVE_GENERIC_FILLATTR_USERNS +extern int zfs_getattr_fast(struct user_namespace *, struct inode *ip, + struct kstat *sp); +#else extern int zfs_getattr_fast(struct inode *ip, struct kstat *sp); +#endif extern int zfs_setattr(znode_t *zp, vattr_t *vap, int flag, cred_t *cr); extern int zfs_rename(znode_t *sdzp, char *snm, znode_t *tdzp, char *tnm, cred_t *cr, int flags); diff --git a/module/os/linux/zfs/zfs_vnops_os.c b/module/os/linux/zfs/zfs_vnops_os.c index 84c33b541ea3..0d9f88b778cb 100644 --- a/module/os/linux/zfs/zfs_vnops_os.c +++ b/module/os/linux/zfs/zfs_vnops_os.c @@ -1656,7 +1656,12 @@ zfs_readdir(struct inode *ip, zpl_dir_context_t *ctx, cred_t *cr) */ /* ARGSUSED */ int +#ifdef HAVE_GENERIC_FILLATTR_USERNS +zfs_getattr_fast(struct user_namespace *user_ns, struct inode *ip, + struct kstat *sp) +#else zfs_getattr_fast(struct inode *ip, struct kstat *sp) +#endif { znode_t *zp = ITOZ(ip); zfsvfs_t *zfsvfs = ITOZSB(ip); @@ -1668,7 +1673,11 @@ zfs_getattr_fast(struct inode *ip, struct kstat *sp) mutex_enter(&zp->z_lock); +#ifdef HAVE_GENERIC_FILLATTR_USERNS + generic_fillattr(user_ns, ip, sp); +#else generic_fillattr(ip, sp); +#endif /* * +1 link count for root inode with visible '.zfs' directory. */ diff --git a/module/os/linux/zfs/zpl_ctldir.c b/module/os/linux/zfs/zpl_ctldir.c index 3044e70c8dcf..e8c7e00d4fda 100644 --- a/module/os/linux/zfs/zpl_ctldir.c +++ b/module/os/linux/zfs/zpl_ctldir.c @@ -112,7 +112,11 @@ zpl_root_getattr_impl(const struct path *path, struct kstat *stat, { struct inode *ip = path->dentry->d_inode; +#if defined(HAVE_GENERIC_FILLATTR_USERNS) && defined(HAVE_USERNS_IOPS_GETATTR) + generic_fillattr(user_ns, ip, stat); +#else generic_fillattr(ip, stat); +#endif stat->atime = current_time(ip); return (0); @@ -382,7 +386,11 @@ zpl_snapdir_getattr_impl(const struct path *path, struct kstat *stat, zfsvfs_t *zfsvfs = ITOZSB(ip); ZPL_ENTER(zfsvfs); +#if defined(HAVE_GENERIC_FILLATTR_USERNS) && defined(HAVE_USERNS_IOPS_GETATTR) + generic_fillattr(user_ns, ip, stat); +#else generic_fillattr(ip, stat); +#endif stat->nlink = stat->size = 2; stat->ctime = stat->mtime = dmu_objset_snap_cmtime(zfsvfs->z_os); @@ -524,7 +532,11 @@ zpl_shares_getattr_impl(const struct path *path, struct kstat *stat, ZPL_ENTER(zfsvfs); if (zfsvfs->z_shares_dir == 0) { +#if defined(HAVE_GENERIC_FILLATTR_USERNS) && defined(HAVE_USERNS_IOPS_GETATTR) + generic_fillattr(user_ns, path->dentry->d_inode, stat); +#else generic_fillattr(path->dentry->d_inode, stat); +#endif stat->nlink = stat->size = 2; stat->atime = current_time(ip); ZPL_EXIT(zfsvfs); @@ -533,7 +545,11 @@ zpl_shares_getattr_impl(const struct path *path, struct kstat *stat, error = -zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp); if (error == 0) { +#if defined(HAVE_GENERIC_FILLATTR_USERNS) && defined(HAVE_USERNS_IOPS_GETATTR) + error = -zfs_getattr_fast(user_ns, ZTOI(dzp), stat); +#else error = -zfs_getattr_fast(ZTOI(dzp), stat); +#endif iput(ZTOI(dzp)); } From 70f3b8bdb0933338506cc8d2e18bac7cc2a9df4a Mon Sep 17 00:00:00 2001 From: Coleman Kane Date: Sun, 14 Mar 2021 11:08:22 -0400 Subject: [PATCH 09/18] mkdir() updates for user_namespace arg addition in 5.12 This commit implements a few small fixes to bring the zpl_snapdir_mkdir() implementation to compatibility with 5.12 and its idmapped mounts addition. Signed-off-by: Coleman Kane --- config/kernel-mkdir-umode-t.m4 | 32 ---------------- config/kernel-mkdir.m4 | 65 ++++++++++++++++++++++++++++++++ config/kernel.m4 | 4 +- module/os/linux/zfs/zpl_ctldir.c | 5 +++ 4 files changed, 72 insertions(+), 34 deletions(-) delete mode 100644 config/kernel-mkdir-umode-t.m4 create mode 100644 config/kernel-mkdir.m4 diff --git a/config/kernel-mkdir-umode-t.m4 b/config/kernel-mkdir-umode-t.m4 deleted file mode 100644 index 19599670df3b..000000000000 --- a/config/kernel-mkdir-umode-t.m4 +++ /dev/null @@ -1,32 +0,0 @@ -dnl # -dnl # 3.3 API change -dnl # The VFS .create, .mkdir and .mknod callbacks were updated to take a -dnl # umode_t type rather than an int. The expectation is that any backport -dnl # would also change all three prototypes. However, if it turns out that -dnl # some distribution doesn't backport the whole thing this could be -dnl # broken apart into three separate checks. -dnl # -AC_DEFUN([ZFS_AC_KERNEL_SRC_MKDIR_UMODE_T], [ - ZFS_LINUX_TEST_SRC([inode_operations_mkdir], [ - #include - - int mkdir(struct inode *inode, struct dentry *dentry, - umode_t umode) { return 0; } - - static const struct inode_operations - iops __attribute__ ((unused)) = { - .mkdir = mkdir, - }; - ],[]) -]) - -AC_DEFUN([ZFS_AC_KERNEL_MKDIR_UMODE_T], [ - AC_MSG_CHECKING([whether iops->create()/mkdir()/mknod() take umode_t]) - ZFS_LINUX_TEST_RESULT([inode_operations_mkdir], [ - AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_MKDIR_UMODE_T, 1, - [iops->create()/mkdir()/mknod() take umode_t]) - ],[ - ZFS_LINUX_TEST_ERROR([mkdir()]) - ]) -]) diff --git a/config/kernel-mkdir.m4 b/config/kernel-mkdir.m4 new file mode 100644 index 000000000000..a162bcd880ff --- /dev/null +++ b/config/kernel-mkdir.m4 @@ -0,0 +1,65 @@ +dnl # +dnl # Supported mkdir() interfaces checked newest to oldest. +dnl # +AC_DEFUN([ZFS_AC_KERNEL_SRC_MKDIR], [ + dnl # + dnl # 5.12 API change + dnl # The struct user_namespace arg was added as the first argument to + dnl # mkdir() + dnl # + ZFS_LINUX_TEST_SRC([mkdir_user_namespace], [ + #include + + int mkdir(struct user_namespace *userns, + struct inode *inode, struct dentry *dentry, + umode_t umode) { return 0; } + + static const struct inode_operations + iops __attribute__ ((unused)) = { + .mkdir = mkdir, + }; + ],[]) + + dnl # + dnl # 3.3 API change + dnl # The VFS .create, .mkdir and .mknod callbacks were updated to take a + dnl # umode_t type rather than an int. The expectation is that any backport + dnl # would also change all three prototypes. However, if it turns out that + dnl # some distribution doesn't backport the whole thing this could be + dnl # broken apart into three separate checks. + dnl # + ZFS_LINUX_TEST_SRC([inode_operations_mkdir], [ + #include + + int mkdir(struct inode *inode, struct dentry *dentry, + umode_t umode) { return 0; } + + static const struct inode_operations + iops __attribute__ ((unused)) = { + .mkdir = mkdir, + }; + ],[]) +]) + +AC_DEFUN([ZFS_AC_KERNEL_MKDIR], [ + dnl # + dnl # 5.12 API change + dnl # The struct user_namespace arg was added as the first argument to + dnl # mkdir() of the iops structure. + dnl # + AC_MSG_CHECKING([whether iops->mkdir() takes struct user_namespace*]) + ZFS_LINUX_TEST_RESULT([mkdir_user_namespace], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_IOPS_MKDIR_USERNS, 1, + [iops->mkdir() takes struct user_namespace*]) + ],[ + AC_MSG_CHECKING([whether iops->mkdir() takes umode_t]) + ZFS_LINUX_TEST_RESULT([inode_operations_mkdir], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_MKDIR_UMODE_T, 1, + [iops->mkdir() takes umode_t]) + ],[ + ZFS_LINUX_TEST_ERROR([mkdir()]) + ]) + ]) +]) diff --git a/config/kernel.m4 b/config/kernel.m4 index b73b7b695157..cf220a164769 100644 --- a/config/kernel.m4 +++ b/config/kernel.m4 @@ -79,7 +79,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [ ZFS_AC_KERNEL_SRC_EVICT_INODE ZFS_AC_KERNEL_SRC_DIRTY_INODE ZFS_AC_KERNEL_SRC_SHRINKER - ZFS_AC_KERNEL_SRC_MKDIR_UMODE_T + ZFS_AC_KERNEL_SRC_MKDIR ZFS_AC_KERNEL_SRC_LOOKUP_FLAGS ZFS_AC_KERNEL_SRC_CREATE_FLAGS ZFS_AC_KERNEL_SRC_GET_LINK @@ -178,7 +178,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [ ZFS_AC_KERNEL_EVICT_INODE ZFS_AC_KERNEL_DIRTY_INODE ZFS_AC_KERNEL_SHRINKER - ZFS_AC_KERNEL_MKDIR_UMODE_T + ZFS_AC_KERNEL_MKDIR ZFS_AC_KERNEL_LOOKUP_FLAGS ZFS_AC_KERNEL_CREATE_FLAGS ZFS_AC_KERNEL_GET_LINK diff --git a/module/os/linux/zfs/zpl_ctldir.c b/module/os/linux/zfs/zpl_ctldir.c index e8c7e00d4fda..393fd122b901 100644 --- a/module/os/linux/zfs/zpl_ctldir.c +++ b/module/os/linux/zfs/zpl_ctldir.c @@ -343,7 +343,12 @@ zpl_snapdir_rmdir(struct inode *dip, struct dentry *dentry) } static int +#ifdef HAVE_IOPS_MKDIR_USERNS +zpl_snapdir_mkdir(struct user_namespace *user_ns, struct inode *dip, + struct dentry *dentry, umode_t mode) +#else zpl_snapdir_mkdir(struct inode *dip, struct dentry *dentry, umode_t mode) +#endif { cred_t *cr = CRED(); vattr_t *vap; From ff82ed1cb1e445f1cd6eaddca70f9e74fb11d2f5 Mon Sep 17 00:00:00 2001 From: Coleman Kane Date: Sun, 14 Mar 2021 11:10:35 -0400 Subject: [PATCH 10/18] Use correct gersion of zfs_getattr_fast() for 5.12 kernel Update to chase that zfs_getattr_fast() will need to have the correct version called where getattr() requires a struct user_namespace* argument. Signed-off-by: Coleman Kane --- module/os/linux/zfs/zpl_inode.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/module/os/linux/zfs/zpl_inode.c b/module/os/linux/zfs/zpl_inode.c index 9c986dfdb64a..8cfe9e9a5f08 100644 --- a/module/os/linux/zfs/zpl_inode.c +++ b/module/os/linux/zfs/zpl_inode.c @@ -356,7 +356,11 @@ zpl_getattr_impl(const struct path *path, struct kstat *stat, u32 request_mask, * XXX request_mask and query_flags currently ignored. */ +#ifdef HAVE_USERNS_IOPS_GETATTR + error = -zfs_getattr_fast(user_ns, path->dentry->d_inode, stat); +#else error = -zfs_getattr_fast(path->dentry->d_inode, stat); +#endif spl_fstrans_unmark(cookie); ASSERT3S(error, <=, 0); From f5d30cd7373811accd4a53fc4a89bbab58dc20a8 Mon Sep 17 00:00:00 2001 From: Coleman Kane Date: Sun, 14 Mar 2021 11:17:31 -0400 Subject: [PATCH 11/18] Whitespace fixes (line continuations, and other things) Some of the line continuations were converted from 4-spaces to a tab in my earlier edits. This commit restores them to project style guidelines. Additionally, there were a few other style regressions that I went through and resolved. Signed-off-by: Coleman Kane --- include/os/linux/kernel/linux/vfs_compat.h | 10 ++++++---- include/os/linux/zfs/sys/zpl.h | 9 ++++++--- module/os/linux/zfs/zfs_vnops_os.c | 2 +- module/os/linux/zfs/zpl_ctldir.c | 20 ++++++++++---------- module/os/linux/zfs/zpl_inode.c | 2 +- 5 files changed, 24 insertions(+), 19 deletions(-) diff --git a/include/os/linux/kernel/linux/vfs_compat.h b/include/os/linux/kernel/linux/vfs_compat.h index 3c651b7df887..8395bb7386d8 100644 --- a/include/os/linux/kernel/linux/vfs_compat.h +++ b/include/os/linux/kernel/linux/vfs_compat.h @@ -343,7 +343,8 @@ static inline void zfs_gid_write(struct inode *ip, gid_t gid) /* * 4.9 API change */ -#if !(defined(HAVE_SETATTR_PREPARE_NO_USERNS) || defined(HAVE_SETATTR_PREPARE_USERNS)) +#if !(defined(HAVE_SETATTR_PREPARE_NO_USERNS) || \ + defined(HAVE_SETATTR_PREPARE_USERNS)) static inline int setattr_prepare(struct dentry *dentry, struct iattr *ia) { @@ -392,10 +393,11 @@ func(const struct path *path, struct kstat *stat, u32 request_mask, \ #elif defined(HAVE_USERNS_IOPS_GETATTR) #define ZPL_GETATTR_WRAPPER(func) \ static int \ -func(struct user_namespace *user_ns,const struct path *path, \ - struct kstat *stat, u32 request_mask, unsigned int query_flags) \ +func(struct user_namespace *user_ns, const struct path *path, \ + struct kstat *stat, u32 request_mask, unsigned int query_flags) \ { \ - return (func##_impl(user_ns, path, stat, request_mask, query_flags)); \ + return (func##_impl(user_ns, path, stat, request_mask, \ + query_flags)); \ } #else #error diff --git a/include/os/linux/zfs/sys/zpl.h b/include/os/linux/zfs/sys/zpl.h index 2e5a1f0aff4d..945a55cca36a 100644 --- a/include/os/linux/zfs/sys/zpl.h +++ b/include/os/linux/zfs/sys/zpl.h @@ -180,10 +180,13 @@ zpl_dir_emit_dots(struct file *file, zpl_dir_context_t *ctx) #endif #if defined(HAVE_SETATTR_PREPARE_USERNS) -#define zpl_setattr_prepare(ns, dentry, ia) setattr_prepare(ns, dentry, ia) +#define zpl_setattr_prepare(ns, dentry, ia) setattr_prepare(ns, dentry, ia) #else - /* Use kernel-provided version, or our own from linux/vfs_compat.h */ -#define zpl_setattr_prepare(ns, dentry, ia) setattr_prepare(dentry, ia) +/* + * Use kernel-provided version, or our own from + * linux/vfs_compat.h + */ +#define zpl_setattr_prepare(ns, dentry, ia) setattr_prepare(dentry, ia) #endif #endif /* _SYS_ZPL_H */ diff --git a/module/os/linux/zfs/zfs_vnops_os.c b/module/os/linux/zfs/zfs_vnops_os.c index 0d9f88b778cb..d336abd50cf2 100644 --- a/module/os/linux/zfs/zfs_vnops_os.c +++ b/module/os/linux/zfs/zfs_vnops_os.c @@ -1658,7 +1658,7 @@ zfs_readdir(struct inode *ip, zpl_dir_context_t *ctx, cred_t *cr) int #ifdef HAVE_GENERIC_FILLATTR_USERNS zfs_getattr_fast(struct user_namespace *user_ns, struct inode *ip, - struct kstat *sp) + struct kstat *sp) #else zfs_getattr_fast(struct inode *ip, struct kstat *sp) #endif diff --git a/module/os/linux/zfs/zpl_ctldir.c b/module/os/linux/zfs/zpl_ctldir.c index 393fd122b901..f79d905b99cd 100644 --- a/module/os/linux/zfs/zpl_ctldir.c +++ b/module/os/linux/zfs/zpl_ctldir.c @@ -103,11 +103,11 @@ zpl_root_readdir(struct file *filp, void *dirent, filldir_t filldir) static int #ifdef HAVE_USERNS_IOPS_GETATTR zpl_root_getattr_impl(struct user_namespace *user_ns, - const struct path *path, struct kstat *stat, u32 request_mask, - unsigned int query_flags) + const struct path *path, struct kstat *stat, u32 request_mask, + unsigned int query_flags) #else zpl_root_getattr_impl(const struct path *path, struct kstat *stat, - u32 request_mask, unsigned int query_flags) + u32 request_mask, unsigned int query_flags) #endif { struct inode *ip = path->dentry->d_inode; @@ -345,7 +345,7 @@ zpl_snapdir_rmdir(struct inode *dip, struct dentry *dentry) static int #ifdef HAVE_IOPS_MKDIR_USERNS zpl_snapdir_mkdir(struct user_namespace *user_ns, struct inode *dip, - struct dentry *dentry, umode_t mode) + struct dentry *dentry, umode_t mode) #else zpl_snapdir_mkdir(struct inode *dip, struct dentry *dentry, umode_t mode) #endif @@ -380,11 +380,11 @@ zpl_snapdir_mkdir(struct inode *dip, struct dentry *dentry, umode_t mode) static int #ifdef HAVE_USERNS_IOPS_GETATTR zpl_snapdir_getattr_impl(struct user_namespace *user_ns, - const struct path *path, struct kstat *stat, u32 request_mask, - unsigned int query_flags) + const struct path *path, struct kstat *stat, u32 request_mask, + unsigned int query_flags) #else zpl_snapdir_getattr_impl(const struct path *path, struct kstat *stat, - u32 request_mask, unsigned int query_flags) + u32 request_mask, unsigned int query_flags) #endif { struct inode *ip = path->dentry->d_inode; @@ -522,11 +522,11 @@ zpl_shares_readdir(struct file *filp, void *dirent, filldir_t filldir) static int #ifdef HAVE_USERNS_IOPS_GETATTR zpl_shares_getattr_impl(struct user_namespace *user_ns, - const struct path *path, struct kstat *stat, u32 request_mask, - unsigned int query_flags) + const struct path *path, struct kstat *stat, u32 request_mask, + unsigned int query_flags) #else zpl_shares_getattr_impl(const struct path *path, struct kstat *stat, - u32 request_mask, unsigned int query_flags) + u32 request_mask, unsigned int query_flags) #endif { struct inode *ip = path->dentry->d_inode; diff --git a/module/os/linux/zfs/zpl_inode.c b/module/os/linux/zfs/zpl_inode.c index 8cfe9e9a5f08..3cb6d17bb95a 100644 --- a/module/os/linux/zfs/zpl_inode.c +++ b/module/os/linux/zfs/zpl_inode.c @@ -340,7 +340,7 @@ zpl_rmdir(struct inode *dir, struct dentry *dentry) static int #ifdef HAVE_USERNS_IOPS_GETATTR zpl_getattr_impl(struct user_namespace *user_ns, - const struct path *path, struct kstat *stat, u32 request_mask, + const struct path *path, struct kstat *stat, u32 request_mask, unsigned int query_flags) #else zpl_getattr_impl(const struct path *path, struct kstat *stat, u32 request_mask, From beba965bf46972be158b1cbee2cec1e4ef676718 Mon Sep 17 00:00:00 2001 From: Coleman Kane Date: Sun, 14 Mar 2021 20:58:08 -0400 Subject: [PATCH 12/18] Update zpl_mkdir() for 5.12 user_namespace arg This commit adjusts zpl_mkdir() so that it will support the user_namespace argument introduced in kernel version 5.12. Signed-off-by: Coleman Kane --- module/os/linux/zfs/zpl_inode.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/module/os/linux/zfs/zpl_inode.c b/module/os/linux/zfs/zpl_inode.c index 3cb6d17bb95a..ba336b28be34 100644 --- a/module/os/linux/zfs/zpl_inode.c +++ b/module/os/linux/zfs/zpl_inode.c @@ -278,7 +278,12 @@ zpl_unlink(struct inode *dir, struct dentry *dentry) } static int +#ifdef HAVE_IOPS_MKDIR_USERNS +zpl_mkdir(struct user_namespace *user_ns, struct inode *dir, + struct dentry *dentry, umode_t mode) +#else zpl_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) +#endif { cred_t *cr = CRED(); vattr_t *vap; From dfbe695210a68ad65b02d96a8d0aab334b5bb853 Mon Sep 17 00:00:00 2001 From: Coleman Kane Date: Sun, 14 Mar 2021 21:23:21 -0400 Subject: [PATCH 13/18] Updates for setattr() 5.12 user_namespace support Simplify a macro #define and also conditionally compile the zpl_setattr() handler depending upon if we need the struct user_namespace* arg in its type definition, or not. Signed-off-by: Coleman Kane --- include/os/linux/zfs/sys/zpl.h | 2 +- module/os/linux/zfs/zpl_inode.c | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/include/os/linux/zfs/sys/zpl.h b/include/os/linux/zfs/sys/zpl.h index 945a55cca36a..21825d1f378e 100644 --- a/include/os/linux/zfs/sys/zpl.h +++ b/include/os/linux/zfs/sys/zpl.h @@ -179,7 +179,7 @@ zpl_dir_emit_dots(struct file *file, zpl_dir_context_t *ctx) #error "Unsupported kernel" #endif -#if defined(HAVE_SETATTR_PREPARE_USERNS) +#ifdef HAVE_SETATTR_PREPARE_USERNS #define zpl_setattr_prepare(ns, dentry, ia) setattr_prepare(ns, dentry, ia) #else /* diff --git a/module/os/linux/zfs/zpl_inode.c b/module/os/linux/zfs/zpl_inode.c index ba336b28be34..b13f71b34ece 100644 --- a/module/os/linux/zfs/zpl_inode.c +++ b/module/os/linux/zfs/zpl_inode.c @@ -374,7 +374,12 @@ zpl_getattr_impl(const struct path *path, struct kstat *stat, u32 request_mask, ZPL_GETATTR_WRAPPER(zpl_getattr); static int +#ifdef HAVE_SETATTR_PREPARE_USERNS +zpl_setattr(struct user_namespace *user_ns, struct dentry *dentry, + struct iattr *ia) +#else zpl_setattr(struct dentry *dentry, struct iattr *ia) +#endif { struct inode *ip = dentry->d_inode; cred_t *cr = CRED(); From 3c0e3022a390a18ecda01089cc4321a819a3ed7a Mon Sep 17 00:00:00 2001 From: Coleman Kane Date: Sun, 14 Mar 2021 22:11:35 -0400 Subject: [PATCH 14/18] Update mknod() and symlink() for 5.12 user_namespace changes This commit updates both of these so that if configure determines that the kernel FS API requires struct user_namespace* as the first arg, then the respective zpl_mknod and zpl_symlink functions are compiled to match. Signed-off-by: Coleman Kane --- config/kernel-mknod.m4 | 30 ++++++++++++++++++++++++++++++ config/kernel-symlink.m4 | 30 ++++++++++++++++++++++++++++++ config/kernel.m4 | 4 ++++ module/os/linux/zfs/zpl_inode.c | 10 ++++++++++ 4 files changed, 74 insertions(+) create mode 100644 config/kernel-mknod.m4 create mode 100644 config/kernel-symlink.m4 diff --git a/config/kernel-mknod.m4 b/config/kernel-mknod.m4 new file mode 100644 index 000000000000..ffe45106003a --- /dev/null +++ b/config/kernel-mknod.m4 @@ -0,0 +1,30 @@ +AC_DEFUN([ZFS_AC_KERNEL_SRC_MKNOD], [ + dnl # + dnl # 5.12 API change that added the struct user_namespace* arg + dnl # to the front of this function type's arg list. + dnl # + ZFS_LINUX_TEST_SRC([mknod_userns], [ + #include + #include + + int tmp_mknod(struct user_namespace *userns, + struct inode *inode ,struct dentry *dentry, + umode_t u, dev_t d) { return 0; } + + static const struct inode_operations + iops __attribute__ ((unused)) = { + .mknod = tmp_mknod, + }; + ],[]) +]) + +AC_DEFUN([ZFS_AC_KERNEL_MKNOD], [ + AC_MSG_CHECKING([whether iops->mknod() takes struct user_namespace*]) + ZFS_LINUX_TEST_RESULT([mknod_userns], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_IOPS_MKNOD_USERNS, 1, + [iops->mknod() takes struct user_namespace*]) + ],[ + AC_MSG_RESULT(no) + ]) +]) diff --git a/config/kernel-symlink.m4 b/config/kernel-symlink.m4 new file mode 100644 index 000000000000..d90366d04b72 --- /dev/null +++ b/config/kernel-symlink.m4 @@ -0,0 +1,30 @@ +AC_DEFUN([ZFS_AC_KERNEL_SRC_SYMLINK], [ + dnl # + dnl # 5.12 API change that added the struct user_namespace* arg + dnl # to the front of this function type's arg list. + dnl # + ZFS_LINUX_TEST_SRC([symlink_userns], [ + #include + #include + + int tmp_symlink(struct user_namespace *userns, + struct inode *inode ,struct dentry *dentry, + const char *path) { return 0; } + + static const struct inode_operations + iops __attribute__ ((unused)) = { + .symlink = tmp_symlink, + }; + ],[]) +]) + +AC_DEFUN([ZFS_AC_KERNEL_SYMLINK], [ + AC_MSG_CHECKING([whether iops->symlink() takes struct user_namespace*]) + ZFS_LINUX_TEST_RESULT([symlink_userns], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_IOPS_SYMLINK_USERNS, 1, + [iops->symlink() takes struct user_namespace*]) + ],[ + AC_MSG_RESULT(no) + ]) +]) diff --git a/config/kernel.m4 b/config/kernel.m4 index cf220a164769..610d921e4533 100644 --- a/config/kernel.m4 +++ b/config/kernel.m4 @@ -126,6 +126,8 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [ ZFS_AC_KERNEL_SRC_PERCPU ZFS_AC_KERNEL_SRC_CPU_HOTPLUG ZFS_AC_KERNEL_SRC_GENERIC_FILLATTR_USERNS + ZFS_AC_KERNEL_SRC_MKNOD + ZFS_AC_KERNEL_SRC_SYMLINK AC_MSG_CHECKING([for available kernel interfaces]) ZFS_LINUX_TEST_COMPILE_ALL([kabi]) @@ -225,6 +227,8 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [ ZFS_AC_KERNEL_PERCPU ZFS_AC_KERNEL_CPU_HOTPLUG ZFS_AC_KERNEL_GENERIC_FILLATTR_USERNS + ZFS_AC_KERNEL_MKNOD + ZFS_AC_KERNEL_SYMLINK ]) dnl # diff --git a/module/os/linux/zfs/zpl_inode.c b/module/os/linux/zfs/zpl_inode.c index b13f71b34ece..98fba496176b 100644 --- a/module/os/linux/zfs/zpl_inode.c +++ b/module/os/linux/zfs/zpl_inode.c @@ -163,7 +163,12 @@ zpl_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool flag) } static int +#ifdef HAVE_IOPS_MKNOD_USERNS +zpl_mknod(struct user_namespace *user_ns, struct inode *dir, + struct dentry *dentry, umode_t mode, +#else zpl_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, +#endif dev_t rdev) { cred_t *cr = CRED(); @@ -451,7 +456,12 @@ zpl_rename(struct inode *sdip, struct dentry *sdentry, #endif static int +#ifdef HAVE_IOPS_SYMLINK_USERNS +zpl_symlink(struct user_namespace *user_ns, struct inode *dir, + struct dentry *dentry, const char *name) +#else zpl_symlink(struct inode *dir, struct dentry *dentry, const char *name) +#endif { cred_t *cr = CRED(); vattr_t *vap; From 2cb3d86ad12279c5f1c2b10095492d55249aa0d4 Mon Sep 17 00:00:00 2001 From: Coleman Kane Date: Sun, 14 Mar 2021 22:18:10 -0400 Subject: [PATCH 15/18] Update create() for the 5.12 user_namespace API change When configure identifies that create needs to accept a struct user_namespace* as its first argument, make sure that we compile an implementation of the function that adheres to this API. Signed-off-by: Coleman Kane --- config/kernel-inode-create.m4 | 43 +++++++++++++++++++++++++++------ config/kernel.m4 | 4 +-- module/os/linux/zfs/zpl_inode.c | 5 ++++ 3 files changed, 42 insertions(+), 10 deletions(-) diff --git a/config/kernel-inode-create.m4 b/config/kernel-inode-create.m4 index 9f28bcbd4f7f..a6ea11fb61b2 100644 --- a/config/kernel-inode-create.m4 +++ b/config/kernel-inode-create.m4 @@ -1,7 +1,25 @@ -dnl # -dnl # 3.6 API change -dnl # -AC_DEFUN([ZFS_AC_KERNEL_SRC_CREATE_FLAGS], [ +AC_DEFUN([ZFS_AC_KERNEL_SRC_CREATE], [ + dnl # + dnl # 5.12 API change that added the struct user_namespace* arg + dnl # to the front of this function type's arg list. + dnl # + ZFS_LINUX_TEST_SRC([create_userns], [ + #include + #include + + int inode_create(struct user_namespace *userns, + struct inode *inode ,struct dentry *dentry, + umode_t umode, bool flag) { return 0; } + + static const struct inode_operations + iops __attribute__ ((unused)) = { + .create = inode_create, + }; + ],[]) + + dnl # + dnl # 3.6 API change + dnl # ZFS_LINUX_TEST_SRC([create_flags], [ #include #include @@ -16,11 +34,20 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_CREATE_FLAGS], [ ],[]) ]) -AC_DEFUN([ZFS_AC_KERNEL_CREATE_FLAGS], [ - AC_MSG_CHECKING([whether iops->create() passes flags]) - ZFS_LINUX_TEST_RESULT([create_flags], [ +AC_DEFUN([ZFS_AC_KERNEL_CREATE], [ + AC_MSG_CHECKING([whether iops->create() takes struct user_namespace*]) + ZFS_LINUX_TEST_RESULT([create_userns], [ AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_IOPS_CREATE_USERNS, 1, + [iops->create() takes struct user_namespace*]) ],[ - ZFS_LINUX_TEST_ERROR([iops->create()]) + AC_MSG_RESULT(no) + + AC_MSG_CHECKING([whether iops->create() passes flags]) + ZFS_LINUX_TEST_RESULT([create_flags], [ + AC_MSG_RESULT(yes) + ],[ + ZFS_LINUX_TEST_ERROR([iops->create()]) + ]) ]) ]) diff --git a/config/kernel.m4 b/config/kernel.m4 index 610d921e4533..7698f69fe961 100644 --- a/config/kernel.m4 +++ b/config/kernel.m4 @@ -81,7 +81,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [ ZFS_AC_KERNEL_SRC_SHRINKER ZFS_AC_KERNEL_SRC_MKDIR ZFS_AC_KERNEL_SRC_LOOKUP_FLAGS - ZFS_AC_KERNEL_SRC_CREATE_FLAGS + ZFS_AC_KERNEL_SRC_CREATE ZFS_AC_KERNEL_SRC_GET_LINK ZFS_AC_KERNEL_SRC_PUT_LINK ZFS_AC_KERNEL_SRC_TMPFILE @@ -182,7 +182,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [ ZFS_AC_KERNEL_SHRINKER ZFS_AC_KERNEL_MKDIR ZFS_AC_KERNEL_LOOKUP_FLAGS - ZFS_AC_KERNEL_CREATE_FLAGS + ZFS_AC_KERNEL_CREATE ZFS_AC_KERNEL_GET_LINK ZFS_AC_KERNEL_PUT_LINK ZFS_AC_KERNEL_TMPFILE diff --git a/module/os/linux/zfs/zpl_inode.c b/module/os/linux/zfs/zpl_inode.c index 98fba496176b..3bf40e862b8c 100644 --- a/module/os/linux/zfs/zpl_inode.c +++ b/module/os/linux/zfs/zpl_inode.c @@ -128,7 +128,12 @@ zpl_vap_init(vattr_t *vap, struct inode *dir, umode_t mode, cred_t *cr) } static int +#ifdef HAVE_IOPS_CREATE_USERNS +zpl_create(struct user_namespace *user_ns, struct inode *dir, + struct dentry *dentry, umode_t mode, bool flag) +#else zpl_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool flag) +#endif { cred_t *cr = CRED(); znode_t *zp; From 6f526b224ceb7f48de0cbc3c890fec5ffcc7712c Mon Sep 17 00:00:00 2001 From: Coleman Kane Date: Sun, 14 Mar 2021 22:24:56 -0400 Subject: [PATCH 16/18] Implement rename() update for 5.12 user_namespace API change Implement configure code that determines if the struct user_namespace* is required as the first argument to rename() in struct inode_operations, and if so, update zpl_rename implementation to match. Signed-off-by: Coleman Kane --- config/kernel-rename.m4 | 50 ++++++++++++++++++++++++-------- config/kernel.m4 | 4 +-- module/os/linux/zfs/zpl_ctldir.c | 10 +++++-- module/os/linux/zfs/zpl_inode.c | 10 +++++-- 4 files changed, 56 insertions(+), 18 deletions(-) diff --git a/config/kernel-rename.m4 b/config/kernel-rename.m4 index f707391539d8..31d199f33bba 100644 --- a/config/kernel-rename.m4 +++ b/config/kernel-rename.m4 @@ -1,10 +1,10 @@ -dnl # -dnl # 4.9 API change, -dnl # iops->rename2() merged into iops->rename(), and iops->rename() now wants -dnl # flags. -dnl # -AC_DEFUN([ZFS_AC_KERNEL_SRC_RENAME_WANTS_FLAGS], [ - ZFS_LINUX_TEST_SRC([inode_operations_rename], [ +AC_DEFUN([ZFS_AC_KERNEL_SRC_RENAME], [ + dnl # + dnl # 4.9 API change, + dnl # iops->rename2() merged into iops->rename(), and iops->rename() now wants + dnl # flags. + dnl # + ZFS_LINUX_TEST_SRC([inode_operations_rename_flags], [ #include int rename_fn(struct inode *sip, struct dentry *sdp, struct inode *tip, struct dentry *tdp, @@ -15,15 +15,41 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_RENAME_WANTS_FLAGS], [ .rename = rename_fn, }; ],[]) + + dnl # + dnl # 5.12 API change, + dnl # + dnl # Linux 5.12 introduced passing struct user_namespace* as the first argument + dnl # of the rename() and other inode_operations members. + dnl # + ZFS_LINUX_TEST_SRC([inode_operations_rename_userns], [ + #include + int rename_fn(struct user_namespace *user_ns, struct inode *sip, + struct dentry *sdp, struct inode *tip, struct dentry *tdp, + unsigned int flags) { return 0; } + + static const struct inode_operations + iops __attribute__ ((unused)) = { + .rename = rename_fn, + }; + ],[]) ]) -AC_DEFUN([ZFS_AC_KERNEL_RENAME_WANTS_FLAGS], [ - AC_MSG_CHECKING([whether iops->rename() wants flags]) - ZFS_LINUX_TEST_RESULT([inode_operations_rename], [ +AC_DEFUN([ZFS_AC_KERNEL_RENAME], [ + AC_MSG_CHECKING([whether iops->rename() takes struct user_namespace*]) + ZFS_LINUX_TEST_RESULT([inode_operations_rename_userns], [ AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_RENAME_WANTS_FLAGS, 1, - [iops->rename() wants flags]) + AC_DEFINE(HAVE_IOPS_RENAME_USERNS, 1, + [iops->rename() takes struct user_namespace*]) ],[ AC_MSG_RESULT(no) + + ZFS_LINUX_TEST_RESULT([inode_operations_rename_flags], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_RENAME_WANTS_FLAGS, 1, + [iops->rename() wants flags]) + ],[ + AC_MSG_RESULT(no) + ]) ]) ]) diff --git a/config/kernel.m4 b/config/kernel.m4 index 7698f69fe961..24db38f09f43 100644 --- a/config/kernel.m4 +++ b/config/kernel.m4 @@ -115,7 +115,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [ ZFS_AC_KERNEL_SRC_KUIDGID_T ZFS_AC_KERNEL_SRC_KUID_HELPERS ZFS_AC_KERNEL_SRC_MODULE_PARAM_CALL_CONST - ZFS_AC_KERNEL_SRC_RENAME_WANTS_FLAGS + ZFS_AC_KERNEL_SRC_RENAME ZFS_AC_KERNEL_SRC_CURRENT_TIME ZFS_AC_KERNEL_SRC_USERNS_CAPABILITIES ZFS_AC_KERNEL_SRC_IN_COMPAT_SYSCALL @@ -216,7 +216,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [ ZFS_AC_KERNEL_KUIDGID_T ZFS_AC_KERNEL_KUID_HELPERS ZFS_AC_KERNEL_MODULE_PARAM_CALL_CONST - ZFS_AC_KERNEL_RENAME_WANTS_FLAGS + ZFS_AC_KERNEL_RENAME ZFS_AC_KERNEL_CURRENT_TIME ZFS_AC_KERNEL_USERNS_CAPABILITIES ZFS_AC_KERNEL_IN_COMPAT_SYSCALL diff --git a/module/os/linux/zfs/zpl_ctldir.c b/module/os/linux/zfs/zpl_ctldir.c index f79d905b99cd..f76a448b10cc 100644 --- a/module/os/linux/zfs/zpl_ctldir.c +++ b/module/os/linux/zfs/zpl_ctldir.c @@ -300,8 +300,14 @@ zpl_snapdir_readdir(struct file *filp, void *dirent, filldir_t filldir) #endif /* !HAVE_VFS_ITERATE && !HAVE_VFS_ITERATE_SHARED */ static int +#ifdef HAVE_IOPS_RENAME_USERNS +zpl_snapdir_rename2(struct user_namespace *user_ns, struct inode *sdip, + struct dentry *sdentry, struct inode *tdip, struct dentry *tdentry, + unsigned int flags) +#else zpl_snapdir_rename2(struct inode *sdip, struct dentry *sdentry, struct inode *tdip, struct dentry *tdentry, unsigned int flags) +#endif { cred_t *cr = CRED(); int error; @@ -319,7 +325,7 @@ zpl_snapdir_rename2(struct inode *sdip, struct dentry *sdentry, return (error); } -#ifndef HAVE_RENAME_WANTS_FLAGS +#if !defined(HAVE_RENAME_WANTS_FLAGS) && !defined(HAVE_IOPS_RENAME_USERNS) static int zpl_snapdir_rename(struct inode *sdip, struct dentry *sdentry, struct inode *tdip, struct dentry *tdentry) @@ -433,7 +439,7 @@ const struct file_operations zpl_fops_snapdir = { const struct inode_operations zpl_ops_snapdir = { .lookup = zpl_snapdir_lookup, .getattr = zpl_snapdir_getattr, -#ifdef HAVE_RENAME_WANTS_FLAGS +#if defined(HAVE_RENAME_WANTS_FLAGS) || defined(HAVE_IOPS_RENAME_USERNS) .rename = zpl_snapdir_rename2, #else .rename = zpl_snapdir_rename, diff --git a/module/os/linux/zfs/zpl_inode.c b/module/os/linux/zfs/zpl_inode.c index 3bf40e862b8c..14d15595171d 100644 --- a/module/os/linux/zfs/zpl_inode.c +++ b/module/os/linux/zfs/zpl_inode.c @@ -429,8 +429,14 @@ zpl_setattr(struct dentry *dentry, struct iattr *ia) } static int +#ifdef HAVE_IOPS_RENAME_USERNS +zpl_rename2(struct user_namespace *user_ns, struct inode *sdip, + struct dentry *sdentry, struct inode *tdip, struct dentry *tdentry, + unsigned int flags) +#else zpl_rename2(struct inode *sdip, struct dentry *sdentry, struct inode *tdip, struct dentry *tdentry, unsigned int flags) +#endif { cred_t *cr = CRED(); int error; @@ -451,7 +457,7 @@ zpl_rename2(struct inode *sdip, struct dentry *sdentry, return (error); } -#ifndef HAVE_RENAME_WANTS_FLAGS +#if !defined(HAVE_RENAME_WANTS_FLAGS) && !defined(HAVE_IOPS_RENAME_USERNS) static int zpl_rename(struct inode *sdip, struct dentry *sdentry, struct inode *tdip, struct dentry *tdentry) @@ -712,7 +718,7 @@ const struct inode_operations zpl_dir_inode_operations = { .mkdir = zpl_mkdir, .rmdir = zpl_rmdir, .mknod = zpl_mknod, -#ifdef HAVE_RENAME_WANTS_FLAGS +#if defined(HAVE_RENAME_WANTS_FLAGS) || defined(HAVE_IOPS_RENAME_USERNS) .rename = zpl_rename2, #else .rename = zpl_rename, From 6e8512d773f01e566850070f1fe8d2d5b1dae393 Mon Sep 17 00:00:00 2001 From: Coleman Kane Date: Sun, 14 Mar 2021 22:38:53 -0400 Subject: [PATCH 17/18] Update the xattr_set() interface for the 5.12 user_namespace API Some more additions that update the ZPL_XATTR_SET_WRAPPER() macro such that it will build interface functions that adopt the struct user_namespace* argument as the second arg, if that is the implementation required in the kernel (determined by configure). This was added to support idmapped FS mounts in Linux 5.12. Signed-off-by: Coleman Kane --- config/kernel-xattr-handler.m4 | 9 +++++---- include/os/linux/kernel/linux/xattr_compat.h | 17 ++++++++++++++++- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/config/kernel-xattr-handler.m4 b/config/kernel-xattr-handler.m4 index 4fd59ba4c9e6..00b1e74a9ccb 100644 --- a/config/kernel-xattr-handler.m4 +++ b/config/kernel-xattr-handler.m4 @@ -152,7 +152,7 @@ dnl # dnl # Supported xattr handler set() interfaces checked newest to oldest. dnl # AC_DEFUN([ZFS_AC_KERNEL_SRC_XATTR_HANDLER_SET], [ - ZFS_LINUX_TEST_SRC([xattr_handler_set_dentry_inode_user_ns], [ + ZFS_LINUX_TEST_SRC([xattr_handler_set_userns], [ #include int set(const struct xattr_handler *handler, @@ -214,16 +214,17 @@ AC_DEFUN([ZFS_AC_KERNEL_XATTR_HANDLER_SET], [ dnl # struct user_namespace* was inserted as arg #2 dnl # AC_MSG_CHECKING([whether xattr_handler->set() wants dentry, inode, and user_namespace]) - ZFS_LINUX_TEST_RESULT([xattr_handler_set_dentry_inode_user_ns], [ + ZFS_LINUX_TEST_RESULT([xattr_handler_set_userns], [ AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_XATTR_SET_DENTRY_INODE_USER_NS, 1, - [xattr_handler->set() wants dentry, inode, and user_namespace]) + AC_DEFINE(HAVE_XATTR_SET_USERNS, 1, + [xattr_handler->set() takes user_namespace]) ],[ dnl # dnl # 4.7 API change, dnl # The xattr_handler->set() callback was changed to take both dnl # dentry and inode. dnl # + AC_MSG_RESULT(no) AC_MSG_CHECKING([whether xattr_handler->set() wants dentry and inode]) ZFS_LINUX_TEST_RESULT([xattr_handler_set_dentry_inode], [ AC_MSG_RESULT(yes) diff --git a/include/os/linux/kernel/linux/xattr_compat.h b/include/os/linux/kernel/linux/xattr_compat.h index 8348e99198af..54690727eab9 100644 --- a/include/os/linux/kernel/linux/xattr_compat.h +++ b/include/os/linux/kernel/linux/xattr_compat.h @@ -119,12 +119,27 @@ fn(struct dentry *dentry, const char *name, void *buffer, size_t size, \ #error "Unsupported kernel" #endif +/* + * 5.12 API change, + * The xattr_handler->set() callback was changed to take the + * struct user_namespace* as the first arg, to support idmapped + * mounts. + */ +#if defined(HAVE_XATTR_SET_USERNS) +#define ZPL_XATTR_SET_WRAPPER(fn) \ +static int \ +fn(const struct xattr_handler *handler, struct user_namespace *user_ns, \ + struct dentry *dentry, struct inode *inode, const char *name, \ + const void *buffer, size_t size, int flags) \ +{ \ + return (__ ## fn(inode, name, buffer, size, flags)); \ +} /* * 4.7 API change, * The xattr_handler->set() callback was changed to take a both dentry and * inode, because the dentry might not be attached to an inode yet. */ -#if defined(HAVE_XATTR_SET_DENTRY_INODE) +#elif defined(HAVE_XATTR_SET_DENTRY_INODE) #define ZPL_XATTR_SET_WRAPPER(fn) \ static int \ fn(const struct xattr_handler *handler, struct dentry *dentry, \ From 58e2ab2d435a953a9634af844a8ca9ad1875f590 Mon Sep 17 00:00:00 2001 From: Coleman Kane Date: Tue, 16 Mar 2021 19:29:51 -0400 Subject: [PATCH 18/18] Refactor to clean up internal interface zfs_getattr_fast() Instead of conditionally compiling zfs_getattr_fast(), always accept the struct user_namespace* arg in that function, and wrap the kernel's getattr_fast() with a zpl_getattr_fast() wrapper that discards the first arg in Linux <5.12. Have the getattr handler implementations simply pass the kcred->user_ns value when called in earlier kernels that don't support the new interface. Signed-off-by: Coleman Kane --- include/os/linux/kernel/linux/vfs_compat.h | 12 ++++++++++++ include/os/linux/zfs/sys/zfs_vnops_os.h | 4 ---- module/os/linux/zfs/zfs_vnops_os.c | 10 +--------- module/os/linux/zfs/zpl_ctldir.c | 2 +- module/os/linux/zfs/zpl_inode.c | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/include/os/linux/kernel/linux/vfs_compat.h b/include/os/linux/kernel/linux/vfs_compat.h index 8395bb7386d8..91e908598fbb 100644 --- a/include/os/linux/kernel/linux/vfs_compat.h +++ b/include/os/linux/kernel/linux/vfs_compat.h @@ -446,4 +446,16 @@ zpl_is_32bit_api(void) #endif } +/* + * 5.12 API change + * To support id-mapped mounts, generic_fillattr() was modified to + * accept a new struct user_namespace* as its first arg. + */ +#ifdef HAVE_GENERIC_FILLATTR_USERNS +#define zpl_generic_fillattr(user_ns, ip, sp) \ + generic_fillattr(user_ns, ip, sp) +#else +#define zpl_generic_fillattr(user_ns, ip, sp) generic_fillattr(ip, sp) +#endif + #endif /* _ZFS_VFS_H */ diff --git a/include/os/linux/zfs/sys/zfs_vnops_os.h b/include/os/linux/zfs/sys/zfs_vnops_os.h index f42e11759eeb..47f91e4a6cf4 100644 --- a/include/os/linux/zfs/sys/zfs_vnops_os.h +++ b/include/os/linux/zfs/sys/zfs_vnops_os.h @@ -54,12 +54,8 @@ extern int zfs_mkdir(znode_t *dzp, char *dirname, vattr_t *vap, extern int zfs_rmdir(znode_t *dzp, char *name, znode_t *cwd, cred_t *cr, int flags); extern int zfs_readdir(struct inode *ip, zpl_dir_context_t *ctx, cred_t *cr); -#ifdef HAVE_GENERIC_FILLATTR_USERNS extern int zfs_getattr_fast(struct user_namespace *, struct inode *ip, struct kstat *sp); -#else -extern int zfs_getattr_fast(struct inode *ip, struct kstat *sp); -#endif extern int zfs_setattr(znode_t *zp, vattr_t *vap, int flag, cred_t *cr); extern int zfs_rename(znode_t *sdzp, char *snm, znode_t *tdzp, char *tnm, cred_t *cr, int flags); diff --git a/module/os/linux/zfs/zfs_vnops_os.c b/module/os/linux/zfs/zfs_vnops_os.c index d336abd50cf2..8aeed6f568cf 100644 --- a/module/os/linux/zfs/zfs_vnops_os.c +++ b/module/os/linux/zfs/zfs_vnops_os.c @@ -1656,12 +1656,8 @@ zfs_readdir(struct inode *ip, zpl_dir_context_t *ctx, cred_t *cr) */ /* ARGSUSED */ int -#ifdef HAVE_GENERIC_FILLATTR_USERNS zfs_getattr_fast(struct user_namespace *user_ns, struct inode *ip, struct kstat *sp) -#else -zfs_getattr_fast(struct inode *ip, struct kstat *sp) -#endif { znode_t *zp = ITOZ(ip); zfsvfs_t *zfsvfs = ITOZSB(ip); @@ -1673,11 +1669,7 @@ zfs_getattr_fast(struct inode *ip, struct kstat *sp) mutex_enter(&zp->z_lock); -#ifdef HAVE_GENERIC_FILLATTR_USERNS - generic_fillattr(user_ns, ip, sp); -#else - generic_fillattr(ip, sp); -#endif + zpl_generic_fillattr(user_ns, ip, sp); /* * +1 link count for root inode with visible '.zfs' directory. */ diff --git a/module/os/linux/zfs/zpl_ctldir.c b/module/os/linux/zfs/zpl_ctldir.c index f76a448b10cc..9b526afd0002 100644 --- a/module/os/linux/zfs/zpl_ctldir.c +++ b/module/os/linux/zfs/zpl_ctldir.c @@ -559,7 +559,7 @@ zpl_shares_getattr_impl(const struct path *path, struct kstat *stat, #if defined(HAVE_GENERIC_FILLATTR_USERNS) && defined(HAVE_USERNS_IOPS_GETATTR) error = -zfs_getattr_fast(user_ns, ZTOI(dzp), stat); #else - error = -zfs_getattr_fast(ZTOI(dzp), stat); + error = -zfs_getattr_fast(kcred->user_ns, ZTOI(dzp), stat); #endif iput(ZTOI(dzp)); } diff --git a/module/os/linux/zfs/zpl_inode.c b/module/os/linux/zfs/zpl_inode.c index 14d15595171d..19c120d6dee7 100644 --- a/module/os/linux/zfs/zpl_inode.c +++ b/module/os/linux/zfs/zpl_inode.c @@ -374,7 +374,7 @@ zpl_getattr_impl(const struct path *path, struct kstat *stat, u32 request_mask, #ifdef HAVE_USERNS_IOPS_GETATTR error = -zfs_getattr_fast(user_ns, path->dentry->d_inode, stat); #else - error = -zfs_getattr_fast(path->dentry->d_inode, stat); + error = -zfs_getattr_fast(kcred->user_ns, path->dentry->d_inode, stat); #endif spl_fstrans_unmark(cookie); ASSERT3S(error, <=, 0);