Add trivial acl helpers
[zfs.git] / module / zfs / zfs_acl.c
index 1181bd4..ea209ba 100644 (file)
@@ -22,6 +22,8 @@
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
+#ifdef HAVE_ZPL
+
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/time.h>
@@ -51,7 +53,6 @@
 #include <sys/zap.h>
 #include <sys/sa.h>
 #include "fs/fs_subr.h"
-#include <acl/acl_common.h>
 
 #define        ALLOW   ACE_ACCESS_ALLOWED_ACE_TYPE
 #define        DENY    ACE_ACCESS_DENIED_ACE_TYPE
@@ -327,19 +328,35 @@ static acl_ops_t zfs_acl_fuid_ops = {
  * an external ACL and what version of ACL previously existed on the
  * file.  Would really be nice to not need this, sigh.
  */
-
 uint64_t
 zfs_external_acl(znode_t *zp)
 {
        zfs_acl_phys_t acl_phys;
+       int error;
 
        if (zp->z_is_sa)
                return (0);
 
-       VERIFY(0 == sa_lookup(zp->z_sa_hdl, SA_ZPL_ZNODE_ACL(zp->z_zfsvfs),
-           &acl_phys, sizeof (acl_phys)));
+       /*
+        * Need to deal with a potential
+        * race where zfs_sa_upgrade could cause
+        * z_isa_sa to change.
+        *
+        * If the lookup fails then the state of z_is_sa should have
+        * changed.
+        */
 
-       return (acl_phys.z_acl_extern_obj);
+       if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_ZNODE_ACL(zp->z_zfsvfs),
+           &acl_phys, sizeof (acl_phys))) == 0)
+               return (acl_phys.z_acl_extern_obj);
+       else {
+               /*
+                * after upgrade the SA_ZPL_ZNODE_ACL should have been
+                * removed
+                */
+               VERIFY(zp->z_is_sa && error == ENOENT);
+               return (0);
+       }
 }
 
 /*
@@ -357,6 +374,7 @@ zfs_acl_znode_info(znode_t *zp, int *aclsize, int *aclcount,
        int size;
        int error;
 
+       ASSERT(MUTEX_HELD(&zp->z_acl_lock));
        if (zp->z_is_sa) {
                if ((error = sa_size(zp->z_sa_hdl, SA_ZPL_DACL_ACES(zfsvfs),
                    &size)) != 0)
@@ -387,13 +405,31 @@ zfs_znode_acl_version(znode_t *zp)
 {
        zfs_acl_phys_t acl_phys;
 
-       if (zp->z_is_sa) {
+       if (zp->z_is_sa)
                return (ZFS_ACL_VERSION_FUID);
-       } else {
-               VERIFY(0 == sa_lookup(zp->z_sa_hdl,
+       else {
+               int error;
+
+               /*
+                * Need to deal with a potential
+                * race where zfs_sa_upgrade could cause
+                * z_isa_sa to change.
+                *
+                * If the lookup fails then the state of z_is_sa should have
+                * changed.
+                */
+               if ((error = sa_lookup(zp->z_sa_hdl,
                    SA_ZPL_ZNODE_ACL(zp->z_zfsvfs),
-                   &acl_phys, sizeof (acl_phys)));
-               return (acl_phys.z_acl_version);
+                   &acl_phys, sizeof (acl_phys))) == 0)
+                       return (acl_phys.z_acl_version);
+               else {
+                       /*
+                        * After upgrade SA_ZPL_ZNODE_ACL should have
+                        * been removed.
+                        */
+                       VERIFY(zp->z_is_sa && error == ENOENT);
+                       return (ZFS_ACL_VERSION_FUID);
+               }
        }
 }
 
