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..7a356bf29f99 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) {