6650192 zfs ACL/fuid code could use some minor cleanup
authormarks
Fri, 01 Feb 2008 12:13:54 -0800
changeset 5959 1e1904b8526d
parent 5958 d8f13d1693ee
child 5960 31e26d74cdc5
6650192 zfs ACL/fuid code could use some minor cleanup 6650223 zdb znode output should include uid/gid and possible SID information 6657644 zfs_fuid_init() panic
usr/src/cmd/zdb/zdb.c
usr/src/lib/libzpool/common/kernel.c
usr/src/lib/libzpool/common/sys/zfs_context.h
usr/src/uts/common/Makefile.files
usr/src/uts/common/fs/zfs/sys/zfs_fuid.h
usr/src/uts/common/fs/zfs/zfs_acl.c
usr/src/uts/common/fs/zfs/zfs_dir.c
usr/src/uts/common/fs/zfs/zfs_fuid.c
usr/src/uts/common/fs/zfs/zfs_vnops.c
--- a/usr/src/cmd/zdb/zdb.c	Fri Feb 01 10:11:12 2008 -0800
+++ b/usr/src/cmd/zdb/zdb.c	Fri Feb 01 12:13:54 2008 -0800
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -51,6 +51,7 @@
 #include <sys/dmu_traverse.h>
 #include <sys/zio_checksum.h>
 #include <sys/zio_compress.h>
+#include <sys/zfs_fuid.h>
 #undef ZFS_MAXNAMELEN
 #undef verify
 #include <libzfs.h>
@@ -848,6 +849,64 @@
 	mutex_destroy(&bpl.bpl_lock);
 }
 
+static avl_tree_t idx_tree;
+static avl_tree_t domain_tree;
+static boolean_t fuid_table_loaded;
+
+static void
+fuid_table_destroy()
+{
+	if (fuid_table_loaded) {
+		zfs_fuid_table_destroy(&idx_tree, &domain_tree);
+		fuid_table_loaded = B_FALSE;
+	}
+}
+
+/*
+ * print uid or gid information.
+ * For normal POSIX id just the id is printed in decimal format.
+ * For CIFS files with FUID the fuid is printed in hex followed by
+ * the doman-rid string.
+ */
+static void
+print_idstr(uint64_t id, const char *id_type)
+{
+	if (FUID_INDEX(id)) {
+		char *domain;
+
+		domain = zfs_fuid_idx_domain(&idx_tree, FUID_INDEX(id));
+		(void) printf("\t%s     %llx [%s-%d]\n", id_type,
+		    (u_longlong_t)id, domain, (int)FUID_RID(id));
+	} else {
+		(void) printf("\t%s     %llu\n", id_type, (u_longlong_t)id);
+	}
+
+}
+
+static void
+dump_uidgid(objset_t *os, znode_phys_t *zp)
+{
+	uint32_t uid_idx, gid_idx;
+
+	uid_idx = FUID_INDEX(zp->zp_uid);
+	gid_idx = FUID_INDEX(zp->zp_gid);
+
+	/* Load domain table, if not already loaded */
+	if (!fuid_table_loaded && (uid_idx || gid_idx)) {
+		uint64_t fuid_obj;
+
+		/* first find the fuid object.  It lives in the master node */
+		VERIFY(zap_lookup(os, MASTER_NODE_OBJ, ZFS_FUID_TABLES,
+		    8, 1, &fuid_obj) == 0);
+		(void) zfs_fuid_table_load(os, fuid_obj,
+		    &idx_tree, &domain_tree);
+		fuid_table_loaded = B_TRUE;
+	}
+
+	print_idstr(zp->zp_uid, "uid");
+	print_idstr(zp->zp_gid, "gid");
+}
+
 /*ARGSUSED*/
 static void
 dump_znode(objset_t *os, uint64_t object, void *data, size_t size)
@@ -876,6 +935,7 @@
 	z_ctime = (time_t)zp->zp_ctime[0];
 
 	(void) printf("\tpath	%s\n", path);
+	dump_uidgid(os, zp);
 	(void) printf("\tatime	%s", ctime(&z_atime));
 	(void) printf("\tmtime	%s", ctime(&z_mtime));
 	(void) printf("\tctime	%s", ctime(&z_ctime));
@@ -1230,6 +1290,7 @@
 	}
 	dump_dir(os);
 	dmu_objset_close(os);
+	fuid_table_destroy();
 	return (0);
 }
 
@@ -2408,6 +2469,8 @@
 		spa_close(spa, FTAG);
 	}
 
+	fuid_table_destroy();
+
 	libzfs_fini(g_zfs);
 	kernel_fini();
 
--- a/usr/src/lib/libzpool/common/kernel.c	Fri Feb 01 10:11:12 2008 -0800
+++ b/usr/src/lib/libzpool/common/kernel.c	Fri Feb 01 12:13:54 2008 -0800
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -874,3 +874,20 @@
 {
 	return (0);
 }
+
+ksiddomain_t *
+ksid_lookupdomain(const char *dom)
+{
+	ksiddomain_t *kd;
+
+	kd = umem_zalloc(sizeof (ksiddomain_t), UMEM_NOFAIL);
+	kd->kd_name = spa_strdup(dom);
+	return (kd);
+}
+
+void
+ksiddomain_rele(ksiddomain_t *ksid)
+{
+	spa_strfree(ksid->kd_name);
+	umem_free(ksid, sizeof (ksiddomain_t));
+}
--- a/usr/src/lib/libzpool/common/sys/zfs_context.h	Fri Feb 01 10:11:12 2008 -0800
+++ b/usr/src/lib/libzpool/common/sys/zfs_context.h	Fri Feb 01 12:13:54 2008 -0800
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -521,6 +521,16 @@
 extern int zfs_secpolicy_destroy_perms(const char *name, cred_t *cr);
 extern zoneid_t getzoneid(void);
 