@@ -457,7 +493,7 @@ zfs_acl_release_nodes(zfs_acl_t *aclp)
 {
        zfs_acl_node_t *aclnode;
 
-       while (aclnode = list_head(&aclp->z_acl)) {
+       while ((aclnode = list_head(&aclp->z_acl))) {
                list_remove(&aclp->z_acl, aclnode);
                zfs_acl_node_free(aclnode);
        }
@@ -607,13 +643,6 @@ zfs_ace_walk(void *datap, uint64_t cookie, int aclcnt,
        return ((uint64_t)(uintptr_t)acep);
 }
 
-static zfs_acl_node_t *
-zfs_acl_curr_node(zfs_acl_t *aclp)
-{
-       ASSERT(aclp->z_curr_node);
-       return (aclp->z_curr_node);
-}
-
 /*
  * Copy ACE to internal ZFS format.
  * While processing the ACL each ACE will be validated for correctness.
@@ -695,8 +724,8 @@ zfs_copy_fuid_2_ace(zfsvfs_t *zfsvfs, zfs_acl_t *aclp, cred_t *cr,
        size_t ace_size;
        uint16_t entry_type;
 
-       while (zacep = zfs_acl_next_ace(aclp, zacep,
-           &who, &access_mask, &iflags, &type)) {
+       while ((zacep = zfs_acl_next_ace(aclp, zacep,
+           &who, &access_mask, &iflags, &type))) {
 
                switch (type) {
                case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
@@ -786,8 +815,8 @@ zfs_acl_xform(znode_t *zp, zfs_acl_t *aclp, cred_t *cr)
        oldaclp = kmem_alloc(sizeof (zfs_oldace_t) * aclp->z_acl_count,
            KM_SLEEP);
        i = 0;
-       while (cookie = zfs_acl_next_ace(aclp, cookie, &who,
-           &access_mask, &iflags, &type)) {
+       while ((cookie = zfs_acl_next_ace(aclp, cookie, &who,
+           &access_mask, &iflags, &type))) {
                oldaclp[i].z_flags = iflags;
                oldaclp[i].z_type = type;
                oldaclp[i].z_fuid = who;
@@ -867,8 +896,8 @@ zfs_mode_compute(uint64_t fmode, zfs_acl_t *aclp,
 
        mode = (fmode & (S_IFMT | S_ISUID | S_ISGID | S_ISVTX));
 
-       while (acep = zfs_acl_next_ace(aclp, acep, &who,
-           &access_mask, &iflags, &type)) {
+       while ((acep = zfs_acl_next_ace(aclp, acep, &who,
+           &access_mask, &iflags, &type))) {
 
                if (!zfs_acl_valid_ace_type(type, iflags))
                        continue;
@@ -1024,7 +1053,8 @@ zfs_mode_compute(uint64_t fmode, zfs_acl_t *aclp,
  * create a new acl and leave any cached acl in place.
  */
 static int
-zfs_acl_node_read(znode_t *zp, zfs_acl_t **aclpp, boolean_t will_modify)
+zfs_acl_node_read(znode_t *zp, boolean_t have_lock, zfs_acl_t **aclpp,
+    boolean_t will_modify)
 {
        zfs_acl_t       *aclp;
        int             aclsize;
@@ -1033,6 +1063,7 @@ zfs_acl_node_read(znode_t *zp, zfs_acl_t **aclpp, boolean_t will_modify)
        zfs_acl_phys_t  znode_acl;
        int             version;
        int             error;
+       boolean_t       drop_lock = B_FALSE;
 
        ASSERT(MUTEX_HELD(&zp->z_acl_lock));
 
@@ -1041,11 +1072,23 @@ zfs_acl_node_read(znode_t *zp, zfs_acl_t **aclpp, boolean_t will_modify)
                return (0);
        }
 
-       version = ZNODE_ACL_VERSION(zp);
+       /*
+        * close race where znode could be upgrade while trying to
+        * read the znode attributes.
+        *
+        * But this could only happen if the file isn't already an SA
+        * znode
+        */
+       if (!zp->z_is_sa && !have_lock) {
+               mutex_enter(&zp->z_lock);
+               drop_lock = B_TRUE;
+       }
+       version = zfs_znode_acl_version(zp);
 
        if ((error = zfs_acl_znode_info(zp, &aclsize,
-           &acl_count, &znode_acl)) != 0)
-               return (error);
+           &acl_count, &znode_acl)) != 0) {
+               goto done;
+       }
 
        aclp = zfs_acl_alloc(version);
 
@@ -1076,7 +1119,7 @@ zfs_acl_node_read(znode_t *zp, zfs_acl_t **aclpp, boolean_t will_modify)
                /* convert checksum errors into IO errors */
                if (error == ECKSUM)
                        error = EIO;
-               return (error);
+               goto done;
        }
 
        list_insert_head(&aclp->z_acl, aclnode);
@@ -1084,7 +1127,10 @@ zfs_acl_node_read(znode_t *zp, zfs_acl_t **aclpp, boolean_t will_modify)
        *aclpp = aclp;
        if (!will_modify)
                zp->z_acl_cached = aclp;
-       return (0);
+done:
+       if (drop_lock)
+               mutex_exit(&zp->z_lock);
+       return (error);
 }
 
 /*ARGSUSED*/
@@ -1104,47 +1150,141 @@ zfs_acl_data_locator(void **dataptr, uint32_t *length, uint32_t buflen,
        *length = cb->cb_acl_node->z_size;
 }
 
