
Common NFSv4 ACL definitions.


 fs/Kconfig               |    4 
 fs/Makefile              |    1 
 fs/nfs/Makefile          |    2 
 fs/nfs/idmap_syms.c      |   48 ++
 fs/nfs4acl/Makefile      |    3 
 fs/nfs4acl/acl.c         |  936 +++++++++++++++++++++++++++++++++++++++++++++++
 fs/nfs4acl/acl_map.c     |  123 ++++++
 fs/nfs4acl/acl_map.h     |   53 ++
 fs/nfs4acl/acl_syms.c    |   52 ++
 fs/nfsd/Makefile         |    3 
 fs/nfsd/nfs4idmap_syms.c |   45 ++
 include/linux/nfs4.h     |   59 ++
 include/linux/nfs4_acl.h |   58 ++
 13 files changed, 1381 insertions(+), 6 deletions(-)

diff -puN include/linux/nfs4.h~acl_common include/linux/nfs4.h
--- current/include/linux/nfs4.h~acl_common	Thu May 22 05:10:21 2003
+++ current-marius/include/linux/nfs4.h	Thu May 22 05:10:21 2003
@@ -39,10 +39,61 @@
 #define NFS4_SET_TO_SERVER_TIME	0
 #define NFS4_SET_TO_CLIENT_TIME	1
 
-#define NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE 0
-#define NFS4_ACE_ACCESS_DENIED_ACE_TYPE  1
-#define NFS4_ACE_SYSTEM_AUDIT_ACE_TYPE   2
-#define NFS4_ACE_SYSTEM_ALARM_ACE_TYPE   3
+#define ACL4_SUPPORT_ALLOW_ACL            0x00000001
+#define ACL4_SUPPORT_DENY_ACL             0x00000002
+#define ACL4_SUPPORT_AUDIT_ACL            0x00000004
+#define ACL4_SUPPORT_ALARM_ACL            0x00000008
+
+#define NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE      0x00000000
+#define NFS4_ACE_ACCESS_DENIED_ACE_TYPE       0x00000001
+#define NFS4_ACE_SYSTEM_AUDIT_ACE_TYPE        0x00000002
+#define NFS4_ACE_SYSTEM_ALARM_ACE_TYPE        0x00000003
+
+#define NFS4_ACE_FILE_INHERIT_ACE             0x00000001
+#define NFS4_ACE_DIRECTORY_INHERIT_ACE        0x00000002
+#define NFS4_ACE_NO_PROPAGATE_INHERIT_ACE     0x00000004
+#define NFS4_ACE_INHERIT_ONLY_ACE             0x00000008
+#define NFS4_ACE_SUCCESSFUL_ACCESS_ACE_FLAG   0x00000010
+#define NFS4_ACE_FAILED_ACCESS_ACE_FLAG       0x00000020
+#define NFS4_ACE_IDENTIFIER_GROUP             0x00000040
+#define NFS4_ACE_OWNER                        0x00000080
+#define NFS4_ACE_GROUP                        0x00000100
+#define NFS4_ACE_EVERYONE                     0x00000200
+
+#define NFS4_ACE_READ_DATA                    0x00000001
+#define NFS4_ACE_LIST_DIRECTORY               0x00000001
+#define NFS4_ACE_WRITE_DATA                   0x00000002
+#define NFS4_ACE_ADD_FILE                     0x00000002
+#define NFS4_ACE_APPEND_DATA                  0x00000004
+#define NFS4_ACE_ADD_SUBDIRECTORY             0x00000004
+#define NFS4_ACE_READ_NAMED_ATTRS             0x00000008
+#define NFS4_ACE_WRITE_NAMED_ATTRS            0x00000010
+#define NFS4_ACE_EXECUTE                      0x00000020
+#define NFS4_ACE_DELETE_CHILD                 0x00000040
+#define NFS4_ACE_READ_ATTRIBUTES              0x00000080
+#define NFS4_ACE_WRITE_ATTRIBUTES             0x00000100
+#define NFS4_ACE_DELETE                       0x00010000
+#define NFS4_ACE_READ_ACL                     0x00020000
+#define NFS4_ACE_WRITE_ACL                    0x00040000
+#define NFS4_ACE_WRITE_OWNER                  0x00080000
+#define NFS4_ACE_SYNCHRONIZE                  0x00100000
+#define NFS4_ACE_GENERIC_READ                 0x00120081
+#define NFS4_ACE_GENERIC_WRITE                0x00160106
+#define NFS4_ACE_GENERIC_EXECUTE              0x001200A0
+
+struct nfs4_ace {
+	u32               type;
+	u32               flag;
+	u32               access_mask;
+	char             *who;
+	u32               wholen;
+	struct list_head  l_ace;
+};
+
+struct nfs4_acl {
+	u32              naces;
+	struct list_head ace_head;
+};
 
 typedef char nfs4_verifier[NFS4_VERIFIER_SIZE];
 typedef char nfs4_stateid[16];
diff -puN /dev/null fs/nfs4acl/Makefile
--- /dev/null	Thu Aug 30 16:30:55 2001
+++ current-marius/fs/nfs4acl/Makefile	Thu May 22 05:10:21 2003
@@ -0,0 +1,3 @@
+obj-$(CONFIG_NFS_V4_ACL) += nfs4acl.o
+
+nfs4acl-objs := acl.o acl_syms.o acl_map.o
diff -puN fs/Kconfig~acl_common fs/Kconfig
--- current/fs/Kconfig~acl_common	Thu May 22 05:10:21 2003
+++ current-marius/fs/Kconfig	Thu May 22 05:10:21 2003
@@ -1353,6 +1353,10 @@ config LOCKD_V4
 	depends on NFSD_V3 || NFS_V3
 	default y
 
+config NFS_V4_ACL
+	tristate "Provide NFSv4 ACL support"
+	depends on NFSD_V4 || NFS_V4
+
 config EXPORTFS
 	tristate
 	default NFSD