+/* SID stuff */
+typedef struct ksiddomain {
+	uint_t	kd_ref;
+	uint_t	kd_len;
+	char	*kd_name;
+} ksiddomain_t;
+
+ksiddomain_t *ksid_lookupdomain(const char *);
+void ksiddomain_rele(ksiddomain_t *);
+
 #ifdef	__cplusplus
 }
 #endif
--- a/usr/src/uts/common/Makefile.files	Fri Feb 01 10:11:12 2008 -0800
+++ b/usr/src/uts/common/Makefile.files	Fri Feb 01 12:13:54 2008 -0800
@@ -1115,6 +1115,7 @@
 	zap_micro.o		\
 	zfs_byteswap.o		\
 	zfs_fm.o		\
+	zfs_fuid.o		\
 	zfs_znode.o		\
 	zil.o			\
 	zio.o			\
@@ -1137,7 +1138,6 @@
 	zfs_acl.o		\
 	zfs_ctldir.o		\
 	zfs_dir.o		\
-	zfs_fuid.o		\
 	zfs_ioctl.o		\
 	zfs_log.o		\
 	zfs_replay.o		\
--- a/usr/src/uts/common/fs/zfs/sys/zfs_fuid.h	Fri Feb 01 10:11:12 2008 -0800
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_fuid.h	Fri Feb 01 12:13:54 2008 -0800
@@ -28,21 +28,17 @@
 
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
 
-#include <sys/isa_defs.h>
-#include <sys/types32.h>
 #ifdef _KERNEL
 #include <sys/kidmap.h>
 #include <sys/sid.h>
 #include <sys/dmu.h>
 #include <sys/zfs_vfsops.h>
 #endif
+#include <sys/avl.h>
 