-
-static int
-zfs_acl_get_owner_fuids(znode_t *zp, uint64_t *fuid, uint64_t *fgid)
-{
-       int count = 0;
-       sa_bulk_attr_t  bulk[2];
-       int error;
-
-       if (IS_EPHEMERAL(zp->z_uid) || IS_EPHEMERAL(zp->z_gid)) {
-               SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_UID(zp->z_zfsvfs), NULL,
-                   &fuid, sizeof (fuid));
-               SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_GID(zp->z_zfsvfs), NULL,
-                   &fgid, sizeof (fuid));
-               if ((error = sa_bulk_lookup(zp->z_sa_hdl, bulk, count)) != 0) {
-                       return (error);
-               }
-       } else {
-               *fuid = zp->z_uid;
-               *fgid = zp->z_gid;
-       }
-       return (0);
-}
-
 int
 zfs_acl_chown_setattr(znode_t *zp)
 {
        int error;
        zfs_acl_t *aclp;
-       uint64_t fuid, fgid;
 
-       if ((error = zfs_acl_get_owner_fuids(zp, &fuid, &fgid)) != 0)
-               return (error);
+       ASSERT(MUTEX_HELD(&zp->z_lock));
+       ASSERT(MUTEX_HELD(&zp->z_acl_lock));
 
-       mutex_enter(&zp->z_acl_lock);
-       if ((error = zfs_acl_node_read(zp, &aclp, B_FALSE)) == 0)
+       if ((error = zfs_acl_node_read(zp, B_TRUE, &aclp, B_FALSE)) == 0)
                zp->z_mode = zfs_mode_compute(zp->z_mode, aclp,
-                   &zp->z_pflags, fuid, fgid);
-       mutex_exit(&zp->z_acl_lock);
+                   &zp->z_pflags, zp->z_uid, zp->z_gid);
        return (error);
 }
 
