mirror of https://github.com/archzfs/zfs-dkms
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1231 lines
39 KiB
1231 lines
39 KiB
4 years ago
|
diff --git a/config/kernel-bio_max_segs.m4 b/config/kernel-bio_max_segs.m4
|
||
|
new file mode 100644
|
||
|
index 00000000000..a90d75455c1
|
||
|
--- /dev/null
|
||
|
+++ b/config/kernel-bio_max_segs.m4
|
||
|
@@ -0,0 +1,23 @@
|
||
|
+dnl #
|
||
|
+dnl # 5.12 API change removes BIO_MAX_PAGES in favor of bio_max_segs()
|
||
|
+dnl # which will handle the logic of setting the upper-bound to a
|
||
|
+dnl # BIO_MAX_PAGES, internally.
|
||
|
+dnl #
|
||
|
+AC_DEFUN([ZFS_AC_KERNEL_SRC_BIO_MAX_SEGS], [
|
||
|
+ ZFS_LINUX_TEST_SRC([bio_max_segs], [
|
||
|
+ #include <linux/bio.h>
|
||
|
+ ],[
|
||
|
+ bio_max_segs(1);
|
||
|
+ ])
|
||
|
+])
|
||
|
+
|
||
|
+AC_DEFUN([ZFS_AC_KERNEL_BIO_MAX_SEGS], [
|
||
|
+ AC_MSG_CHECKING([whether bio_max_segs() exists])
|
||
|
+ ZFS_LINUX_TEST_RESULT([bio_max_segs], [
|
||
|
+ AC_MSG_RESULT(yes)
|
||
|
+
|
||
|
+ AC_DEFINE([HAVE_BIO_MAX_SEGS], 1, [bio_max_segs() is implemented])
|
||
|
+ ],[
|
||
|
+ AC_MSG_RESULT(no)
|
||
|
+ ])
|
||
|
+])
|
||
|
diff --git a/config/kernel-generic_fillattr.m4 b/config/kernel-generic_fillattr.m4
|
||
|
new file mode 100644
|
||
|
index 00000000000..50c8031305b
|
||
|
--- /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 <linux/fs.h>
|
||
|
+ ],[
|
||
|
+ 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-inode-create.m4 b/config/kernel-inode-create.m4
|
||
|
index 9f28bcbd4f7..a6ea11fb61b 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 <linux/fs.h>
|
||
|
+ #include <linux/sched.h>
|
||
|
+
|
||
|
+ 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 <linux/fs.h>
|
||
|
#include <linux/sched.h>
|
||
|
@@ -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-inode-getattr.m4 b/config/kernel-inode-getattr.m4
|
||
|
index 48391d66f8b..f62e82f5230 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 <linux/fs.h>
|
||
|
+
|
||
|
+ 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 <linux/fs.h>
|
||
|
|
||
|
@@ -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/config/kernel-is_owner_or_cap.m4 b/config/kernel-is_owner_or_cap.m4
|
||
|
index 3df6163da27..3c3c6ad2240 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 <linux/fs.h>
|
||
|
+ ],[
|
||
|
+ 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/config/kernel-mkdir-umode-t.m4 b/config/kernel-mkdir-umode-t.m4
|
||
|
deleted file mode 100644
|
||
|
index 19599670df3..00000000000
|
||
|
--- 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 <linux/fs.h>
|
||
|
-
|
||
|
- 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 00000000000..a162bcd880f
|
||
|
--- /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 <linux/fs.h>
|
||
|
+
|
||
|
+ 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 <linux/fs.h>
|
||
|
+
|
||
|
+ 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-mknod.m4 b/config/kernel-mknod.m4
|
||
|
new file mode 100644
|
||
|
index 00000000000..ffe45106003
|
||
|
--- /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 <linux/fs.h>
|
||
|
+ #include <linux/sched.h>
|
||
|
+
|
||
|
+ 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-rename.m4 b/config/kernel-rename.m4
|
||
|
index f707391539d..31d199f33bb 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 <linux/fs.h>
|
||
|
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 <linux/fs.h>
|
||
|
+ 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-setattr-prepare.m4 b/config/kernel-setattr-prepare.m4
|
||
|
index 45408c45c69..24245aa5344 100644
|
||
|
--- a/config/kernel-setattr-prepare.m4
|
||
|
+++ b/config/kernel-setattr-prepare.m4
|
||
|
@@ -1,27 +1,52 @@
|
||
|
-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 <linux/fs.h>
|
||
|
], [
|
||
|
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 <linux/fs.h>
|
||
|
+ ], [
|
||
|
+ 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],
|
||
|
+ AC_MSG_CHECKING([whether setattr_prepare() is available and accepts struct user_namespace*])
|
||
|
+ ZFS_LINUX_TEST_RESULT_SYMBOL([setattr_prepare_userns],
|
||
|
[setattr_prepare], [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/config/kernel-symlink.m4 b/config/kernel-symlink.m4
|
||
|
new file mode 100644
|
||
|
index 00000000000..d90366d04b7
|
||
|
--- /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 <linux/fs.h>
|
||
|
+ #include <linux/sched.h>
|
||
|
+
|
||
|
+ 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-xattr-handler.m4 b/config/kernel-xattr-handler.m4
|
||
|
index 137bf4a8aff..00b1e74a9cc 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_userns], [
|
||
|
+ #include <linux/xattr.h>
|
||
|
+
|
||
|
+ 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 <linux/xattr.h>
|
||
|
|
||
|
@@ -194,45 +209,58 @@ 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_userns], [
|
||
|
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_USERNS, 1,
|
||
|
+ [xattr_handler->set() takes 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()])
|
||
|
+ ])
|
||
|
])
|
||
|
])
|
||
|
])
|
||
|
diff --git a/config/kernel.m4 b/config/kernel.m4
|
||
|
index 55620b3daa8..b8d53490a4a 100644
|
||
|
--- a/config/kernel.m4
|
||
|
+++ b/config/kernel.m4
|
||
|
@@ -79,9 +79,9 @@ 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_CREATE
|
||
|
ZFS_AC_KERNEL_SRC_GET_LINK
|
||
|
ZFS_AC_KERNEL_SRC_PUT_LINK
|
||
|
ZFS_AC_KERNEL_SRC_TMPFILE
|
||
|
@@ -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
|
||
|
@@ -124,6 +124,10 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
|
||
|
ZFS_AC_KERNEL_SRC_TOTALHIGH_PAGES
|
||
|
ZFS_AC_KERNEL_SRC_KSTRTOUL
|
||
|
ZFS_AC_KERNEL_SRC_PERCPU
|
||
|
+ ZFS_AC_KERNEL_SRC_GENERIC_FILLATTR_USERNS
|
||
|
+ ZFS_AC_KERNEL_SRC_MKNOD
|
||
|
+ ZFS_AC_KERNEL_SRC_SYMLINK
|
||
|
+ ZFS_AC_KERNEL_SRC_BIO_MAX_SEGS
|
||
|
|
||
|
AC_MSG_CHECKING([for available kernel interfaces])
|
||
|
ZFS_LINUX_TEST_COMPILE_ALL([kabi])
|
||
|
@@ -176,9 +180,9 @@ 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_CREATE
|
||
|
ZFS_AC_KERNEL_GET_LINK
|
||
|
ZFS_AC_KERNEL_PUT_LINK
|
||
|
ZFS_AC_KERNEL_TMPFILE
|
||
|
@@ -212,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
|
||
|
@@ -221,6 +225,10 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
|
||
|
ZFS_AC_KERNEL_TOTALHIGH_PAGES
|
||
|
ZFS_AC_KERNEL_KSTRTOUL
|
||
|
ZFS_AC_KERNEL_PERCPU
|
||
|
+ ZFS_AC_KERNEL_GENERIC_FILLATTR_USERNS
|
||
|
+ ZFS_AC_KERNEL_MKNOD
|
||
|
+ ZFS_AC_KERNEL_SYMLINK
|
||
|
+ ZFS_AC_KERNEL_BIO_MAX_SEGS
|
||
|
])
|
||
|
|
||
|
dnl #
|
||
|
diff --git a/include/os/linux/kernel/linux/vfs_compat.h b/include/os/linux/kernel/linux/vfs_compat.h
|
||
|
index c35e80d31cd..91e908598fb 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
|
||
|
*/
|
||
|
-#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)
|
||
|
{
|
||
|
@@ -389,6 +390,15 @@ 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
|
||
|
@@ -436,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/kernel/linux/xattr_compat.h b/include/os/linux/kernel/linux/xattr_compat.h
|
||
|
index 8348e99198a..54690727eab 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, \
|
||
|
diff --git a/include/os/linux/zfs/sys/zfs_vnops_os.h b/include/os/linux/zfs/sys/zfs_vnops_os.h
|
||
|
index 1c9cdf7bf8f..ba83f5dd83d 100644
|
||
|
--- a/include/os/linux/zfs/sys/zfs_vnops_os.h
|
||
|
+++ b/include/os/linux/zfs/sys/zfs_vnops_os.h
|
||
|
@@ -56,7 +56,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);
|
||
|
-extern int zfs_getattr_fast(struct inode *ip, struct kstat *sp);
|
||
|
+extern int zfs_getattr_fast(struct user_namespace *, struct inode *ip,
|
||
|
+ struct kstat *sp);
|
||
|
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/include/os/linux/zfs/sys/zpl.h b/include/os/linux/zfs/sys/zpl.h
|
||
|
index b0bb9c29c0b..21825d1f378 100644
|
||
|
--- a/include/os/linux/zfs/sys/zpl.h
|
||
|
+++ b/include/os/linux/zfs/sys/zpl.h
|
||
|
@@ -171,4 +171,22 @@ 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
|
||
|
+
|
||
|
+#ifdef 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/policy.c b/module/os/linux/zfs/policy.c
|
||
|
index 8780d7f6c70..bbccb2e572d 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/vdev_disk.c b/module/os/linux/zfs/vdev_disk.c
|
||
|
index 08c33313407..aaaf4105979 100644
|
||
|
--- a/module/os/linux/zfs/vdev_disk.c
|
||
|
+++ b/module/os/linux/zfs/vdev_disk.c
|
||
|
@@ -593,9 +593,14 @@ __vdev_disk_physio(struct block_device *bdev, zio_t *zio,
|
||
|
}
|
||
|
|
||
|
/* bio_alloc() with __GFP_WAIT never returns NULL */
|
||
|
+#ifdef HAVE_BIO_MAX_SEGS
|
||
|
+ dr->dr_bio[i] = bio_alloc(GFP_NOIO, bio_max_segs(
|
||
|
+ abd_nr_pages_off(zio->io_abd, bio_size, abd_offset)));
|
||
|
+#else
|
||
|
dr->dr_bio[i] = bio_alloc(GFP_NOIO,
|
||
|
MIN(abd_nr_pages_off(zio->io_abd, bio_size, abd_offset),
|
||
|
BIO_MAX_PAGES));
|
||
|
+#endif
|
||
|
if (unlikely(dr->dr_bio[i] == NULL)) {
|
||
|
vdev_disk_dio_free(dr);
|
||
|
return (SET_ERROR(ENOMEM));
|
||
|
diff --git a/module/os/linux/zfs/zfs_vnops_os.c b/module/os/linux/zfs/zfs_vnops_os.c
|
||
|
index 7484d651c1f..ce0701763fd 100644
|
||
|
--- a/module/os/linux/zfs/zfs_vnops_os.c
|
||
|
+++ b/module/os/linux/zfs/zfs_vnops_os.c
|
||
|
@@ -1907,7 +1907,8 @@ zfs_readdir(struct inode *ip, zpl_dir_context_t *ctx, cred_t *cr)
|
||
|
*/
|
||
|
/* ARGSUSED */
|
||
|
int
|
||
|
-zfs_getattr_fast(struct inode *ip, struct kstat *sp)
|
||
|
+zfs_getattr_fast(struct user_namespace *user_ns, struct inode *ip,
|
||
|
+ struct kstat *sp)
|
||
|
{
|
||
|
znode_t *zp = ITOZ(ip);
|
||
|
zfsvfs_t *zfsvfs = ITOZSB(ip);
|
||
|
@@ -1919,7 +1920,7 @@ zfs_getattr_fast(struct inode *ip, struct kstat *sp)
|
||
|
|
||
|
mutex_enter(&zp->z_lock);
|
||
|
|
||
|
- generic_fillattr(ip, sp);
|
||
|
+ 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 e6420f19ed8..9b526afd000 100644
|
||
|
--- a/module/os/linux/zfs/zpl_ctldir.c
|
||
|
+++ b/module/os/linux/zfs/zpl_ctldir.c
|
||
|
@@ -101,12 +101,22 @@ 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)
|
||
|
+#endif
|
||
|
{
|
||
|
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);
|
||
|
@@ -290,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;
|
||
|
@@ -309,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)
|
||
|
@@ -333,7 +349,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;
|
||
|
@@ -363,14 +384,24 @@ 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)
|
||
|
+#endif
|
||
|
{
|
||
|
struct inode *ip = path->dentry->d_inode;
|
||
|
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);
|
||
|
@@ -408,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,
|
||
|
@@ -495,8 +526,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)
|
||
|
+#endif
|
||
|
{
|
||
|
struct inode *ip = path->dentry->d_inode;
|
||
|
zfsvfs_t *zfsvfs = ITOZSB(ip);
|
||
|
@@ -506,7 +543,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);
|
||
|
@@ -515,7 +556,11 @@ zpl_shares_getattr_impl(const struct path *path, struct kstat *stat,
|
||
|
|
||
|
error = -zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp);
|
||
|
if (error == 0) {
|
||
|
- error = -zfs_getattr_fast(ZTOI(dzp), 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(kcred->user_ns, ZTOI(dzp), stat);
|
||
|
+#endif
|
||
|
iput(ZTOI(dzp));
|
||
|
}
|
||
|
|
||
|
diff --git a/module/os/linux/zfs/zpl_file.c b/module/os/linux/zfs/zpl_file.c
|
||
|
index 80762f9669b..08bf97ff338 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_inode.c b/module/os/linux/zfs/zpl_inode.c
|
||
|
index f336fbb1272..364b9fbef24 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;
|
||
|
@@ -163,7 +168,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();
|
||
|
@@ -278,7 +288,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;
|
||
|
@@ -338,8 +353,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;
|
||
|
@@ -350,7 +371,11 @@ zpl_getattr_impl(const struct path *path, struct kstat *stat, u32 request_mask,
|
||
|
* XXX request_mask and query_flags currently ignored.
|
||
|
*/
|
||
|
|
||
|
- error = -zfs_getattr_fast(path->dentry->d_inode, stat);
|
||
|
+#ifdef HAVE_USERNS_IOPS_GETATTR
|
||
|
+ error = -zfs_getattr_fast(user_ns, path->dentry->d_inode, stat);
|
||
|
+#else
|
||
|
+ error = -zfs_getattr_fast(kcred->user_ns, path->dentry->d_inode, stat);
|
||
|
+#endif
|
||
|
spl_fstrans_unmark(cookie);
|
||
|
ASSERT3S(error, <=, 0);
|
||
|
|
||
|
@@ -359,7 +384,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();
|
||
|
@@ -367,7 +397,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);
|
||
|
|
||
|
@@ -399,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;
|
||
|
@@ -421,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)
|
||
|
@@ -431,7 +467,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;
|
||
|
@@ -677,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,
|
||
|
diff --git a/module/os/linux/zfs/zpl_xattr.c b/module/os/linux/zfs/zpl_xattr.c
|
||
|
index 1ec3dae2bb8..5e35f90df85 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) {
|