-#ifdef _KERNEL
-typedef struct zfs_fuid_hdl {
-	idmap_get_handle_t	*z_hdl;
-	boolean_t		z_map_needed; /* is mapping required */
-	idmap_stat		z_status; /* needed for kidmap interface */
-} zfs_fuid_hdl_t;
+#ifdef	__cplusplus
+extern "C" {
+#endif
 
 typedef enum {
 	ZFS_OWNER,
@@ -51,8 +47,6 @@
 	ZFS_ACE_GROUP
 } zfs_fuid_type_t;
 
-#endif
-
 /*
  * Estimate space needed for one more fuid table entry.
  * for now assume its current size + 1K
@@ -107,29 +101,22 @@
 
 #ifdef _KERNEL
 struct znode;
-extern void zfs_fuid_map_id(zfsvfs_t *, uint64_t, cred_t *, zfs_fuid_type_t,
-    uid_t *);
+extern uid_t zfs_fuid_map_id(zfsvfs_t *, uint64_t, cred_t *, zfs_fuid_type_t);
 extern void zfs_fuid_destroy(zfsvfs_t *);
-extern uint64_t zfs_fuid_create_cred(zfsvfs_t *, uint64_t, zfs_fuid_type_t,
+extern uint64_t zfs_fuid_create_cred(zfsvfs_t *, zfs_fuid_type_t,
     dmu_tx_t *, cred_t *, zfs_fuid_info_t **);
 extern uint64_t zfs_fuid_create(zfsvfs_t *, uint64_t, cred_t *, zfs_fuid_type_t,
     dmu_tx_t *, zfs_fuid_info_t **);
-extern void zfs_fuid_queue_map_id(zfsvfs_t *zfsvfs, zfs_fuid_hdl_t *,
-    uint64_t, cred_t *, zfs_fuid_type_t, uid_t *);
 extern void zfs_fuid_map_ids(struct znode *zp, cred_t *cr, uid_t *uid,
     uid_t *gid);
-extern void zfs_fuid_get_mappings(zfs_fuid_hdl_t *);
-extern char *zfs_fuid_find_by_idx(zfsvfs_t *, uint64_t);
-int zfs_fuid_find_by_domain(zfsvfs_t *, const char *, char **, dmu_tx_t *);
 extern zfs_fuid_info_t *zfs_fuid_info_alloc(void);
 extern void zfs_fuid_info_free();
 extern boolean_t zfs_groupmember(zfsvfs_t *, uint64_t, cred_t *);
-
 #endif
 
-#ifdef	__cplusplus
-extern "C" {
-#endif
+char *zfs_fuid_idx_domain(avl_tree_t *, uint32_t);
+uint64_t zfs_fuid_table_load(objset_t *, uint64_t, avl_tree_t *, avl_tree_t *);
+void zfs_fuid_table_destroy(avl_tree_t *, avl_tree_t *);
 
 #ifdef	__cplusplus
 }
--- a/usr/src/uts/common/fs/zfs/zfs_acl.c	Fri Feb 01 10:11:12 2008 -0800
+++ b/usr/src/uts/common/fs/zfs/zfs_acl.c	Fri Feb 01 12:13:54 2008 -0800
@@ -545,8 +545,7 @@
 		if (entry_type != ACE_OWNER && entry_type != OWNING_GROUP &&
 		    entry_type != ACE_EVERYONE) {
 			if (!aclp->z_has_fuids)
-				aclp->z_has_fuids = IS_EPHEMERAL(acep->a_who) ?
-				    B_TRUE : B_FALSE;
+				aclp->z_has_fuids = IS_EPHEMERAL(acep->a_who);
 			aceptr->z_fuid = (uint64_t)acep->a_who;
 		}
 
@@ -599,7 +598,6 @@
 	ace_t *acep = datap;
 	ace_object_t *objacep;
 	zfs_object_ace_t *zobjacep;
-	zfs_fuid_hdl_t hdl = { 0 };
 	size_t ace_size;
 	uint16_t entry_type;
 
@@ -632,18 +630,18 @@
 		entry_type = (iflags & ACE_TYPE_FLAGS);
 		if ((entry_type != ACE_OWNER &&
 		    entry_type != (ACE_GROUP | ACE_IDENTIFIER_GROUP) &&
-		    entry_type != ACE_EVERYONE))
-			zfs_fuid_queue_map_id(zfsvfs, &hdl, who, cr,
-			    (entry_type & ACE_IDENTIFIER_GROUP) ?
-			    ZFS_ACE_GROUP : ZFS_ACE_USER, &acep->a_who);
-		else
+		    entry_type != ACE_EVERYONE)) {
+			acep->a_who = zfs_fuid_map_id(zfsvfs, who,
+			    cr, (entry_type & ACE_IDENTIFIER_GROUP) ?
+			    ZFS_ACE_GROUP : ZFS_ACE_USER);
+		} else {
 			acep->a_who = (uid_t)(int64_t)who;
+		}
 		acep->a_access_mask = access_mask;
 		acep->a_flags = iflags;
 		acep->a_type = type;
 		acep = (ace_t *)((caddr_t)acep + ace_size);
 	}
-	zfs_fuid_get_mappings(&hdl);
 }
 
 static int
@@ -897,8 +895,8 @@
 		if (entry_type == 0 || entry_type == ACE_IDENTIFIER_GROUP) {
 			aclp->z_ops.ace_who_set(acep,
 			    zfs_fuid_create(zp->z_zfsvfs, who, cr,
-			    entry_type == 0 ? ZFS_ACE_USER : ZFS_ACE_GROUP, tx,
-			    fuidp));
+			    (entry_type == 0) ? ZFS_ACE_USER : ZFS_ACE_GROUP,
+			    tx, fuidp));
 		}
 	}
 	return (mode);
@@ -1535,7 +1533,7 @@
 					reuse_deny = zfs_reuse_deny(aclp, acep,
 					    prevacep);
 
-					if (reuse_deny == B_FALSE) {
+					if (!reuse_deny) {
 						prevacep =
 						    zfs_acl_prepend_deny(zp,
 						    aclp, acep, mode);
@@ -1766,15 +1764,13 @@
     vattr_t *vap, dmu_tx_t *tx, cred_t *cr,
     zfs_acl_t *setaclp, zfs_fuid_info_t **fuidp)
 {
-	uint64_t	mode;
-	uint64_t	uid;
-	uint64_t	gid;
+	uint64_t	mode, fuid, fgid;
 	int		error;
-	int		pull_down;
 	zfsvfs_t	*zfsvfs = zp->z_zfsvfs;
 	zfs_acl_t	*aclp = NULL;
 	zfs_acl_t	*paclp;
 	xvattr_t	*xvap = (xvattr_t *)vap;
+	gid_t		gid;
 
 	if (setaclp)
 		aclp = setaclp;
@@ -1786,24 +1782,33 @@
 	 */
 	if ((flag & (IS_ROOT_NODE | IS_REPLAY)) ||
 	    ((flag & IS_XATTR) && (vap->va_type == VDIR))) {
-		uid = zfs_fuid_create(zfsvfs, vap->va_uid, cr,
+		fuid = zfs_fuid_create(zfsvfs, vap->va_uid, cr,
 		    ZFS_OWNER, tx, fuidp);
-		gid = zfs_fuid_create(zfsvfs, vap->va_gid, cr,
+		fgid = zfs_fuid_create(zfsvfs, vap->va_gid, cr,
 		    ZFS_GROUP, tx, fuidp);
+		gid = vap->va_gid;
 	} else {
-		uid = zfs_fuid_create_cred(zfsvfs, crgetuid(cr),
-		    ZFS_OWNER, tx, cr, fuidp);
-		if ((vap->va_mask & AT_GID) &&
-		    ((vap->va_gid == parent->z_phys->zp_gid) ||
-		    groupmember(vap->va_gid, cr) ||
-		    secpolicy_vnode_create_gid(cr) == 0)) {
-			gid = zfs_fuid_create_cred(zfsvfs, vap->va_gid,
-			    ZFS_GROUP, tx, cr, fuidp);
-		} else {
-			gid = (parent->z_phys->zp_mode & S_ISGID) ?
-			    parent->z_phys->zp_gid : crgetgid(cr);
-			gid = zfs_fuid_create_cred(zfsvfs, gid,
-			    ZFS_GROUP, tx, cr, fuidp);
+		fuid = zfs_fuid_create_cred(zfsvfs, ZFS_OWNER, tx, cr, fuidp);
+		fgid = 0;
+		if (vap->va_mask & AT_GID)  {
+			fgid = zfs_fuid_create(zfsvfs, vap->va_gid, cr,
+			    ZFS_GROUP, tx, fuidp);
+			gid = vap->va_gid;
+			if (fgid != parent->z_phys->zp_gid &&
+			    !groupmember(vap->va_gid, cr) &&
+			    secpolicy_vnode_create_gid(cr) != 0)
+				fgid = 0;
+		}
+		if (fgid == 0) {
+			if (parent->z_phys->zp_mode & S_ISGID) {
+				fgid = parent->z_phys->zp_gid;
+				gid = zfs_fuid_map_id(zfsvfs, fgid,
+				    cr, ZFS_GROUP);
+			} else {
+				fgid = zfs_fuid_create_cred(zfsvfs,
+				    ZFS_GROUP, tx, cr, fuidp);
+				gid = crgetgid(cr);
+			}
 		}
 	}
 
@@ -1814,22 +1819,21 @@
 	 * file's new group, clear the file's set-GID bit.
 	 */
 
-	if ((parent->z_phys->zp_mode & S_ISGID) && (vap->va_type == VDIR))
+	if ((parent->z_phys->zp_mode & S_ISGID) && (vap->va_type == VDIR)) {
 		mode |= S_ISGID;
-	else {
+	} else {
 		if ((mode & S_ISGID) &&
 		    secpolicy_vnode_setids_setgids(cr, gid) != 0)
 			mode &= ~S_ISGID;
 	}
 
-	zp->z_phys->zp_uid = uid;
-	zp->z_phys->zp_gid = gid;
+	zp->z_phys->zp_uid = fuid;
+	zp->z_phys->zp_gid = fgid;
 	zp->z_phys->zp_mode = mode;
 
 	if (aclp == NULL) {
 		mutex_enter(&parent->z_lock);
-		pull_down = (parent->z_phys->zp_flags & ZFS_INHERIT_ACE);
-		if (pull_down) {
+		if (parent->z_phys->zp_flags & ZFS_INHERIT_ACE) {
 			mutex_enter(&parent->z_acl_lock);
 			VERIFY(0 == zfs_acl_node_read(parent, &paclp, B_FALSE));
 			mutex_exit(&parent->z_acl_lock);
@@ -1861,9 +1865,8 @@
 	mutex_exit(&zp->z_acl_lock);
 	ASSERT3U(error, ==, 0);
 
-	if (aclp != setaclp) {
+	if (aclp != setaclp)
 		zfs_acl_free(aclp);
-	}
 }
 
 /*
@@ -2242,8 +2245,8 @@
 			if (entry_type == 0) {
 				uid_t newid;
 
-				zfs_fuid_map_id(zfsvfs, who, cr,
-				    ZFS_ACE_USER, &newid);
+				newid = zfs_fuid_map_id(zfsvfs, who, cr,
+				    ZFS_ACE_USER);
 				if (newid != IDMAP_WK_CREATOR_OWNER_UID &&
 				    uid == newid)
 					checkit = B_TRUE;
@@ -2341,7 +2344,7 @@
 		return (0);
 	}
 
-	if (error && check_privs == B_FALSE) {
+	if (error && !check_privs) {
 		if (is_attr)
 			VN_RELE(ZTOV(xzp));
 		return (error);
@@ -2355,8 +2358,8 @@
 		uid_t		owner;
 		mode_t		checkmode = 0;
 
-		zfs_fuid_map_id(zfsvfs, check_zp->z_phys->zp_uid, cr,
-		    ZFS_OWNER, &owner);
+		owner = zfs_fuid_map_id(zfsvfs, check_zp->z_phys->zp_uid, cr,
+		    ZFS_OWNER);
 
 		/*
 		 * First check for implicit owner permission on
@@ -2440,7 +2443,7 @@
 	uid_t downer;
 	zfsvfs_t *zfsvfs = zp->z_zfsvfs;
 
-	zfs_fuid_map_id(zfsvfs, dzp->z_phys->zp_uid, cr, ZFS_OWNER, &downer);
+	downer = zfs_fuid_map_id(zfsvfs, dzp->z_phys->zp_uid, cr, ZFS_OWNER);
 
 	error = secpolicy_vnode_access(cr, ZTOV(zp), downer, S_IWRITE|S_IEXEC);
 
@@ -2513,8 +2516,7 @@
 	zp_error = zfs_zaccess_common(zp, ACE_DELETE, &zp_working_mode,
 	    &zpcheck_privs, B_FALSE, cr);
 
-	if ((dzp_error && dzpcheck_privs == B_FALSE) ||
-	    (zp_error && zpcheck_privs == B_FALSE))
+	if ((dzp_error && !dzpcheck_privs) || (zp_error && !zpcheck_privs))
 		return (dzp_error);
 
 	/*
@@ -2557,7 +2559,7 @@
 	dzp_error = zfs_zaccess_common(dzp, ACE_WRITE_DATA|ACE_EXECUTE,
 	    &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr);
 
-	if (dzp_error && dzpcheck_privs == B_FALSE)
+	if (dzp_error && !dzpcheck_privs)
 		return (dzp_error);
 
 	if ((dzp_working_mode & (ACE_WRITE_DATA|ACE_EXECUTE)) == 0)
--- a/usr/src/uts/common/fs/zfs/zfs_dir.c	Fri Feb 01 10:11:12 2008 -0800
+++ b/usr/src/uts/common/fs/zfs/zfs_dir.c	Fri Feb 01 12:13:54 2008 -0800
@@ -956,8 +956,8 @@
 	if ((zdp->z_phys->zp_mode & S_ISVTX) == 0)
 		return (0);
 
-	zfs_fuid_map_id(zfsvfs, zdp->z_phys->zp_uid, cr, ZFS_OWNER, &downer);
-	zfs_fuid_map_id(zfsvfs, zp->z_phys->zp_uid, cr, ZFS_OWNER, &fowner);
+	downer = zfs_fuid_map_id(zfsvfs, zdp->z_phys->zp_uid, cr, ZFS_OWNER);
+	fowner = zfs_fuid_map_id(zfsvfs, zp->z_phys->zp_uid, cr, ZFS_OWNER);
 
 	if ((uid = crgetuid(cr)) == downer || uid == fowner ||
 	    (ZTOV(zp)->v_type == VREG &&
--- a/usr/src/uts/common/fs/zfs/zfs_fuid.c	Fri Feb 01 10:11:12 2008 -0800
+++ b/usr/src/uts/common/fs/zfs/zfs_fuid.c	Fri Feb 01 12:13:54 2008 -0800
@@ -25,20 +25,20 @@
 
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
 
-#include <sys/types.h>
-#include <sys/unistd.h>
-#include <sys/sysmacros.h>
+#include <sys/zfs_context.h>
 #include <sys/sunddi.h>
+#include <sys/dmu.h>
+#include <sys/avl.h>
+#include <sys/zap.h>
+#include <sys/refcount.h>
+#include <sys/nvpair.h>
+#ifdef _KERNEL
+#include <sys/kidmap.h>
+#include <sys/sid.h>
 #include <sys/zfs_vfsops.h>
 #include <sys/zfs_znode.h>
+#endif
 #include <sys/zfs_fuid.h>
-#include <sys/dmu.h>
-#include <sys/refcount.h>
-#include <sys/avl.h>
-#include <sys/zap.h>
-#include <sys/nvpair.h>
-#include <sys/kidmap.h>
-#include <sys/sid.h>
 
 /*
  * FUID Domain table(s).
@@ -59,26 +59,20 @@
 #define	FUID_NVP_ARRAY	"fuid_nvlist"
 
 typedef struct fuid_domain {
-	avl_node_t	f_node;
+	avl_node_t	f_domnode;
+	avl_node_t	f_idxnode;
 	ksiddomain_t	*f_ksid;
-	int		f_idx;
-	uint32_t	f_offset;
+	uint64_t	f_idx;
 } fuid_domain_t;
 
-typedef struct fuid_idx {
-	avl_node_t	f_node;
-	int		f_idx;
-	fuid_domain_t	*f_domain;
-} fuid_idx_t;
-
 /*
  * Compare two indexes.
  */
 static int
 idx_compare(const void *arg1, const void *arg2)
 {
-	const fuid_idx_t *node1 = arg1;
-	const fuid_idx_t *node2 = arg2;
+	const fuid_domain_t *node1 = arg1;
+	const fuid_domain_t *node2 = arg2;
 
 	if (node1->f_idx < node2->f_idx)
 		return (-1);
@@ -104,15 +98,100 @@
 }
 
 /*
+ * load initial fuid domain and idx trees.  This function is used by
+ * both the kernel and zdb.
+ */
+uint64_t
+zfs_fuid_table_load(objset_t *os, uint64_t fuid_obj, avl_tree_t *idx_tree,
+    avl_tree_t *domain_tree)
+{
+	dmu_buf_t *db;
+	uint64_t fuid_size;
+
+	avl_create(idx_tree, idx_compare,
+	    sizeof (fuid_domain_t), offsetof(fuid_domain_t, f_idxnode));
+	avl_create(domain_tree, domain_compare,
+	    sizeof (fuid_domain_t), offsetof(fuid_domain_t, f_domnode));
+
+	VERIFY(0 == dmu_bonus_hold(os, fuid_obj, FTAG, &db));
+	fuid_size = *(uint64_t *)db->db_data;
+	dmu_buf_rele(db, FTAG);
+
+	if (fuid_size)  {
+		nvlist_t **fuidnvp;
+		nvlist_t *nvp = NULL;
+		uint_t count;
+		char *packed;
+		int i;
+
+		packed = kmem_alloc(fuid_size, KM_SLEEP);
+		VERIFY(dmu_read(os, fuid_obj, 0, fuid_size, packed) == 0);
+		VERIFY(nvlist_unpack(packed, fuid_size,
+		    &nvp, 0) == 0);
+		VERIFY(nvlist_lookup_nvlist_array(nvp, FUID_NVP_ARRAY,
+		    &fuidnvp, &count) == 0);
+
+		for (i = 0; i != count; i++) {
+			fuid_domain_t *domnode;
+			char *domain;
+			uint64_t idx;
+
+			VERIFY(nvlist_lookup_string(fuidnvp[i], FUID_DOMAIN,
+			    &domain) == 0);
+			VERIFY(nvlist_lookup_uint64(fuidnvp[i], FUID_IDX,
+			    &idx) == 0);
+
+			domnode = kmem_alloc(sizeof (fuid_domain_t), KM_SLEEP);
+
+			domnode->f_idx = idx;
+			domnode->f_ksid = ksid_lookupdomain(domain);
+			avl_add(idx_tree, domnode);
+			avl_add(domain_tree, domnode);
+		}
+		nvlist_free(nvp);
+		kmem_free(packed, fuid_size);
+	}
+	return (fuid_size);
+}
+
+void
+zfs_fuid_table_destroy(avl_tree_t *idx_tree, avl_tree_t *domain_tree)
+{
+	fuid_domain_t *domnode;
+	void *cookie;
+
+	cookie = NULL;
+	while (domnode = avl_destroy_nodes(domain_tree, &cookie))
+		ksiddomain_rele(domnode->f_ksid);
+
+	avl_destroy(domain_tree);
+	cookie = NULL;
+	while (domnode = avl_destroy_nodes(idx_tree, &cookie))
+		kmem_free(domnode, sizeof (fuid_domain_t));
+	avl_destroy(idx_tree);
+}
+
+char *
+zfs_fuid_idx_domain(avl_tree_t *idx_tree, uint32_t idx)
+{
+	fuid_domain_t searchnode, *findnode;
+	avl_index_t loc;
+
+	searchnode.f_idx = idx;
+
+	findnode = avl_find(idx_tree, &searchnode, &loc);
+
+	return (findnode->f_ksid->kd_name);
+}
+
+#ifdef _KERNEL
+/*
  * Load the fuid table(s) into memory.
  */
 static void
 zfs_fuid_init(zfsvfs_t *zfsvfs, dmu_tx_t *tx)
 {
-	dmu_buf_t *db;
-	char *packed;
 	int error = 0;
-	int i;
 
 	rw_enter(&zfsvfs->z_fuid_lock, RW_WRITER);
 
@@ -137,70 +216,9 @@
 		}
 	}
 
-	avl_create(&zfsvfs->z_fuid_idx, idx_compare,
-	    sizeof (fuid_idx_t), offsetof(fuid_idx_t, f_node));
-	avl_create(&zfsvfs->z_fuid_domain, domain_compare,
-	    sizeof (fuid_domain_t), offsetof(fuid_domain_t, f_node));
-
-	if (zfsvfs->z_fuid_obj) {
-		VERIFY(0 == dmu_bonus_hold(zfsvfs->z_os, zfsvfs->z_fuid_obj,
-		    FTAG, &db));
-		zfsvfs->z_fuid_size = *(uint64_t *)db->db_data;
-		dmu_buf_rele(db, FTAG);
-	}
-
-	if (zfsvfs->z_fuid_size == 0)
-		goto initialized;
-
-	packed = kmem_alloc(zfsvfs->z_fuid_size, KM_SLEEP);
-	error = dmu_read(zfsvfs->z_os, zfsvfs->z_fuid_obj, 0,
-	    zfsvfs->z_fuid_size, packed);
-	if (error == 0)  {
-		nvlist_t **fuidnvp;
-		nvlist_t *nvp = NULL;
-		uint_t count;
-
-		VERIFY(nvlist_unpack(packed, zfsvfs->z_fuid_size,
-		    &nvp, 0) == 0);
-		VERIFY((error = nvlist_lookup_nvlist_array(nvp, FUID_NVP_ARRAY,
-		    &fuidnvp, &count)) == 0);
+	zfsvfs->z_fuid_size = zfs_fuid_table_load(zfsvfs->z_os,
+	    zfsvfs->z_fuid_obj, &zfsvfs->z_fuid_idx, &zfsvfs->z_fuid_domain);
 
-		for (i = 0; i != count; i++) {
-			fuid_idx_t *idxnode;
-			fuid_domain_t *domnode;
-			char *domain;
-			avl_index_t loc;
-			uint64_t idx, offset;
-
-			VERIFY(nvlist_lookup_string(fuidnvp[i], FUID_DOMAIN,
-			    &domain) == 0);
-			VERIFY(nvlist_lookup_uint64(fuidnvp[i], FUID_IDX,
-			    &idx) == 0);
-			VERIFY(nvlist_lookup_uint64(fuidnvp[i], FUID_OFFSET,
-			    &offset) == 0);
-
-			idxnode = kmem_alloc(sizeof (fuid_idx_t), KM_SLEEP);
-			domnode = kmem_alloc(sizeof (fuid_domain_t), KM_SLEEP);
-
-			domnode->f_idx = idxnode->f_idx = idx;
-			domnode->f_ksid = ksid_lookupdomain(domain);
-			idxnode->f_domain = domnode;
-			domnode->f_offset = offset;
-			if (avl_find(&zfsvfs->z_fuid_idx,
-			    idxnode, &loc) == NULL) {
-				avl_insert(&zfsvfs->z_fuid_idx, idxnode, loc);
-			}
-			if (avl_find(&zfsvfs->z_fuid_domain,
-			    domnode, &loc) == NULL) {
-				avl_insert(&zfsvfs->z_fuid_domain,
-				    domnode, loc);
-			}
-		}
-		nvlist_free(nvp);
-	}
-	kmem_free(packed, zfsvfs->z_fuid_size);
-
-initialized:
 	zfsvfs->z_fuid_loaded = B_TRUE;
 	rw_exit(&zfsvfs->z_fuid_lock);
 }
@@ -232,7 +250,7 @@
 	if (retdomain) {
 		*retdomain = searchnode.f_ksid->kd_name;
 	}
-	if (zfsvfs->z_fuid_loaded == B_FALSE)
+	if (!zfsvfs->z_fuid_loaded)
 		zfs_fuid_init(zfsvfs, tx);
 
 	rw_enter(&zfsvfs->z_fuid_lock, RW_READER);
@@ -244,7 +262,6 @@
 		return (findnode->f_idx);
 	} else {
 		fuid_domain_t *domnode;
-		fuid_idx_t *newidxnode;
 		nvlist_t *nvp;
 		nvlist_t **fuids;
 		uint64_t retidx;
@@ -255,17 +272,12 @@
 
 		domnode = kmem_alloc(sizeof (fuid_domain_t), KM_SLEEP);
 		domnode->f_ksid = searchnode.f_ksid;
-		domnode->f_offset = 0;
-
-		newidxnode = kmem_alloc(sizeof (fuid_idx_t), KM_SLEEP);
-		newidxnode->f_domain = domnode;
 
 		rw_enter(&zfsvfs->z_fuid_lock, RW_WRITER);
-		retidx = domnode->f_idx = newidxnode->f_idx =
-		    avl_numnodes(&zfsvfs->z_fuid_idx) + 1;
+		retidx = domnode->f_idx = avl_numnodes(&zfsvfs->z_fuid_idx) + 1;
 
 		avl_add(&zfsvfs->z_fuid_domain, domnode);
-		avl_add(&zfsvfs->z_fuid_idx, newidxnode);
+		avl_add(&zfsvfs->z_fuid_idx, domnode);
 		/*
 		 * Now resync the on-disk nvlist.
 		 */
@@ -278,8 +290,8 @@
 			    NV_UNIQUE_NAME, KM_SLEEP) == 0);
 			VERIFY(nvlist_add_uint64(fuids[i], FUID_IDX,
 			    domnode->f_idx) == 0);
-			VERIFY(nvlist_add_uint64(fuids[i], FUID_OFFSET,
-			    domnode->f_offset) == 0);
+			VERIFY(nvlist_add_uint64(fuids[i],
+			    FUID_OFFSET, 0) == 0);
 			VERIFY(nvlist_add_string(fuids[i++], FUID_DOMAIN,
 			    domnode->f_ksid->kd_name) == 0);
 			domnode = AVL_NEXT(&zfsvfs->z_fuid_domain, domnode);
@@ -315,119 +327,56 @@
  * Returns a pointer from an avl node of the domain string.
  *
  */
-char *
-zfs_fuid_find_by_idx(zfsvfs_t *zfsvfs, uint64_t idx)
+static char *
+zfs_fuid_find_by_idx(zfsvfs_t *zfsvfs, uint32_t idx)
 {
-	fuid_idx_t searchnode, *findnode;
-	avl_index_t loc;
+	char *domain;
 
-	if (idx == 0 || zfsvfs->z_use_fuids == B_FALSE)
+	if (idx == 0 || !zfsvfs->z_use_fuids)
 		return (NULL);
 
-	if (zfsvfs->z_fuid_loaded == B_FALSE)
+	if (!zfsvfs->z_fuid_loaded)
 		zfs_fuid_init(zfsvfs, NULL);
 
-	searchnode.f_idx = idx;
-
 	rw_enter(&zfsvfs->z_fuid_lock, RW_READER);
-	findnode = avl_find(&zfsvfs->z_fuid_idx, &searchnode, &loc);
+	domain = zfs_fuid_idx_domain(&zfsvfs->z_fuid_idx, idx);
 	rw_exit(&zfsvfs->z_fuid_lock);
 
-	ASSERT(findnode);
-	return (findnode->f_domain->f_ksid->kd_name);
+	ASSERT(domain);
+	return (domain);
 }
 
 void
-zfs_fuid_get_mappings(zfs_fuid_hdl_t *hdl)
+zfs_fuid_map_ids(znode_t *zp, cred_t *cr, uid_t *uidp, uid_t *gidp)
 {
-	VERIFY(hdl != NULL);
-	if (hdl->z_map_needed == B_FALSE)
-		return;
-
-	(void) kidmap_get_mappings(hdl->z_hdl);
-
-	kidmap_get_destroy(hdl->z_hdl);
-	hdl->z_hdl = NULL;
-	hdl->z_map_needed = B_FALSE;
+	*uidp = zfs_fuid_map_id(zp->z_zfsvfs, zp->z_phys->zp_uid,
+	    cr, ZFS_OWNER);
+	*gidp = zfs_fuid_map_id(zp->z_zfsvfs, zp->z_phys->zp_gid,
+	    cr, ZFS_GROUP);
 }
 
-void
-zfs_fuid_queue_map_id(zfsvfs_t *zfsvfs, zfs_fuid_hdl_t *hdl,
-    uint64_t fuid, cred_t *cr, zfs_fuid_type_t type, uid_t *id)
+uid_t
+zfs_fuid_map_id(zfsvfs_t *zfsvfs, uint64_t fuid,
+    cred_t *cr, zfs_fuid_type_t type)
 {
 	uint32_t index = FUID_INDEX(fuid);
 	char *domain;
-	int status;
-
-	VERIFY(hdl);
+	uid_t id;
 
-	if (index == 0 || zfsvfs->z_use_fuids == B_FALSE) {
-		*id = (uid_t)fuid;
-		return;
-	}
-
-	if (hdl->z_hdl == NULL) {
-		hdl->z_hdl = kidmap_get_create(crgetzone(cr));
-		hdl->z_map_needed = B_TRUE;
-	}
+	if (index == 0)
+		return (fuid);
 
 	domain = zfs_fuid_find_by_idx(zfsvfs, index);
 	ASSERT(domain != NULL);
 
-	if (type == ZFS_OWNER || type == ZFS_ACE_USER)
-		status = kidmap_batch_getuidbysid(hdl->z_hdl, domain,
-		    FUID_RID(fuid), id, &hdl->z_status);
-	else
-		status = kidmap_batch_getgidbysid(hdl->z_hdl, domain,
-		    FUID_RID(fuid), id, &hdl->z_status);
-	ASSERT(status == 0);
-}
-
-void
-zfs_fuid_map_ids(znode_t *zp, cred_t *cr, uid_t *uid, uid_t *gid)
-{
-	uint32_t uid_index = FUID_INDEX(zp->z_phys->zp_uid);
-	uint32_t gid_index = FUID_INDEX(zp->z_phys->zp_gid);
-
-	/* Favor the common case, neither will be ephemeral */
-	if (uid_index == 0 && gid_index == 0) {
-		*uid = zp->z_phys->zp_uid;
-		*gid = zp->z_phys->zp_gid;
-		return;
+	if (type == ZFS_OWNER || type == ZFS_ACE_USER) {
+		(void) kidmap_getuidbysid(crgetzone(cr), domain,
+		    FUID_RID(fuid), &id);
 	} else {
-		zfs_fuid_hdl_t hdl = { 0 };
-
-		zfs_fuid_queue_map_id(zp->z_zfsvfs, &hdl,
-		    zp->z_phys->zp_uid, cr, ZFS_OWNER, uid);
-
-		zfs_fuid_queue_map_id(zp->z_zfsvfs, &hdl,
-		    zp->z_phys->zp_gid, cr, ZFS_GROUP, gid);
-
-		zfs_fuid_get_mappings(&hdl);
+		(void) kidmap_getgidbysid(crgetzone(cr), domain,
+		    FUID_RID(fuid), &id);
 	}
-}
-
-void
-zfs_fuid_map_id(zfsvfs_t *zfsvfs, uint64_t fuid,
-    cred_t *cr, zfs_fuid_type_t type, uid_t *id)
-{
-	uint32_t index = FUID_INDEX(fuid);
-	char *domain;
-
-	if (index == 0) {
-		*id = (uid_t)fuid;
-		return;
-	}
-
-	domain = zfs_fuid_find_by_idx(zfsvfs, index);
-	ASSERT(domain != NULL);
-
-	if (type == ZFS_OWNER || type == ZFS_ACE_USER)
-		(void) kidmap_getuidbysid(crgetzone(cr), domain,
-		    FUID_RID(fuid), id);
-	else
-		(void) kidmap_getgidbysid(crgetzone(cr), domain,
-		    FUID_RID(fuid), id);
+	return (id);
 }
 
 /*
@@ -466,7 +415,7 @@
 		}
 	}
 
-	if (found == B_FALSE) {
+	if (!found) {
 		fuid_domain = kmem_alloc(sizeof (zfs_fuid_domain_t), KM_SLEEP);
 		fuid_domain->z_domain = domain;
 		fuid_domain->z_domidx = idx;
@@ -499,18 +448,24 @@
  * Create a file system FUID, based on information in the users cred
  */
 uint64_t
-zfs_fuid_create_cred(zfsvfs_t *zfsvfs, uint64_t id,
-    zfs_fuid_type_t type, dmu_tx_t *tx, cred_t *cr, zfs_fuid_info_t **fuidp)
+zfs_fuid_create_cred(zfsvfs_t *zfsvfs, zfs_fuid_type_t type,
+    dmu_tx_t *tx, cred_t *cr, zfs_fuid_info_t **fuidp)
 {
 	uint64_t	idx;
 	ksid_t		*ksid;
 	uint32_t	rid;
 	char 		*kdomain;
 	const char	*domain;
+	uid_t		id;
 
 	VERIFY(type == ZFS_OWNER || type == ZFS_GROUP);
 
-	if (zfsvfs->z_use_fuids == B_FALSE || !IS_EPHEMERAL(id))
+	if (type == ZFS_OWNER)
+		id = crgetuid(cr);
+	else
+		id = crgetgid(cr);
+
+	if (!zfsvfs->z_use_fuids || !IS_EPHEMERAL(id))
 		return ((uint64_t)id);
 
 	ksid = crgetsid(cr, (type == ZFS_OWNER) ? KSID_OWNER : KSID_GROUP);
@@ -555,8 +510,12 @@
 	/*
 	 * If POSIX ID, or entry is already a FUID then
 	 * just return the id
+	 *
+	 * We may also be handed an already FUID'ized id via
+	 * chmod.
 	 */
-	if (!IS_EPHEMERAL(id) || fuid_idx != 0)
+
+	if (!zfsvfs->z_use_fuids || !IS_EPHEMERAL(id) || fuid_idx != 0)
 		return (id);
 
 	if (is_replay) {
@@ -605,12 +564,11 @@
 			rid = UID_NOBODY;
 			domain = "";
 		}
-
 	}
 
 	idx = zfs_fuid_find_by_domain(zfsvfs, domain, &kdomain, tx);
 
-	if (is_replay == B_FALSE)
+	if (!is_replay)
 		zfs_fuid_node_add(fuidpp, kdomain, rid, idx, id, type);
 	else if (zfuid != NULL) {
 		list_remove(&fuidp->z_fuids, zfuid);
@@ -622,25 +580,12 @@
 void
 zfs_fuid_destroy(zfsvfs_t *zfsvfs)
 {
-	fuid_domain_t *domnode;
-	fuid_idx_t *idxnode;
-	void *cookie;
-
 	rw_enter(&zfsvfs->z_fuid_lock, RW_WRITER);
-	if (zfsvfs->z_fuid_loaded == B_FALSE) {
+	if (!zfsvfs->z_fuid_loaded) {
 		rw_exit(&zfsvfs->z_fuid_lock);
 		return;
 	}
-	cookie = NULL;
-	while (domnode = avl_destroy_nodes(&zfsvfs->z_fuid_domain, &cookie)) {
-		ksiddomain_rele(domnode->f_ksid);
-		kmem_free(domnode, sizeof (fuid_domain_t));
-	}
-	avl_destroy(&zfsvfs->z_fuid_domain);
-	cookie = NULL;
-	while (idxnode = avl_destroy_nodes(&zfsvfs->z_fuid_idx, &cookie))
-		kmem_free(idxnode, sizeof (fuid_idx_t));
-	avl_destroy(&zfsvfs->z_fuid_idx);
+	zfs_fuid_table_destroy(&zfsvfs->z_fuid_idx, &zfsvfs->z_fuid_domain);
 	rw_exit(&zfsvfs->z_fuid_lock);
 }
 
@@ -723,15 +668,13 @@
 				ASSERT(domain != NULL);
 
 				if (strcmp(domain,
-				    IDMAP_WK_CREATOR_SID_AUTHORITY) == 0) {
+				    IDMAP_WK_CREATOR_SID_AUTHORITY) == 0)
 					return (B_FALSE);
-				}
 
 				if ((strcmp(domain,
 				    ksid_groups[i].ks_domain->kd_name) == 0) &&
-				    rid == ksid_groups[i].ks_rid) {
+				    rid == ksid_groups[i].ks_rid)
 					return (B_TRUE);
-				}
 			}
 		}
 	}