+static void
+acl_trivial_access_masks(mode_t mode, uint32_t *allow0, uint32_t *deny1,
+    uint32_t *deny2, uint32_t *owner, uint32_t *group, uint32_t *everyone)
+{
+       *deny1 = *deny2 = *allow0 = *group = 0;
+
+       if (!(mode & S_IRUSR) && (mode & (S_IRGRP|S_IROTH)))
+               *deny1 |= ACE_READ_DATA;
+       if (!(mode & S_IWUSR) && (mode & (S_IWGRP|S_IWOTH)))
+               *deny1 |= ACE_WRITE_DATA;
+       if (!(mode & S_IXUSR) && (mode & (S_IXGRP|S_IXOTH)))
+               *deny1 |= ACE_EXECUTE;
+
+       if (!(mode & S_IRGRP) && (mode & S_IROTH))
+               *deny2 = ACE_READ_DATA;
+       if (!(mode & S_IWGRP) && (mode & S_IWOTH))
+               *deny2 |= ACE_WRITE_DATA;
+       if (!(mode & S_IXGRP) && (mode & S_IXOTH))
+               *deny2 |= ACE_EXECUTE;
+
+       if ((mode & S_IRUSR) && (!(mode & S_IRGRP) && (mode & S_IROTH)))
+               *allow0 |= ACE_READ_DATA;
+       if ((mode & S_IWUSR) && (!(mode & S_IWGRP) && (mode & S_IWOTH)))
+               *allow0 |= ACE_WRITE_DATA;
+       if ((mode & S_IXUSR) && (!(mode & S_IXGRP) && (mode & S_IXOTH)))
+               *allow0 |= ACE_EXECUTE;
+
+       *owner = ACE_WRITE_ATTRIBUTES|ACE_WRITE_OWNER|ACE_WRITE_ACL|
+           ACE_WRITE_NAMED_ATTRS|ACE_READ_ACL|ACE_READ_ATTRIBUTES|
+           ACE_READ_NAMED_ATTRS|ACE_SYNCHRONIZE;
+       if (mode & S_IRUSR)
+               *owner |= ACE_READ_DATA;
+       if (mode & S_IWUSR)
+               *owner |= ACE_WRITE_DATA|ACE_APPEND_DATA;
+       if (mode & S_IXUSR)
+               *owner |= ACE_EXECUTE;
+
+       *group = ACE_READ_ACL|ACE_READ_ATTRIBUTES| ACE_READ_NAMED_ATTRS|
+           ACE_SYNCHRONIZE;
+       if (mode & S_IRGRP)
+               *group |= ACE_READ_DATA;
+       if (mode & S_IWGRP)
+               *group |= ACE_WRITE_DATA|ACE_APPEND_DATA;
+       if (mode & S_IXGRP)
+               *group |= ACE_EXECUTE;
+
+       *everyone = ACE_READ_ACL|ACE_READ_ATTRIBUTES| ACE_READ_NAMED_ATTRS|
+           ACE_SYNCHRONIZE;
+       if (mode & S_IROTH)
+               *everyone |= ACE_READ_DATA;
+       if (mode & S_IWOTH)
+               *everyone |= ACE_WRITE_DATA|ACE_APPEND_DATA;
+       if (mode & S_IXOTH)
+               *everyone |= ACE_EXECUTE;
+}
+
+/*
+ * ace_trivial:
+ * determine whether an ace_t acl is trivial
+ *
+ * Trivialness implies that the acl is composed of only
+ * owner, group, everyone entries.  ACL can't
+ * have read_acl denied, and write_owner/write_acl/write_attributes
+ * can only be owner@ entry.
+ */
+static int
+ace_trivial_common(void *acep, int aclcnt,
+    uint64_t (*walk)(void *, uint64_t, int aclcnt,
+    uint16_t *, uint16_t *, uint32_t *))
+{
+       uint16_t flags;
+       uint32_t mask;
+       uint16_t type;
+       uint64_t cookie = 0;
+
+       while ((cookie = walk(acep, cookie, aclcnt, &flags, &type, &mask))) {
+               switch (flags & ACE_TYPE_FLAGS) {
+               case ACE_OWNER:
+               case ACE_GROUP|ACE_IDENTIFIER_GROUP:
+               case ACE_EVERYONE:
+                       break;
+               default:
+                       return (1);
+               }
+
+               if (flags & (ACE_FILE_INHERIT_ACE|
+                   ACE_DIRECTORY_INHERIT_ACE|ACE_NO_PROPAGATE_INHERIT_ACE|
+                   ACE_INHERIT_ONLY_ACE))
+                       return (1);
+
+               /*
+                * Special check for some special bits
+                *
+                * Don't allow anybody to deny reading basic
+                * attributes or a files ACL.
+                */
+               if ((mask & (ACE_READ_ACL|ACE_READ_ATTRIBUTES)) &&
+                   (type == ACE_ACCESS_DENIED_ACE_TYPE))
+                       return (1);
+
+               /*
+                * Delete permissions are never set by default
+                */
+               if (mask & (ACE_DELETE|ACE_DELETE_CHILD))
+                       return (1);
+               /*
+                * only allow owner@ to have
+                * write_acl/write_owner/write_attributes/write_xattr/
+                */
+               if (type == ACE_ACCESS_ALLOWED_ACE_TYPE &&
+                   (!(flags & ACE_OWNER) && (mask &
+                   (ACE_WRITE_OWNER|ACE_WRITE_ACL| ACE_WRITE_ATTRIBUTES|
+                   ACE_WRITE_NAMED_ATTRS))))
+                       return (1);
+
+       }
+
+       return (0);
+}
+
 /*
  * common code for setting ACLs.
  *
@@ -1163,14 +1303,11 @@ zfs_aclset_common(znode_t *zp, zfs_acl_t *aclp, cred_t *cr, dmu_tx_t *tx)
        sa_bulk_attr_t          bulk[5];
        uint64_t                ctime[2];
        int                     count = 0;
-       uint64_t                fuid, fgid;
 
        mode = zp->z_mode;
 
-       if ((error = zfs_acl_get_owner_fuids(zp, &fuid, &fgid)) != 0)
-               return (error);
-
-       mode = zfs_mode_compute(mode, aclp, &zp->z_pflags, fuid, fgid);
+       mode = zfs_mode_compute(mode, aclp, &zp->z_pflags,
+           zp->z_uid, zp->z_gid);
 
        zp->z_mode = mode;
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MODE(zfsvfs), NULL,
@@ -1307,73 +1444,6 @@ zfs_aclset_common(znode_t *zp, zfs_acl_t *aclp, cred_t *cr, dmu_tx_t *tx)
        return (sa_bulk_update(zp->z_sa_hdl, bulk, count, tx));
 }
 
-/*
- * Update access mask for prepended ACE
- *
- * This applies the "groupmask" value for aclmode property.
- */
-static void
-zfs_acl_prepend_fixup(zfs_acl_t *aclp, void  *acep, void  *origacep,
-    mode_t mode, uint64_t owner)
-{
-       int     rmask, wmask, xmask;
-       int     user_ace;
-       uint16_t aceflags;
-       uint32_t origmask, acepmask;
-       uint64_t fuid;
-
-       aceflags = aclp->z_ops.ace_flags_get(acep);
-       fuid = aclp->z_ops.ace_who_get(acep);
-       origmask = aclp->z_ops.ace_mask_get(origacep);
-       acepmask = aclp->z_ops.ace_mask_get(acep);
-
-       user_ace = (!(aceflags &
-           (ACE_OWNER|ACE_GROUP|ACE_IDENTIFIER_GROUP)));
-
-       if (user_ace && (fuid == owner)) {
-               rmask = S_IRUSR;
-               wmask = S_IWUSR;
-               xmask = S_IXUSR;
-       } else {
-               rmask = S_IRGRP;
-               wmask = S_IWGRP;
-               xmask = S_IXGRP;
-       }
-
-       if (origmask & ACE_READ_DATA) {
-               if (mode & rmask) {
-                       acepmask &= ~ACE_READ_DATA;
-               } else {
-                       acepmask |= ACE_READ_DATA;
-               }
-       }
-
-       if (origmask & ACE_WRITE_DATA) {
-               if (mode & wmask) {
-                       acepmask &= ~ACE_WRITE_DATA;
-               } else {
-                       acepmask |= ACE_WRITE_DATA;
-               }
-       }
-
-       if (origmask & ACE_APPEND_DATA) {
-               if (mode & wmask) {
-                       acepmask &= ~ACE_APPEND_DATA;
-               } else {
-                       acepmask |= ACE_APPEND_DATA;
-               }
-       }
-
-       if (origmask & ACE_EXECUTE) {
-               if (mode & xmask) {
-                       acepmask &= ~ACE_EXECUTE;
-               } else {
-                       acepmask |= ACE_EXECUTE;
-               }
-       }
-       aclp->z_ops.ace_mask_set(acep, acepmask);
-}
-
 static void
 zfs_acl_chmod(zfsvfs_t *zfsvfs, uint64_t mode, zfs_acl_t *aclp)
 {
@@ -1416,8 +1486,8 @@ zfs_acl_chmod(zfsvfs_t *zfsvfs, uint64_t mode, zfs_acl_t *aclp)
                new_bytes += abstract_size;
        }
 
