From f8d050934ec64d4654dd17f71094747e3bf7e1bb Mon Sep 17 00:00:00 2001 From: Brian Behlendorf Date: Wed, 8 Sep 2021 16:01:32 -0700 Subject: [PATCH] Linux 5.15 compat: get_acl() Kernel commits 332f606b32b6 ovl: enable RCU'd ->get_acl() 0cad6246621b vfs: add rcu argument to ->get_acl() callback Added compatibility code to detect the new ->get_acl() interface and correctly handle the case where the new rcu argument is set. Signed-off-by: Brian Behlendorf --- config/kernel-acl.m4 | 23 +++++++++++++++++++++- include/os/linux/zfs/sys/zpl.h | 4 ++++ module/os/linux/zfs/zpl_xattr.c | 34 +++++++++++++++++++++++++-------- 3 files changed, 52 insertions(+), 9 deletions(-) diff --git a/config/kernel-acl.m4 b/config/kernel-acl.m4 index c6da4df24eb9..a155b59d006a 100644 --- a/config/kernel-acl.m4 +++ b/config/kernel-acl.m4 @@ -162,6 +162,9 @@ dnl # dnl # 3.1 API change, dnl # Check if inode_operations contains the function get_acl dnl # +dnl # 5.15 API change, +dnl # Added the bool rcu argument to get_acl for rcu path walk. +dnl # AC_DEFUN([ZFS_AC_KERNEL_SRC_INODE_OPERATIONS_GET_ACL], [ ZFS_LINUX_TEST_SRC([inode_operations_get_acl], [ #include @@ -174,14 +177,32 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_INODE_OPERATIONS_GET_ACL], [ .get_acl = get_acl_fn, }; ],[]) + + ZFS_LINUX_TEST_SRC([inode_operations_get_acl_rcu], [ + #include + + struct posix_acl *get_acl_fn(struct inode *inode, int type, + bool rcu) { return NULL; } + + static const struct inode_operations + iops __attribute__ ((unused)) = { + .get_acl = get_acl_fn, + }; + ],[]) ]) AC_DEFUN([ZFS_AC_KERNEL_INODE_OPERATIONS_GET_ACL], [ AC_MSG_CHECKING([whether iops->get_acl() exists]) ZFS_LINUX_TEST_RESULT([inode_operations_get_acl], [ AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_GET_ACL, 1, [iops->get_acl() exists]) ],[ - ZFS_LINUX_TEST_ERROR([iops->get_acl()]) + ZFS_LINUX_TEST_RESULT([inode_operations_get_acl_rcu], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_GET_ACL_RCU, 1, [iops->get_acl() takes rcu]) + ],[ + ZFS_LINUX_TEST_ERROR([iops->get_acl()]) + ]) ]) ]) diff --git a/include/os/linux/zfs/sys/zpl.h b/include/os/linux/zfs/sys/zpl.h index 54f3fa0fdb0f..ff86e027bbe2 100644 --- a/include/os/linux/zfs/sys/zpl.h +++ b/include/os/linux/zfs/sys/zpl.h @@ -70,7 +70,11 @@ extern int zpl_set_acl(struct user_namespace *userns, struct inode *ip, extern int zpl_set_acl(struct inode *ip, struct posix_acl *acl, int type); #endif /* HAVE_SET_ACL_USERNS */ #endif /* HAVE_SET_ACL */ +#if defined(HAVE_GET_ACL_RCU) +extern struct posix_acl *zpl_get_acl(struct inode *ip, int type, bool rcu); +#elif defined(HAVE_GET_ACL) extern struct posix_acl *zpl_get_acl(struct inode *ip, int type); +#endif extern int zpl_init_acl(struct inode *ip, struct inode *dir); extern int zpl_chmod_acl(struct inode *ip); #else diff --git a/module/os/linux/zfs/zpl_xattr.c b/module/os/linux/zfs/zpl_xattr.c index 66f197e4c77a..e7726e8458af 100644 --- a/module/os/linux/zfs/zpl_xattr.c +++ b/module/os/linux/zfs/zpl_xattr.c @@ -1012,13 +1012,12 @@ zpl_set_acl(struct inode *ip, struct posix_acl *acl, int type) } #endif /* HAVE_SET_ACL */ -struct posix_acl * -zpl_get_acl(struct inode *ip, int type) +static struct posix_acl * +zpl_get_acl_impl(struct inode *ip, int type) { struct posix_acl *acl; void *value = NULL; char *name; - int size; /* * As of Linux 3.14, the kernel get_acl will check this for us. @@ -1042,7 +1041,7 @@ zpl_get_acl(struct inode *ip, int type) return (ERR_PTR(-EINVAL)); } - size = zpl_xattr_get(ip, name, NULL, 0); + int size = zpl_xattr_get(ip, name, NULL, 0); if (size > 0) { value = kmem_alloc(size, KM_SLEEP); size = zpl_xattr_get(ip, name, value, size); @@ -1068,6 +1067,25 @@ zpl_get_acl(struct inode *ip, int type) return (acl); } +#if defined(HAVE_GET_ACL_RCU) +struct posix_acl * +zpl_get_acl(struct inode *ip, int type, bool rcu) +{ + if (rcu) + return (ERR_PTR(-ECHILD)); + + return (zpl_get_acl_impl(ip, type)); +} +#elif defined(HAVE_GET_ACL) +struct posix_acl * +zpl_get_acl(struct inode *ip, int type) +{ + return (zpl_get_acl_impl(ip, type)); +} +#else +#error "Unsupported iops->get_acl() implementation" +#endif /* HAVE_GET_ACL_RCU */ + int zpl_init_acl(struct inode *ip, struct inode *dir) { @@ -1078,7 +1096,7 @@ zpl_init_acl(struct inode *ip, struct inode *dir) return (0); if (!S_ISLNK(ip->i_mode)) { - acl = zpl_get_acl(dir, ACL_TYPE_DEFAULT); + acl = zpl_get_acl_impl(dir, ACL_TYPE_DEFAULT); if (IS_ERR(acl)) return (PTR_ERR(acl)); if (!acl) { @@ -1127,7 +1145,7 @@ zpl_chmod_acl(struct inode *ip) if (S_ISLNK(ip->i_mode)) return (-EOPNOTSUPP); - acl = zpl_get_acl(ip, ACL_TYPE_ACCESS); + acl = zpl_get_acl_impl(ip, ACL_TYPE_ACCESS); if (IS_ERR(acl) || !acl) return (PTR_ERR(acl)); @@ -1189,7 +1207,7 @@ __zpl_xattr_acl_get_access(struct inode *ip, const char *name, if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIX) return (-EOPNOTSUPP); - acl = zpl_get_acl(ip, type); + acl = zpl_get_acl_impl(ip, type); if (IS_ERR(acl)) return (PTR_ERR(acl)); if (acl == NULL) @@ -1217,7 +1235,7 @@ __zpl_xattr_acl_get_default(struct inode *ip, const char *name, if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIX) return (-EOPNOTSUPP); - acl = zpl_get_acl(ip, type); + acl = zpl_get_acl_impl(ip, type); if (IS_ERR(acl)) return (PTR_ERR(acl)); if (acl == NULL)