diff -puN fs/Makefile~acl_common fs/Makefile
--- current/fs/Makefile~acl_common	Thu May 22 05:10:21 2003
+++ current-marius/fs/Makefile	Thu May 22 05:10:21 2003
@@ -69,6 +69,7 @@ obj-$(CONFIG_NFS_FS)		+= nfs/
 obj-$(CONFIG_EXPORTFS)		+= exportfs/
 obj-$(CONFIG_NFSD)		+= nfsd/
 obj-$(CONFIG_LOCKD)		+= lockd/
+obj-$(CONFIG_NFS_V4_ACL)        += nfs4acl/
 obj-$(CONFIG_NLS)		+= nls/
 obj-$(CONFIG_SYSV_FS)		+= sysv/
 obj-$(CONFIG_SMB_FS)		+= smbfs/
diff -puN /dev/null fs/nfs4acl/acl.c
--- /dev/null	Thu Aug 30 16:30:55 2001
+++ current-marius/fs/nfs4acl/acl.c	Mon Jun  2 18:00:56 2003
@@ -0,0 +1,936 @@
+/*
+ *  fs/nfs4acl/acl.c
+ *
+ *  Common NFSv4 ACL handling code.
+ *
+ *  Copyright (c) 2002, 2003 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Marius Aamodt Eriksen <marius@umich.edu>
+ *  Jeff Sedlak <jsedlak@umich.edu>
+ * 
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the University nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/nfs_fs.h>
+#include <linux/posix_acl.h>
+#include <linux/nfs4.h>
+#include <linux/nfs4_acl.h>
+
+#include "acl_map.h"
+
+#define ACETYPE_OWNER     0x01
+#define ACETYPE_GROUP     0x02
+#define ACETYPE_EVERYONE  0x04
+#define ACETYPE_OGROUP    0x08
+#define ACETYPE_OUSER     0x10
+#define ACETYPE_OGROUP1   0x20
+#define ACETYPE_OGROUP2   0x40
+#define ACETYPE_OGROUP3   0x80
+
+/* #define ACL_DEBUG */
+
+#ifdef ACL_DEBUG
+#define DPRINTK(fmt, arg...) printk(fmt, ##arg)
+#define ON_DEBUG(x) x
+#else
+#define DPRINTK(...)
+#define ON_DEBUG
+#endif /* ACL_DEBUG */
+
+#define SET_MASK_FROM_POSIX(perm, mask) do {		\
+        mask = 0;					\
+        if (perm & ACL_READ)				\
+                mask |= NFS4_ACE_GENERIC_READ;		\
+        if (perm & ACL_WRITE)				\
+                mask |= NFS4_ACE_GENERIC_WRITE;		\
+        if (perm & ACL_EXECUTE)				\
+                mask |= NFS4_ACE_GENERIC_EXECUTE;	\
+} while (0)
+
+#define SET_MODE_FROM_NFS4(perm, mode) do {				   \
+        mode = 0;							   \
+        if ((perm & NFS4_ACE_GENERIC_READ) == NFS4_ACE_GENERIC_READ)	   \
+                mode |= ACL_READ;					   \
+        if ((perm & NFS4_ACE_GENERIC_WRITE) == NFS4_ACE_GENERIC_WRITE)	   \
+                mode |= ACL_WRITE;					   \
+        if ((perm & NFS4_ACE_GENERIC_EXECUTE) == NFS4_ACE_GENERIC_EXECUTE) \
+                mode |= ACL_EXECUTE;					   \
+} while (0)
+
+struct ace_container {
+	struct nfs4_ace  *ace;
+	struct list_head  ace_l;
+};
+
+static void              nfs4_acl_print_ace(struct nfs4_ace *);
+static void              nfs4_posix_acl_print(struct posix_acl *);
+static int               ace2type(struct nfs4_ace *);
+static int               _posix_to_nfsv4_one(struct inode *, struct posix_acl *,
+                             struct nfs4_acl *, int);
+static struct posix_acl *_nfsv4_to_posix_one(struct inode *,
+                             struct nfs4_acl *);
+
+struct nfs4_acl *
+nfs4_acl_posix_to_nfsv4(struct inode *inode, struct posix_acl *pacl,
+    struct posix_acl *dpacl)
+{
+	struct nfs4_acl *acl;
+	int error = -EINVAL;
+
+	if ((pacl != NULL &&
+		(posix_acl_valid(pacl) < 0 || pacl->a_count == 0)) ||
+	    (dpacl != NULL &&
+		(posix_acl_valid(dpacl) < 0 || dpacl->a_count == 0)))
+		goto out_err;
+
+	acl = nfs4_acl_new();
+	if (acl == NULL) {
+		error = -ENOMEM;
+		goto out_err;
+	}
+
+	if (pacl != NULL) {
+		error = _posix_to_nfsv4_one(inode, pacl, acl, 0);
+		if (error < 0)
+			goto out_acl;
+	}
+
+	if (dpacl != NULL) {
+		error = _posix_to_nfsv4_one(inode, dpacl, acl,
+		    NFS4_ACE_FILE_INHERIT_ACE |
+		    NFS4_ACE_DIRECTORY_INHERIT_ACE |		    
+		    NFS4_ACE_INHERIT_ONLY_ACE);
+		if (error < 0)
+			goto out_acl;
+	}
+
+	DPRINTK("NFS%s encoded ACL:\n", inode == NULL ? "d" : "");
+	ON_DEBUG(nfs4_acl_print(acl));
+
+	return (acl);
+
+ out_acl:
+	nfs4_acl_free(acl);
+ out_err:
+	acl = ERR_PTR(error);
+
+	return (acl);
+}
+
+#define ADD_MASK_ACL(acl, mask, owner, ownerlen, flag, error, out) do {	\
+	error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE,	\
+	    flag,  mask_mask, owner, ownerlen);				\
+	if (error < 0)							\
+		goto out;						\
+} while (0)
+
+static int
+_posix_to_nfsv4_one(struct inode *inode, struct posix_acl *pacl,
+    struct nfs4_acl *acl, int eflag)
+{
+	struct posix_acl_entry *pa, *pe, *user_owner_entry = NULL,
+	    *group_owner_entry = NULL, *mask_entry = NULL;
+	int error = -EINVAL;
+	u32 mask, mask_mask; 
+	char xname[NFS4_ACL_MAP_MAXNAMELEN];
+	int xnamelen;
+
+	FOREACH_ACL_ENTRY(pa, pacl, pe)
+	    switch (pa->e_tag) {
+	    case ACL_USER_OBJ:
+		    user_owner_entry = pa;
+		    break;
+	    case ACL_GROUP_OBJ:
+		    group_owner_entry = pa;
+		    break;
+	    case ACL_MASK:
+		    mask_entry = pa;
+		    break;
+	    default:
+		    break;
+	    }
+
+	if (mask_entry != NULL) {
+		SET_MASK_FROM_POSIX(mask_entry->e_perm, mask_mask);
+		mask_mask = ~mask_mask;
+	} else
+		mask_mask = 0;
+
+	if (user_owner_entry != NULL) {
+		SET_MASK_FROM_POSIX(user_owner_entry->e_perm, mask);
+		error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE,
+		    eflag, mask, "OWNER@", sizeof("OWNER@") - 1);
+		if (error < 0)
+			goto out;
+
+		error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE,
+		    eflag, ~mask, "OWNER@", sizeof("OWNER@") - 1);
+		if (error < 0)
+			goto out;
+	}
+
+	/* First all user ACEs */
+	FOREACH_ACL_ENTRY(pa, pacl, pe) {
+		if (pa->e_tag != ACL_USER)
+			continue;
+
+		SET_MASK_FROM_POSIX(pa->e_perm, mask);
+		xnamelen = sizeof(xname);
+		error = nfs4_acl_map_id2name(inode, NFS4_ACL_MAP_USER,
+		    xname, &xnamelen, pa->e_id);
+		if (error < 0)
+			goto out;
+
+		ADD_MASK_ACL(acl, mask_mask,
+		    xname, xnamelen, eflag, error, out);
+
+		error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE,
+		    eflag, mask, xname, xnamelen);
+		if (error < 0)
+			goto out;
+
+		error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE,
+		    eflag, ~mask, xname, xnamelen);
+		if (error < 0)
+			goto out;
+	}
+
+	/*
+	 * Here, we apply positive ACEs first, then negative ACEs,
+	 * since a user can be in more than one group.
+	 */
+
+	/*
+	 * Positive ACEs
+	 */
+
+	if (group_owner_entry != NULL) {
+		SET_MASK_FROM_POSIX(group_owner_entry->e_perm, mask);
+		error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE,
+		    eflag, mask,
+		    "GROUP@", sizeof("GROUP@") - 1);
+		if (error < 0)
+			goto out;
+	}
+
+	FOREACH_ACL_ENTRY(pa, pacl, pe) {
+		if (pa->e_tag != ACL_GROUP)
+			continue;
+
+		SET_MASK_FROM_POSIX(pa->e_perm, mask);
+		xnamelen = sizeof(xname);
+		error = nfs4_acl_map_id2name(inode, NFS4_ACL_MAP_GROUP,
+		    xname, &xnamelen, pa->e_id);
+		if (error < 0)
+			goto out;
+
+		ADD_MASK_ACL(acl, mask_mask,
+		    xname, xnamelen, NFS4_ACE_IDENTIFIER_GROUP | eflag,
+		    error, out);
+
+		error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE,
+		    NFS4_ACE_IDENTIFIER_GROUP | eflag, mask, xname, xnamelen);
+		if (error < 0)
+			goto out;
+	}
+
+	/*
+	 * Negative ACEs
+	 */
+
+	if (group_owner_entry != NULL) {
+		SET_MASK_FROM_POSIX(group_owner_entry->e_perm, mask);
+		error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE,
+		    eflag, ~mask, "GROUP@", sizeof("GROUP@") - 1);
+		if (error < 0)
+			goto out;
+	}
+
+	FOREACH_ACL_ENTRY(pa, pacl, pe) {
+		if (pa->e_tag != ACL_GROUP)
+			continue;
+
+		SET_MASK_FROM_POSIX(pa->e_perm, mask);
+		xnamelen = sizeof(xname);
+		error = nfs4_acl_map_id2name(inode, NFS4_ACL_MAP_GROUP,
+		    xname, &xnamelen, pa->e_id);
+		if (error < 0)
+			goto out;
+
+		error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE,
+		    NFS4_ACE_IDENTIFIER_GROUP | eflag, ~mask, xname, xnamelen);
+		if (error < 0)
+			goto out;
+	}
+
+	/* EVERYONE@ ace*/
+	FOREACH_ACL_ENTRY(pa, pacl, pe)
+		if (pa->e_tag == ACL_OTHER)
+			break;
+
+	if (pa < pe) {
+		SET_MASK_FROM_POSIX(pa->e_perm, mask);
+		error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE,
+		    eflag, mask, "EVERYONE@", sizeof("EVERYONE@") - 1);
+		if (error < 0)
+			goto out;
+		error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE,
+		    eflag, ~mask, "EVERYONE@", sizeof("EVERYONE@") - 1);
+	}
+
+ out:
+	return (error);
+}
+
+#define ASSIGN_ACE(ace, pace, mask, tag, error, out, inode) do {	     \
+	int mode, map = NFS4_ACL_MAP_USER;				     \
+									     \
+	if (tag == ACL_GROUP_OBJ || tag == ACL_GROUP)			     \
+		map = NFS4_ACL_MAP_GROUP;				     \
+									     \
+	SET_MODE_FROM_NFS4((ace)->access_mask, mode);			     \
+	(pace)->e_tag = tag;						     \
+	(pace)->e_perm = mode;						     \
+	(mask) |= mode;							     \
+        if (tag == ACL_USER_OBJ || tag == ACL_GROUP_OBJ || tag == ACL_OTHER) \
+		break;							     \
+	(error) = nfs4_acl_map_name2id((inode), map,			     \
+	    (ace)->who, (ace)->wholen, &(pace)->e_id);			     \
+	if ((error) < 0)						     \
+		goto out;						     \
+} while (0)
+
+#define NEXT_ACE(p, ace, head, error, out) do {				\
+	p = p->next; prefetch(p->next);					\
+	if (p == head) {						\
+		error = -EINVAL;					\
+		goto out;						\
+	}								\
+	ace = list_entry(p, struct nfs4_ace, l_ace);			\
+} while (0)
+
+int
+nfs4_acl_nfsv4_to_posix(struct inode *inode, struct nfs4_acl *acl,
+    struct posix_acl **pacl, struct posix_acl **dpacl)
+{
+	struct nfs4_acl *dacl;
+	int error = -ENOMEM;
+
+	dacl = nfs4_acl_new();
+	if (dacl == NULL)
+		goto out;
+
+	error = nfs4_acl_split(acl, dacl);
+	if (error < 0)
+		goto out_acl;
+
+	if (pacl != NULL) {
+		if (acl->naces == 0) {
+			error = -ENODATA;
+			*pacl = NULL;
+			goto try_dpacl;
+		}
+
+		*pacl = _nfsv4_to_posix_one(inode, acl);
+		if (IS_ERR(*pacl)) {
+			error = PTR_ERR(*pacl);
+			goto out_acl;
+		}
+	}
+
+ try_dpacl:
+	if (dpacl != NULL) {
+		if (dacl->naces == 0) {
+			if (pacl == NULL || (pacl != NULL && *pacl == NULL))
+				error = -ENODATA;
+			*dpacl = NULL;
+			goto out_acl;
+		}
+
+		error = 0;
+		*dpacl = _nfsv4_to_posix_one(inode, dacl);
+		if (IS_ERR(*dpacl)) {
+			error = PTR_ERR(*dpacl);
+			goto out_acl;
+		}
+	}
+
+ out_acl:
+	nfs4_acl_free(dacl);
+ out:
+	return (error);
+}
+
+static struct posix_acl *
+_nfsv4_to_posix_one(struct inode *inode, struct nfs4_acl *n4acl)
+{
+	struct posix_acl *acl;
+	int error = -EINVAL, nace = 0, i, nmask = 0, mask_wholen, deny_wholen;
+	struct list_head *p, group_l;
+	struct nfs4_ace *ace, *_ace, *user_owner_ace, *group_owner_ace, *mask_ace;
+	u32 mask = 0, mode;
+	struct posix_acl_entry *pace;
+	struct ace_container *ac;
+	int state = ACETYPE_OWNER, type, access_mask, flag, mask_flag;
+	char *mask_who, *deny_who;
+
+	user_owner_ace = group_owner_ace = mask_ace = NULL;
+
+	nace = n4acl->naces;
+
+	list_for_each(p, &n4acl->ace_head) {
+		ace = list_entry(p, struct nfs4_ace, l_ace);
+
+		type = ace2type(ace);
+		switch (type) {
+		case ACETYPE_OUSER:
+		case ACETYPE_OGROUP:
+			nmask++;
+			break;
+		default:
+			break;
+		}
+	}
+
+	if (nmask % 3 != 0)
+		goto out_err;
+
+	nmask /= 3; 
+	nace -= nmask;
+
+	if (nace % 2 != 0)
+		goto out_err;
+
+	nace /= 2;
+	nace++;		/* ACL_MASK */
+
+	if ((acl = posix_acl_alloc(nace, GFP_KERNEL)) == NULL) {
+		error = -ENOMEM;
+		goto out_err;
+	}
+
+	i = 0;
+	INIT_LIST_HEAD(&group_l);
+	list_for_each(p, &n4acl->ace_head) {
+		ace = list_entry(p, struct nfs4_ace, l_ace);
+		pace = &acl->a_entries[i++];
+		error = -EINVAL;
+
+		DPRINTK("MARIUS: mapping entry %d\n", i - 1);
+		ON_DEBUG(nfs4_acl_print_ace(ace));
+
+		type = ace2type(ace);
+		switch (type) {
+		case ACETYPE_OWNER:
+			if (state != ACETYPE_OWNER) {
+				DPRINTK("MARIUS: state != ACETYPE_OWNER\n");
+				goto out_acl;
+			}
+
+			if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE)
+				goto out_acl;
+
+			/* obviously, also make sure this is an allowed type. */
+
+			access_mask = ace->access_mask;
+			flag = ace->flag;
+			deny_who = ace->who;
+			deny_wholen = ace->wholen;
+			ASSIGN_ACE(ace, pace, mask, ACL_USER_OBJ,
+			    error, out_acl, inode);
+			NEXT_ACE(p, ace, &n4acl->ace_head, error, out_acl);
+
+			if (ace->access_mask != ~access_mask ||
+			    ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE ||
+			    ace->flag != flag ||
+			    ace->wholen != deny_wholen ||
+			    memcmp(ace->who, deny_who, deny_wholen) != 0)
+				goto out_acl;
+			state = ACETYPE_OUSER;
+			break;
+		case ACETYPE_OUSER:
+			if (state != ACETYPE_OUSER) {
+				DPRINTK("MARIUS: state != ACETYPE_OUSER\n");
+				goto out_acl;
+			}
+
+			if (mask_ace == NULL) 
+				mask_ace = ace;
+
+			if (ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE ||
+			    ace->access_mask != mask_ace->access_mask)
+				goto out_acl;
+
+			mask_who = ace->who;
+			mask_wholen = ace->wholen;
+			mask_flag = ace->flag;
+			NEXT_ACE(p, ace, &n4acl->ace_head, error, out_acl);
+
+			if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE)
+				goto out_acl;
+
+			access_mask = ace->access_mask;
+			flag = ace->flag;
+			deny_who = ace->who;
+			deny_wholen = ace->wholen;
+			ASSIGN_ACE(ace, pace, mask, ACL_USER,
+			    error, out_acl, inode);
+			NEXT_ACE(p, ace, &n4acl->ace_head, error, out_acl);
+			if (ace->access_mask != ~access_mask ||
+			    ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE ||
+			    ace->flag != flag ||
+			    mask_flag != flag ||
+			    ace->wholen != deny_wholen ||
+			    memcmp(ace->who, deny_who, deny_wholen) != 0 ||
+			    ace->wholen != mask_wholen ||
+			    memcmp(ace->who, mask_who, mask_wholen) != 0)
+				goto out_acl;
+			break;
+		case ACETYPE_GROUP:
+			if (state == ACETYPE_OGROUP)
+				state = ACETYPE_OGROUP3;
+
+			if (state == ACETYPE_OUSER) {
+				ac = kmalloc(sizeof(*ac), GFP_KERNEL);
+				if (ac == NULL) {
+					error = -ENOMEM;
+					goto out_acl;
+				}
+				ac->ace = ace;
+				list_add_tail(&ac->ace_l, &group_l);
+
+				if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE)
+					goto out_acl;
+
+				ASSIGN_ACE(ace, pace, mask, ACL_GROUP_OBJ,
+				    error, out_acl, inode);
+
+				state = ACETYPE_OGROUP;
+			} else if (state == ACETYPE_OGROUP1 ||
+			    state == ACETYPE_OGROUP3) {
+				ac = list_entry(group_l.next,
+				    struct ace_container, ace_l);
+				_ace = ac->ace;
+
+				DPRINTK("MARIUS: processing _ACE: \n");
+				ON_DEBUG(nfs4_acl_print_ace(_ace));
+
+				if (ace->access_mask != ~_ace->access_mask ||
+				    ace->type !=
+				    NFS4_ACE_ACCESS_DENIED_ACE_TYPE ||
+				    ace->flag != _ace->flag ||
+				    ace->wholen != _ace->wholen ||
+				    memcmp(ace->who,
+					_ace->who, _ace->wholen) != 0)
+					goto out_acl;
+
+				list_del(group_l.next);
+				kfree(ac);
+
+				if (state == ACETYPE_OGROUP3 &&
+				    !list_empty(&group_l))
+					goto out_acl;
+
+				state = list_empty(&group_l) ?
+				    ACETYPE_EVERYONE : ACETYPE_OGROUP2;
+				i--;
+			} else {
+				DPRINTK("MARIUS: bad state in ACETYPE_GROUP "
+				    "(%d)\n", state);
+				goto out_acl;
+			}
+			break;
+		case ACETYPE_OGROUP:
+			if (state == ACETYPE_OGROUP ||
+			    state == ACETYPE_OGROUP1) {
+				if (mask_ace == NULL)
+					mask_ace = ace;
+
+				mask_who = ace->who;
+				mask_wholen = ace->wholen;
+
+				if (ace->type !=
+				    NFS4_ACE_ACCESS_DENIED_ACE_TYPE ||
+				    ace->access_mask != mask_ace->access_mask)
+					goto out_acl;
+
+				NEXT_ACE(p, ace, &n4acl->ace_head, error,
+				    out_acl);
+
+				ac = kmalloc(sizeof(*ac), GFP_KERNEL);
+				if (ac == NULL) {
+					error = -ENOMEM;
+					goto out_acl;
+				}
+
+				if (ace->type !=
+				    NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE ||
+				    ace->wholen != mask_wholen ||
+				    memcmp(ace->who,
+					mask_who, mask_wholen) != 0)
+					goto out_acl;
+
+				ac->ace = ace;
+				list_add_tail(&ac->ace_l, &group_l);
+
+				ASSIGN_ACE(ace, pace, mask, ACL_GROUP,
+				    error, out_acl, inode);
+
+				state = ACETYPE_OGROUP1;
+			} else if (state == ACETYPE_OGROUP2) {
+				ac = list_entry(group_l.next,
+				    struct ace_container, ace_l);
+				_ace = ac->ace;
+
+				if (ace->access_mask != ~_ace->access_mask ||
+				    ace->type !=
+				    NFS4_ACE_ACCESS_DENIED_ACE_TYPE ||
+				    ace->flag != _ace->flag ||
+				    ace->wholen != _ace->wholen ||
+				    memcmp(ace->who,
+					_ace->who, _ace->wholen) != 0)
+					goto out_acl;
+
+				list_del(group_l.next);
+				kfree(ac);
+
+				if (list_empty(&group_l))
+					state = ACETYPE_EVERYONE;
+				i--;
+			} else {
+				DPRINTK("MARIUS: bad state in "
+				    "ACETYPE_OGROUP (%d)\n", state);
+				goto out_acl;
+			}
+
+			break;
+		case ACETYPE_EVERYONE:
+			/* XXX jump over OGROUP */
+			if (state != ACETYPE_EVERYONE &&
+			    state != ACETYPE_OGROUP) {
+				DPRINTK("MARIUS: bad state in "
+				    "ACETYPE_EVERYONE (%d)\n", state);
+				goto out_acl;
+			}
+
+			/* First, the ACL_MASK */
+			pace->e_tag = ACL_MASK;
+			if (mask_ace != NULL)
+				SET_MODE_FROM_NFS4(~mask_ace->access_mask,
+				    pace->e_perm);
+			else
+				SET_MODE_FROM_NFS4(0xFFFFFFFF, pace->e_perm);
+			pace = &acl->a_entries[i++];
+
+			if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE)
+				goto out_acl;
+
+			access_mask = ace->access_mask;
+			flag = ace->flag;
+			deny_who = ace->who;
+			deny_wholen = ace->wholen;
+
+			SET_MODE_FROM_NFS4(ace->access_mask, mode);
+			ASSIGN_ACE(ace, pace, mask, ACL_OTHER,
+			    error, out_acl, inode);
+
+			NEXT_ACE(p, ace, &n4acl->ace_head, error, out_acl);
+
+			if (ace->access_mask != ~access_mask ||
+			    ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE ||
+			    ace->flag != flag ||
+			    ace->wholen != deny_wholen ||
+			    memcmp(ace->who, deny_who, deny_wholen) != 0)
+				goto out_acl;
+
+			state = 0;
+
+			DPRINTK("MARIUS: (ACL#) %d == (nace) %d\n", i, nace);
+		}
+	}
+
+	if (!list_empty(&group_l) || state != 0) {
+		error = -EINVAL;
+		goto out_acl;
+	}
+
+	DPRINTK("MARIUS: SUCCESSFUL mapping\n");
+	ON_DEBUG(nfs4_posix_acl_print(acl));
+
+	return (acl);
+
+ out_acl:
+	while (!list_empty(&group_l)) {
+		ac = list_entry(group_l.next, struct ace_container, ace_l);
+		list_del(group_l.next);
+		kfree(ac);
+	}
+
+
+	DPRINTK("FAILED mapping\n");
+	ON_DEBUG(nfs4_posix_acl_print(acl));
+
+	posix_acl_release(acl);
+ out_err:
+	acl = ERR_PTR(error);
+
+	return (acl);
+}
+
+
+struct nfs4_acl *
+nfs4_acl_new(void)
+{
+	struct nfs4_acl *acl;
+
+	if ((acl = kmalloc(sizeof(*acl), GFP_KERNEL)) == NULL)
+		return (NULL);
+
+	acl->naces = 0;
+	INIT_LIST_HEAD(&acl->ace_head);
+
+	return (acl);
+}
+
+struct nfs4_acl *
+nfs4_acl_free(struct nfs4_acl *acl)
+{
+	struct list_head *h;
+	struct nfs4_ace *ace;
+
+	while (!list_empty(&acl->ace_head)) {
+		h = acl->ace_head.next;
+		list_del(h);
+		ace = list_entry(h, struct nfs4_ace, l_ace);
+		if (ace->who != NULL)
+			kfree(ace->who);
+		kfree(ace);
+	}
+
+	kfree(acl);
+
+	return (NULL);
+}
+
+int
+nfs4_acl_add_ace(struct nfs4_acl *acl, u32 type, u32 flag, u32 access_mask,
+    char *who, u32 wholen)
+{
+	struct nfs4_ace *ace;
+
+	if ((ace = kmalloc(sizeof(*ace), GFP_KERNEL)) == NULL)
+		return (-1);
+
+	ace->type = type;
+	ace->flag = flag;
+	ace->access_mask = access_mask;
+	if (wholen > 0) {
+		if ((ace->who = kmalloc(wholen, GFP_KERNEL)) == NULL)
+			goto fail;
+		memcpy(ace->who, who, wholen);
+	}
+	ace->wholen = wholen;
+
+	list_add_tail(&ace->l_ace, &acl->ace_head);
+
+	return (++acl->naces);
+
+ fail:
+	kfree(ace);
+	return (-1);
+}
+    
+
+int
+nfs4_acl_merge(struct nfs4_acl *fromacl, struct nfs4_acl *withacl)
+{
+	struct nfs4_ace *ace;
+	struct list_head *h;
+
+	if (fromacl == NULL || withacl == NULL)
+		return (0);
+
+	while (!list_empty(&fromacl->ace_head)) {
+		h = fromacl->ace_head.next;
+		list_del(h);
+		ace = list_entry(h, struct nfs4_ace, l_ace);
+		/* XXX */
+		ace->flag |= NFS4_ACE_FILE_INHERIT_ACE |
+		    NFS4_ACE_DIRECTORY_INHERIT_ACE | NFS4_ACE_INHERIT_ONLY_ACE;
+		list_add_tail(&ace->l_ace, &withacl->ace_head);
+		withacl->naces++;
+	}
+
+	return (0);
+}
+
+int
+nfs4_acl_split(struct nfs4_acl *acl, struct nfs4_acl *dacl)
+{
+	struct list_head *h, *n;
+	struct nfs4_ace *ace;
+	int error = 0;
+
+	list_for_each_safe(h, n, &acl->ace_head) {
+		ace = list_entry(h, struct nfs4_ace, l_ace);
+
+		if (!(ace->flag & NFS4_ACE_DIRECTORY_INHERIT_ACE &&
+			ace->flag & NFS4_ACE_FILE_INHERIT_ACE &&
+			ace->flag & NFS4_ACE_INHERIT_ONLY_ACE))
+			continue;
+
+		error = nfs4_acl_add_ace(dacl, ace->type, ace->flag,
+		    ace->access_mask, ace->who, ace->wholen) == -1;
+		if (error < 0)
+			goto out;
+
+		list_del(h);
+		if (ace->who != NULL)
+			kfree(ace->who);
+		kfree(ace);
+		acl->naces--;
+	}
+
+ out:
+	return (error);
+}
+
+void
+nfs4_acl_print(struct nfs4_acl *acl)
+{
+#ifdef ACL_DEBUG
+	struct list_head *h;
+	struct nfs4_ace *ace;
+
+	printk(KERN_INFO "** ACL [%i]:\n", acl->naces);
+
+	list_for_each(h, &acl->ace_head) {
+		ace = list_entry(h, struct nfs4_ace, l_ace);
+		nfs4_acl_print_ace(ace);
+	}
+#endif /* ACL_DEBUG */
+}
+
+static void
+nfs4_acl_print_ace(struct nfs4_ace *ace)
+{
+#ifdef ACL_DEBUG
+	char mask[4];
+
+	mask[3] = '\0';
+
+	mask[0] = (ace->access_mask &
+	    NFS4_ACE_GENERIC_READ) == NFS4_ACE_GENERIC_READ ? 'r' : '-';
+	mask[1] = (ace->access_mask &
+	    NFS4_ACE_GENERIC_WRITE) == NFS4_ACE_GENERIC_WRITE ? 'w' : '-';
+	mask[2] = (ace->access_mask &
+	    NFS4_ACE_GENERIC_EXECUTE) == NFS4_ACE_GENERIC_EXECUTE ? 'x' : '-';
+
+	if (ace->wholen == 0)
+		return;
+
+	printk(KERN_INFO "**\twho: %.*s\n", ace->wholen, ace->who);
+	printk(KERN_INFO "**\ttype: %x flag: %x mask: %s\n",
+	    ace->type, ace->flag, mask);
+#endif /* ACL_DEBUG */
+}
+
+static void
+nfs4_posix_acl_print(struct posix_acl *acl)
+{
+#ifdef ACL_DEBUG
+	struct posix_acl_entry *pa, *pe;
+
+	FOREACH_ACL_ENTRY(pa, acl, pe)
+	    switch(pa->e_tag) {
+	    case ACL_USER_OBJ:
+		    printk("++\tOWNER: p: 0x%x\n", pa->e_perm);
+		    break;
+	    case ACL_USER:
+		    printk("++\t%d p: 0x%x\n", pa->e_id, pa->e_perm);
+		    break;
+	    case ACL_GROUP_OBJ:
+		    printk("++\tGROUP: p: 0x%x\n", pa->e_perm);
+		    break;
+	    case ACL_GROUP:
+		    printk("++\t%d p: 0x%x\n", pa->e_id, pa->e_perm);
+		    break;
+	    case ACL_MASK:
+		    printk("++\tMASK: p: 0x%x\n", pa->e_perm);
+		    break;
+	    case ACL_OTHER:
+		    printk("++\tOTHER: p: 0x%x\n", pa->e_perm);
+		    break;
+	    default:
+		    break;
+	    }
+#endif ACL_DEBUG
+}
+
+static struct {
+	char *string;
+	int   stringlen;
+	int   type;
+} s2t_map[] = {
+	{
+		.string    = "OWNER@",
+		.stringlen = sizeof("OWNER@") - 1,
+		.type      = ACETYPE_OWNER
+	},
+	{
+		.string    = "GROUP@",
+		.stringlen = sizeof("GROUP@") - 1,
+		.type      = ACETYPE_GROUP
+	},
+	{
+		.string    = "EVERYONE@",
+		.stringlen = sizeof("EVERYONE@") - 1,
+		.type      = ACETYPE_EVERYONE
+	},
+};
+
+static int
+ace2type(struct nfs4_ace *ace)
+{
+	int i;
+
+	if (ace->who == NULL || ace->wholen <= 0)
+		return (0);
+
+	for (i = 0; i < sizeof(s2t_map) / sizeof(*s2t_map); i++)
+		if (s2t_map[i].stringlen == ace->wholen &&
+		    strncmp(s2t_map[i].string, ace->who, ace->wholen) == 0)
+			return (s2t_map[i].type);
+
+	return (ace->flag & NFS4_ACE_IDENTIFIER_GROUP ? ACETYPE_OGROUP :
+	    ACETYPE_OUSER);
+}
diff -puN /dev/null include/linux/nfs4_acl.h
--- /dev/null	Thu Aug 30 16:30:55 2001
+++ current-marius/include/linux/nfs4_acl.h	Thu May 22 05:10:21 2003
@@ -0,0 +1,58 @@
+/*
+ *  include/linux/nfs4_acl.c
+ *
+ *  Common NFSv4 ACL handling definitions.
+ *
+ *  Copyright (c) 2002 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Marius Aamodt Eriksen <marius@umich.edu>
+ * 
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the University nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LINUX_NFS4_ACL_H
+#define LINUX_NFS4_ACL_H
+
+#include <linux/posix_acl.h>
+
+#define NFS4_ACL_TYPE_ACCESS  0
+#define NFS4_ACL_TYPE_DEFAULT 1
+
+struct nfs4_acl  *nfs4_acl_new(void);
+struct nfs4_acl  *nfs4_acl_free(struct nfs4_acl *);
+int               nfs4_acl_merge(struct nfs4_acl *, struct nfs4_acl *);
+int               nfs4_acl_split(struct nfs4_acl *, struct nfs4_acl *);
+int               nfs4_acl_add_ace(struct nfs4_acl *, u32, u32,
+                      u32, char *, u32);
+void              nfs4_acl_print(struct nfs4_acl *);
+struct nfs4_acl  *nfs4_acl_posix_to_nfsv4(struct inode *inode,
+                      struct posix_acl *, struct posix_acl *);
+int               nfs4_acl_nfsv4_to_posix(struct inode *inode,
+                      struct nfs4_acl *, struct posix_acl **,
+                      struct posix_acl **);
+
+#endif /* LINUX_NFS4_ACL_H */
diff -puN /dev/null fs/nfs4acl/acl_syms.c
--- /dev/null	Thu Aug 30 16:30:55 2001
+++ current-marius/fs/nfs4acl/acl_syms.c	Thu May 22 05:10:21 2003
@@ -0,0 +1,52 @@
+/*
+ *  fs/nfs4acl/acl_syms.c
+ *
+ *  Common NFSv4 ACL handling symbol exports.
+ *
+ *  Copyright (c) 2002 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Marius Aamodt Eriksen <marius@umich.edu>
+ * 
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the University nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/posix_acl.h>
+#include <linux/nfs4.h>
+#include <linux/nfs4_acl.h>
+
+EXPORT_SYMBOL(nfs4_acl_new);
+EXPORT_SYMBOL(nfs4_acl_free);
+EXPORT_SYMBOL(nfs4_acl_merge);
+EXPORT_SYMBOL(nfs4_acl_split);
+EXPORT_SYMBOL(nfs4_acl_add_ace);
+EXPORT_SYMBOL(nfs4_acl_print);
diff -puN /dev/null fs/nfs4acl/acl_map.c
--- /dev/null	Thu Aug 30 16:30:55 2001
+++ current-marius/fs/nfs4acl/acl_map.c	Thu May 22 05:10:21 2003
@@ -0,0 +1,123 @@
+/*
+ *  fs/nfs4acl/acl_map.c
+ *
+ *  Name mapping multiplexing for the NFSv4 ACL handling code.
+ *
+ *  Copyright (c) 2003 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Marius Aamodt Eriksen <marius@umich.edu>
+ * 
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the University nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This is to mediate the two interfaces.  *HOPEFULLY* these will be
+ * coalesced at some point, and we can get rid of this.
+ */
+
+#include <asm/bitops.h>
+
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/nfs_fs.h>
+#include <linux/nfs_idmap.h>
+#include <linux/nfsd_idmap.h>
+
+#include "acl_map.h"
+
+int
+nfs4_acl_map_name2id(struct inode *inode, short flag,
+    char *name, u32 namelen, uid_t *id)
+{
+	u8 type;
+	int error = -EINVAL;
+	int i = 0;
+
+	type = flag & NFS4_ACL_MAP_USER ? IDMAP_TYPE_USER : IDMAP_TYPE_GROUP;
+
+	/* check inode != NULL for client ... */
+
+	if (inode != NULL) {
+#ifdef CONFIG_NFS_V4
+		error = nfs_idmap_id(NFS_SERVER(inode), type, name,
+		    namelen, id);
+#else
+		error = -EOPNOTSUPP;
+#endif /* CONFIG_NFS_V4 */
+	} else {
+#ifdef CONFIG_NFSD_V4
+		char *xname;
+		/* XXX */
+		i+= 2;
+
+		if ((xname = kmalloc(namelen + 1, GFP_KERNEL)) == NULL)
+			return (-ENOMEM);
+
+		memcpy(xname, name, namelen);
+		xname[namelen] = '\0';
+
+		error = nfsd_idmap(IDMAP_TRANS_NAMETOID, type, id, xname);
+
+		kfree(xname);
+#else
+		error = -EOPNOTSUPP;
+#endif /* CONFIG_NFSD_V4 */
+	}
+
+	return (error);
+}
+
+int
+nfs4_acl_map_id2name(struct inode *inode, short flag,
+    char *name, u32 *namelen, uid_t id)
+{
+	u8 type;
+	int error = -EINVAL;
+
+	if (*namelen < IDMAP_NAMESZ)
+		return (-EINVAL);
+
+	type = flag & NFS4_ACL_MAP_USER ? IDMAP_TYPE_USER : IDMAP_TYPE_GROUP;
+
+	if (inode != NULL) {
+#ifdef CONFIG_NFS_V4
+		error = nfs_idmap_name(NFS_SERVER(inode), type, id, name, namelen);
+#else
+		error = -EOPNOTSUPP;
+#endif /* CONFIG_NFS_V4 */
+	} else {
+#ifdef CONFIG_NFSD_V4
+		error = nfsd_idmap(IDMAP_TRANS_IDTONAME, type, &id, name);
+
+		*namelen = strlen(name);
+#else
+		error = -EOPNOTSUPP;
+#endif /* CONFIG_NFSD_V4 */
+	}
+
+	return (error);
+}
diff -puN /dev/null fs/nfs4acl/acl_map.h
--- /dev/null	Thu Aug 30 16:30:55 2001
+++ current-marius/fs/nfs4acl/acl_map.h	Thu May 22 05:10:21 2003
@@ -0,0 +1,53 @@
+/*
+ *  fs/nfs4acl/acl_map.h
+ *
+ *  Name mapping multiplexing for the NFSv4 ACL handling code.
+ *
+ *  Copyright (c) 2003 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Marius Aamodt Eriksen <marius@umich.edu>
+ * 
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the University nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This is to mediate the two interfaces.  *HOPEFULLY* these will be
+ * coalesced at some point, and we can get rid of this.
+ */
+
+#ifndef FS_NFS4MAP_ACL_MAP_H
+#define FS_NFS4MAP_ACL_MAP_H
+
+#define NFS4_ACL_MAP_USER   0x01
+#define NFS4_ACL_MAP_GROUP  0x02
+
+#define NFS4_ACL_MAP_MAXNAMELEN 128
+
+int nfs4_acl_map_name2id(struct inode *, short, char *, u32, uid_t *);
+int nfs4_acl_map_id2name(struct inode *, short, char *, u32 *, uid_t);
+
+#endif /* FS_NFS4MAP_ACL_MAP_H */
diff -puN /dev/null fs/nfs/idmap_syms.c
--- /dev/null	Thu Aug 30 16:30:55 2001
+++ current-marius/fs/nfs/idmap_syms.c	Thu May 22 05:10:21 2003
@@ -0,0 +1,48 @@
+/*
+ *  fs/nfs/idmap_syms.c
+ *
+ *  NFSv4 client IDmap symbol exports.
+ *
+ *  Copyright (c) 2003 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Marius Aamodt Eriksen <marius@umich.edu>
+ * 
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the University nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/nfs_fs.h>
+#include <linux/types.h>
+#include <linux/nfs_idmap.h>
+
+EXPORT_SYMBOL(nfs_idmap_new);
+EXPORT_SYMBOL(nfs_idmap_delete);
+EXPORT_SYMBOL(nfs_idmap_id);
+EXPORT_SYMBOL(nfs_idmap_name);
diff -puN /dev/null fs/nfsd/nfs4idmap_syms.c
--- /dev/null	Thu Aug 30 16:30:55 2001
+++ current-marius/fs/nfsd/nfs4idmap_syms.c	Thu May 22 05:10:21 2003
@@ -0,0 +1,45 @@
+/*
+ *  fs/nfsd/nfs4idmap_syms.c
+ *
+ *  NFSv4 server IDmap symbol exports.
+ *
+ *  Copyright (c) 2003 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Marius Aamodt Eriksen <marius@umich.edu>
+ * 
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the University nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/types.h>
+#include <linux/nfsd_idmap.h>
+
+EXPORT_SYMBOL(nfsd_idmap_init);
+EXPORT_SYMBOL(nfsd_idmap_shutdown);
+EXPORT_SYMBOL(nfsd_idmap);
diff -puN fs/nfsd/Makefile~acl_common fs/nfsd/Makefile
--- current/fs/nfsd/Makefile~acl_common	Thu May 22 05:10:21 2003
+++ current-marius/fs/nfsd/Makefile	Thu May 22 05:10:21 2003
@@ -7,5 +7,6 @@ obj-$(CONFIG_NFSD)	+= nfsd.o
 nfsd-y 			:= nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \
 			   export.o auth.o lockd.o nfscache.o nfsxdr.o stats.o
 nfsd-$(CONFIG_NFSD_V3)	+= nfs3proc.o nfs3xdr.o
-nfsd-$(CONFIG_NFSD_V4)	+= nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o
+nfsd-$(CONFIG_NFSD_V4)	+= nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \
+                           nfs4idmap_syms.o
 nfsd-objs		:= $(nfsd-y)
diff -puN fs/nfs/Makefile~acl_common fs/nfs/Makefile
--- current/fs/nfs/Makefile~acl_common	Thu May 22 05:10:21 2003
+++ current-marius/fs/nfs/Makefile	Thu May 22 05:10:21 2003
@@ -9,6 +9,6 @@ nfs-y 			:= dir.o file.o inode.o nfs2xdr
 nfs-$(CONFIG_ROOT_NFS)	+= nfsroot.o mount_clnt.o      
 nfs-$(CONFIG_NFS_V3)	+= nfs3proc.o nfs3xdr.o
 nfs-$(CONFIG_NFS_V4)	+= nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \
-			   idmap.o
+			   idmap.o idmap_syms.o
 nfs-$(CONFIG_NFS_DIRECTIO) += direct.o
 nfs-objs		:= $(nfs-y)

_