-       while (acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask,
-           &iflags, &type)) {
+       while ((acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask,
+           &iflags, &type))) {
                uint16_t inherit_flags;
 
                entry_type = (iflags & ACE_TYPE_FLAGS);
@@ -1482,18 +1552,17 @@ zfs_acl_chmod(zfsvfs_t *zfsvfs, uint64_t mode, zfs_acl_t *aclp)
        list_insert_tail(&aclp->z_acl, newnode);
 }
 
-int
+void
 zfs_acl_chmod_setattr(znode_t *zp, zfs_acl_t **aclp, uint64_t mode)
 {
-       mutex_enter(&zp->z_lock);
        mutex_enter(&zp->z_acl_lock);
+       mutex_enter(&zp->z_lock);
        *aclp = zfs_acl_alloc(zfs_acl_version_zp(zp));
        (*aclp)->z_hints = zp->z_pflags & V4_ACL_WIDE_FLAGS;
        zfs_acl_chmod(zp->z_zfsvfs, mode, *aclp);
-       mutex_exit(&zp->z_acl_lock);
        mutex_exit(&zp->z_lock);
+       mutex_exit(&zp->z_acl_lock);
        ASSERT(*aclp);
-       return (0);
 }
 
 /*
@@ -1560,8 +1629,8 @@ zfs_acl_inherit(zfsvfs_t *zfsvfs, vtype_t vtype, zfs_acl_t *paclp,
        aclp = zfs_acl_alloc(paclp->z_version);
        if (zfsvfs->z_acl_inherit == ZFS_ACL_DISCARD || vtype == VLNK)
                return (aclp);
-       while (pacep = zfs_acl_next_ace(paclp, pacep, &who,
-           &access_mask, &iflags, &type)) {
+       while ((pacep = zfs_acl_next_ace(paclp, pacep, &who,
+           &access_mask, &iflags, &type))) {
 
                /*
                 * don't inherit bogus ACEs
@@ -1660,7 +1729,6 @@ zfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr,
        gid_t           gid;
        boolean_t       need_chmod = B_TRUE;
        boolean_t       inherited = B_FALSE;
-       uint64_t        parentgid;
 
        bzero(acl_ids, sizeof (zfs_acl_ids_t));
        acl_ids->z_mode = MAKEIMODE(vap->va_type, vap->va_mode);
@@ -1682,12 +1750,6 @@ zfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr,
                    ZFS_GROUP, &acl_ids->z_fuidp);
                gid = vap->va_gid;
        } else {
-               if (IS_EPHEMERAL(dzp->z_gid))
-                       VERIFY(0 == sa_lookup(dzp->z_sa_hdl, SA_ZPL_GID(zfsvfs),
-                           &parentgid, sizeof (parentgid)));
-               else
-                       parentgid = (uint64_t)dzp->z_gid;
-
                acl_ids->z_fuid = zfs_fuid_create_cred(zfsvfs, ZFS_OWNER,
                    cr, &acl_ids->z_fuidp);
                acl_ids->z_fgid = 0;
@@ -1696,7 +1758,7 @@ zfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr,
                            (uint64_t)vap->va_gid,
                            cr, ZFS_GROUP, &acl_ids->z_fuidp);
                        gid = vap->va_gid;
-                       if (acl_ids->z_fgid != parentgid &&
+                       if (acl_ids->z_fgid != dzp->z_gid &&
                            !groupmember(vap->va_gid, cr) &&
                            secpolicy_vnode_create_gid(cr) != 0)
                                acl_ids->z_fgid = 0;
@@ -1706,7 +1768,7 @@ zfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr,
                                char            *domain;
                                uint32_t        rid;
 
-                               acl_ids->z_fgid = parentgid;
+                               acl_ids->z_fgid = dzp->z_gid;
                                gid = zfs_fuid_map_id(zfsvfs, acl_ids->z_fgid,
                                    cr, ZFS_GROUP);
 
@@ -1746,15 +1808,15 @@ zfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr,
        }
 
        if (acl_ids->z_aclp == NULL) {
+               mutex_enter(&dzp->z_acl_lock);
                mutex_enter(&dzp->z_lock);
                if (!(flag & IS_ROOT_NODE) && (ZTOV(dzp)->v_type == VDIR &&
                    (dzp->z_pflags & ZFS_INHERIT_ACE)) &&
                    !(dzp->z_pflags & ZFS_XATTR)) {
-                       mutex_enter(&dzp->z_acl_lock);
-                       VERIFY(0 == zfs_acl_node_read(dzp, &paclp, B_FALSE));
+                       VERIFY(0 == zfs_acl_node_read(dzp, B_TRUE,
+                           &paclp, B_FALSE));
                        acl_ids->z_aclp = zfs_acl_inherit(zfsvfs,
                            vap->va_type, paclp, acl_ids->z_mode, &need_chmod);
-                       mutex_exit(&dzp->z_acl_lock);
                        inherited = B_TRUE;
                } else {
                        acl_ids->z_aclp =
@@ -1762,6 +1824,7 @@ zfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr,
                        acl_ids->z_aclp->z_hints |= ZFS_ACL_TRIVIAL;
                }
                mutex_exit(&dzp->z_lock);
+               mutex_exit(&dzp->z_acl_lock);
                if (need_chmod) {
                        acl_ids->z_aclp->z_hints |= (vap->va_type == VDIR) ?
                            ZFS_ACL_AUTO_INHERIT : 0;
@@ -1819,12 +1882,12 @@ zfs_getacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr)
        if (mask == 0)
                return (ENOSYS);
 
-       if (error = zfs_zaccess(zp, ACE_READ_ACL, 0, skipaclchk, cr))
+       if ((error = zfs_zaccess(zp, ACE_READ_ACL, 0, skipaclchk, cr)))
                return (error);
 
        mutex_enter(&zp->z_acl_lock);
 
-       error = zfs_acl_node_read(zp, &aclp, B_FALSE);
+       error = zfs_acl_node_read(zp, B_FALSE, &aclp, B_FALSE);
        if (error != 0) {
                mutex_exit(&zp->z_acl_lock);
                return (error);
@@ -1839,8 +1902,8 @@ zfs_getacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr)
                uint32_t access_mask;
                uint16_t type, iflags;
 
-               while (zacep = zfs_acl_next_ace(aclp, zacep,
-                   &who, &access_mask, &iflags, &type)) {
+               while ((zacep = zfs_acl_next_ace(aclp, zacep,
+                   &who, &access_mask, &iflags, &type))) {
                        switch (type) {
                        case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
                        case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
@@ -1970,6 +2033,7 @@ zfs_setacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr)
        zfs_acl_t       *aclp;
        zfs_fuid_info_t *fuidp = NULL;
        boolean_t       fuid_dirtied;
+       uint64_t        acl_obj;
 
        if (mask == 0)
                return (ENOSYS);
@@ -1977,7 +2041,7 @@ zfs_setacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr)
        if (zp->z_pflags & ZFS_IMMUTABLE)
                return (EPERM);
 
-       if (error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr))
+       if ((error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr)))
                return (error);
 
        error = zfs_vsec_2_aclp(zfsvfs, ZTOV(zp)->v_type, vsecp, cr, &fuidp,
@@ -1994,8 +2058,8 @@ zfs_setacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr)
                    (zp->z_pflags & V4_ACL_WIDE_FLAGS);
        }
 top:
-       mutex_enter(&zp->z_lock);
        mutex_enter(&zp->z_acl_lock);
+       mutex_enter(&zp->z_lock);
 
        tx = dmu_tx_create(zfsvfs->z_os);
 
@@ -2010,14 +2074,15 @@ top:
         * upgrading then take out necessary DMU holds
         */
 