@@ -739,6 +682,7 @@
 	/*
 	 * Not found in ksidlist, check posix groups
 	 */
-	zfs_fuid_map_id(zfsvfs, id, cr, ZFS_GROUP, &gid);
+	gid = zfs_fuid_map_id(zfsvfs, id, cr, ZFS_GROUP);
 	return (groupmember(gid, cr));
 }
+#endif
--- a/usr/src/uts/common/fs/zfs/zfs_vnops.c	Fri Feb 01 10:11:12 2008 -0800
+++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c	Fri Feb 01 12:13:54 2008 -0800
@@ -1219,7 +1219,8 @@
 
 		tx = dmu_tx_create(os);
 		dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT);
-		if (aclp && aclp->z_has_fuids) {
+		if ((aclp && aclp->z_has_fuids) || IS_EPHEMERAL(crgetuid(cr)) ||
+		    IS_EPHEMERAL(crgetgid(cr))) {
 			if (zfsvfs->z_fuid_obj == 0) {
 				dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT);
 				dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0,
@@ -1640,7 +1641,8 @@
 	tx = dmu_tx_create(zfsvfs->z_os);
 	dmu_tx_hold_zap(tx, dzp->z_id, TRUE, dirname);
 	dmu_tx_hold_zap(tx, DMU_NEW_OBJECT, FALSE, NULL);
-	if (aclp && aclp->z_has_fuids) {
+	if ((aclp && aclp->z_has_fuids) || IS_EPHEMERAL(crgetuid(cr)) ||
+	    IS_EPHEMERAL(crgetgid(cr))) {
 		if (zfsvfs->z_fuid_obj == 0) {
 			dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT);
 			dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0,
@@ -3420,7 +3422,7 @@
 		return (EPERM);
 	}
 
-	zfs_fuid_map_id(zfsvfs, szp->z_phys->zp_uid, cr, ZFS_OWNER, &owner);
+	owner = zfs_fuid_map_id(zfsvfs, szp->z_phys->zp_uid, cr, ZFS_OWNER);
 	if (owner != crgetuid(cr) &&
 	    secpolicy_basic_link(cr) != 0) {
 		ZFS_EXIT(zfsvfs);