]> granicus.if.org Git - zfs/commitdiff
Linux 4.7 compat: fix zpl_get_acl returns invalid acl pointer
authorChunwei Chen <david.chen@osnexus.com>
Tue, 9 Aug 2016 00:26:21 +0000 (17:26 -0700)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Tue, 9 Aug 2016 17:03:04 +0000 (10:03 -0700)
Starting from Linux 4.7, get_acl will set acl cache pointer to temporary
sentinel value before calling i_op->get_acl. Therefore we can't compare
against ACL_NOT_CACHED and return.

Since from Linux 3.14, get_acl already check the cache for us, so we
disable this in zpl_get_acl.

Linux 4.7 also does set_cached_acl for us so we disable it in zpl_get_acl.

Signed-off-by: Chunwei Chen <david.chen@osnexus.com>
Signed-off-by: Nikolay Borisov <n.borisov.lkml@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #4944
Closes #4946

config/kernel-acl.m4
config/kernel.m4
module/zfs/zpl_xattr.c

index d2a1821c57d4d298de809a64b83588cf100c7890..50b502c31416dfdfd5d1f5ee51487e0fed482a4e 100644 (file)
@@ -249,3 +249,23 @@ AC_DEFUN([ZFS_AC_KERNEL_INODE_OPERATIONS_GET_ACL], [
                AC_MSG_RESULT(no)
        ])
 ])
+
+dnl #
+dnl # 4.7 API change,
+dnl # The kernel get_acl will now check cache before calling i_op->get_acl and
+dnl # do set_cached_acl after that, so i_op->get_acl don't need to do that
+dnl # anymore.
+dnl #
+AC_DEFUN([ZFS_AC_KERNE_GET_ACL_HANDLE_CACHE], [
+       AC_MSG_CHECKING([whether uncached_acl_sentinel() exists])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/fs.h>
+       ],[
+               void *sentinel __attribute__ ((unused)) = uncached_acl_sentinel(NULL);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_KERNEL_GET_ACL_HANDLE_CACHE, 1, [uncached_acl_sentinel() exists])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
index 507e81010d4206b924c66f38a5bbe2840d746867..7a207f642050bb5f2021c3793dd3b3d5b094cfca 100644 (file)
@@ -49,6 +49,7 @@ AC_DEFUN([ZFS_AC_CONFIG_KERNEL], [
        ZFS_AC_KERNEL_INODE_OPERATIONS_CHECK_ACL
        ZFS_AC_KERNEL_INODE_OPERATIONS_CHECK_ACL_WITH_FLAGS
        ZFS_AC_KERNEL_INODE_OPERATIONS_GET_ACL
+       ZFS_AC_KERNE_GET_ACL_HANDLE_CACHE
        ZFS_AC_KERNEL_SHOW_OPTIONS
        ZFS_AC_KERNEL_FILE_INODE
        ZFS_AC_KERNEL_FSYNC
index ab81dd2d06e5d11634587ce7d9567f1e2034e81f..471cb16c67ef8af06cac20c15ac0642d05566a66 100644 (file)
@@ -1017,9 +1017,16 @@ zpl_get_acl(struct inode *ip, int type)
        char *name;
        int size;
 
+       /*
+        * As of Linux 3.14, the kernel get_acl will check this for us.
+        * Also as of Linux 4.7, comparing against ACL_NOT_CACHED is wrong
+        * as the kernel get_acl will set it to temporary sentinel value.
+        */
+#ifndef HAVE_KERNEL_GET_ACL_HANDLE_CACHE
        acl = get_cached_acl(ip, type);
        if (acl != ACL_NOT_CACHED)
                return (acl);
+#endif
 
        switch (type) {
        case ACL_TYPE_ACCESS:
@@ -1049,8 +1056,11 @@ zpl_get_acl(struct inode *ip, int type)
        if (size > 0)
                kmem_free(value, size);
 
+       /* As of Linux 4.7, the kernel get_acl will set this for us */
+#ifndef HAVE_KERNEL_GET_ACL_HANDLE_CACHE
        if (!IS_ERR(acl))
                zpl_set_cached_acl(ip, type, acl);
+#endif
 
        return (acl);
 }