-       if (ZFS_EXTERNAL_ACL(zp)) {
-               if (zfsvfs->z_version <= ZPL_VERSION_SA &&
-                   ZNODE_ACL_VERSION(zp) <= ZFS_ACL_VERSION_INITIAL) {
-                       dmu_tx_hold_free(tx, ZFS_EXTERNAL_ACL(zp), 0,
+       if ((acl_obj = zfs_external_acl(zp)) != 0) {
+               if (zfsvfs->z_version >= ZPL_VERSION_FUID &&
+                   zfs_znode_acl_version(zp) <= ZFS_ACL_VERSION_INITIAL) {
+                       dmu_tx_hold_free(tx, acl_obj, 0,
                            DMU_OBJECT_END);
+                       dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0,
+                           aclp->z_acl_bytes);
                } else {
-                       dmu_tx_hold_write(tx, ZFS_EXTERNAL_ACL(zp),
-                           0, aclp->z_acl_bytes);
+                       dmu_tx_hold_write(tx, acl_obj, 0, aclp->z_acl_bytes);
                }
        } else if (!zp->z_is_sa && aclp->z_acl_bytes > ZFS_ACE_SPACE) {
                dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, aclp->z_acl_bytes);
@@ -2041,6 +2106,7 @@ top:
 
        error = zfs_aclset_common(zp, aclp, cr, tx);
        ASSERT(error == 0);
+       ASSERT(zp->z_acl_cached == NULL);
        zp->z_acl_cached = aclp;
 
        if (fuid_dirtied)
@@ -2051,9 +2117,9 @@ top:
        if (fuidp)
                zfs_fuid_info_free(fuidp);
        dmu_tx_commit(tx);
-done:
-       mutex_exit(&zp->z_acl_lock);
+
        mutex_exit(&zp->z_lock);
+       mutex_exit(&zp->z_acl_lock);
 
        return (error);
 }
@@ -2137,11 +2203,14 @@ zfs_zaccess_aces_check(znode_t *zp, uint32_t *working_mode,
        uint32_t        deny_mask = 0;
        zfs_ace_hdr_t   *acep = NULL;
        boolean_t       checkit;
-       uint64_t        gowner;
+       uid_t           gowner;
+       uid_t           fowner;
+
+       zfs_fuid_map_ids(zp, cr, &fowner, &gowner);
 
        mutex_enter(&zp->z_acl_lock);
 
-       error = zfs_acl_node_read(zp, &aclp, B_FALSE);
+       error = zfs_acl_node_read(zp, B_FALSE, &aclp, B_FALSE);
        if (error != 0) {
                mutex_exit(&zp->z_acl_lock);
                return (error);
@@ -2149,14 +2218,8 @@ zfs_zaccess_aces_check(znode_t *zp, uint32_t *working_mode,
 
        ASSERT(zp->z_acl_cached);
 
-       if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_GID(zfsvfs),
-           &gowner, sizeof (gowner))) != 0) {
-               mutex_exit(&zp->z_acl_lock);
-               return (error);
-       }
-
-       while (acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask,
-           &iflags, &type)) {
+       while ((acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask,
+           &iflags, &type))) {
                uint32_t mask_matched;
 
                if (!zfs_acl_valid_ace_type(type, iflags))
@@ -2176,7 +2239,7 @@ zfs_zaccess_aces_check(znode_t *zp, uint32_t *working_mode,
 
                switch (entry_type) {
                case ACE_OWNER:
-                       if (uid == zp->z_uid)
+                       if (uid == fowner)
                                checkit = B_TRUE;
                        break;
                case OWNING_GROUP:
@@ -2254,8 +2317,10 @@ zfs_has_access(znode_t *zp, cred_t *cr)
        uint32_t have = ACE_ALL_PERMS;
 
        if (zfs_zaccess_aces_check(zp, &have, B_TRUE, cr) != 0) {
-               return (secpolicy_vnode_any_access(cr, ZTOV(zp),
-                   zp->z_uid) == 0);
+               uid_t owner;
+
+               owner = zfs_fuid_map_id(zp->z_zfsvfs, zp->z_uid, cr, ZFS_OWNER);
+               return (secpolicy_vnode_any_access(cr, ZTOV(zp), owner) == 0);
        }
        return (B_TRUE);
 }
@@ -2332,7 +2397,7 @@ zfs_fastaccesschk_execute(znode_t *zdp, cred_t *cr)
                return (0);
        }
 
-       if (IS_EPHEMERAL(zdp->z_uid) != 0 || IS_EPHEMERAL(zdp->z_gid) != 0) {
+       if (FUID_INDEX(zdp->z_uid) != 0 || FUID_INDEX(zdp->z_gid) != 0) {
                mutex_exit(&zdp->z_acl_lock);
                goto slow;
        }
@@ -2389,6 +2454,7 @@ zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr)
        znode_t         *xzp;
        znode_t         *check_zp = zp;
        mode_t          needed_bits;
+       uid_t           owner;
 
        is_attr = ((zp->z_pflags & ZFS_XATTR) && (ZTOV(zp)->v_type == VDIR));
 
@@ -2425,6 +2491,7 @@ zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr)
                }
        }
 
+       owner = zfs_fuid_map_id(zp->z_zfsvfs, zp->z_uid, cr, ZFS_OWNER);
        /*
         * Map the bits required to the standard vnode flags VREAD|VWRITE|VEXEC
         * in needed_bits.  Map the bits mapped by working_mode (currently
@@ -2436,7 +2503,7 @@ zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr)
 
        working_mode = mode;
        if ((working_mode & (ACE_READ_ACL|ACE_READ_ATTRIBUTES)) &&
-           zp->z_uid == crgetuid(cr))
+           owner == crgetuid(cr))
                working_mode &= ~(ACE_READ_ACL|ACE_READ_ATTRIBUTES);
 
        if (working_mode & (ACE_READ_DATA|ACE_READ_NAMED_ATTRS|
@@ -2452,7 +2519,7 @@ zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr)
            &check_privs, skipaclchk, cr)) == 0) {
                if (is_attr)
                        VN_RELE(ZTOV(xzp));
-               return (secpolicy_vnode_access2(cr, ZTOV(zp), zp->z_uid,
+               return (secpolicy_vnode_access2(cr, ZTOV(zp), owner,
                    needed_bits, needed_bits));
        }
 
@@ -2478,7 +2545,7 @@ zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr)
                ASSERT(working_mode != 0);
 
                if ((working_mode & (ACE_READ_ACL|ACE_READ_ATTRIBUTES) &&
-                   zp->z_uid == crgetuid(cr)))
+                   owner == crgetuid(cr)))
                        working_mode &= ~(ACE_READ_ACL|ACE_READ_ATTRIBUTES);
 
                if (working_mode & (ACE_READ_DATA|ACE_READ_NAMED_ATTRS|
@@ -2490,20 +2557,20 @@ zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr)
                if (working_mode & ACE_EXECUTE)
                        checkmode |= VEXEC;
 
-               error = secpolicy_vnode_access2(cr, ZTOV(check_zp), zp->z_uid,
+               error = secpolicy_vnode_access2(cr, ZTOV(check_zp), owner,
                    needed_bits & ~checkmode, needed_bits);
 
                if (error == 0 && (working_mode & ACE_WRITE_OWNER))
-                       error = secpolicy_vnode_chown(cr, zp->z_uid);
+                       error = secpolicy_vnode_chown(cr, owner);
                if (error == 0 && (working_mode & ACE_WRITE_ACL))
-                       error = secpolicy_vnode_setdac(cr, zp->z_uid);
+                       error = secpolicy_vnode_setdac(cr, owner);
 
                if (error == 0 && (working_mode &
                    (ACE_DELETE|ACE_DELETE_CHILD)))
                        error = secpolicy_vnode_remove(cr);
 
                if (error == 0 && (working_mode & ACE_SYNCHRONIZE)) {
-                       error = secpolicy_vnode_chown(cr, zp->z_uid);
+                       error = secpolicy_vnode_chown(cr, owner);
                }
                if (error == 0) {
                        /*
@@ -2515,7 +2582,7 @@ zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr)
                        }
                }
        } else if (error == 0) {
-               error = secpolicy_vnode_access2(cr, ZTOV(zp), zp->z_uid,
+               error = secpolicy_vnode_access2(cr, ZTOV(zp), owner,
                    needed_bits, needed_bits);
        }
 
@@ -2552,9 +2619,12 @@ zfs_delete_final_check(znode_t *zp, znode_t *dzp,
     mode_t available_perms, cred_t *cr)
 {
        int error;
+       uid_t downer;
+
+       downer = zfs_fuid_map_id(dzp->z_zfsvfs, dzp->z_uid, cr, ZFS_OWNER);
 
        error = secpolicy_vnode_access2(cr, ZTOV(dzp),
-           dzp->z_uid, available_perms, VWRITE|VEXEC);
+           downer, available_perms, VWRITE|VEXEC);
 
        if (error == 0)
                error = zfs_sticky_remove_access(dzp, zp, cr);
@@ -2705,14 +2775,14 @@ zfs_zaccess_rename(znode_t *sdzp, znode_t *szp, znode_t *tdzp,
         * If that succeeds then check for add_file/add_subdir permissions
         */
 
-       if (error = zfs_zaccess_delete(sdzp, szp, cr))
+       if ((error = zfs_zaccess_delete(sdzp, szp, cr)))
                return (error);
 
        /*
         * If we have a tzp, see if we can delete it?
         */
        if (tzp) {
-               if (error = zfs_zaccess_delete(tdzp, tzp, cr))
+               if ((error = zfs_zaccess_delete(tdzp, tzp, cr)))
                        return (error);
        }
 
@@ -2723,3 +2793,5 @@ zfs_zaccess_rename(znode_t *sdzp, znode_t *szp, znode_t *tdzp,
 
        return (error);
 }
+
+#endif /* HAVE_ZPL */