
ACL support for the NFSv4 client.


 fs/nfs/dir.c            |    2 
 fs/nfs/file.c           |    2 
 fs/nfs/inode.c          |   87 ++++++++++++++++++++++++++++++++++++
 fs/nfs/nfs4proc.c       |  115 +++++++++++++++++++++++++++++++++++++++++++++---
 fs/nfs/nfs4xdr.c        |   77 ++++++++++++++++++++++++++++++--
 include/linux/nfs_fs.h  |    6 ++
 include/linux/nfs_xdr.h |   11 ++++
 7 files changed, 290 insertions(+), 10 deletions(-)

diff -puN include/linux/nfs_xdr.h~acl_client include/linux/nfs_xdr.h
--- current/include/linux/nfs_xdr.h~acl_client	Mon Jun  2 12:54:10 2003
+++ current-marius/include/linux/nfs_xdr.h	Mon Jun  2 12:54:10 2003
@@ -39,6 +39,9 @@ struct nfs_fattr {
 	__u64			change_attr;	/* NFSv4 change attribute */
 	__u64			pre_change_attr;/* pre-op NFSv4 change attribute */
 	unsigned long		timestamp;
+#ifdef CONFIG_NFS_V4
+	struct nfs4_acl        *acl;            /* NFSv4 ACL */
+#endif /* CONFIG_NFS_V4 */
 };
 
 #define NFS_ATTR_WCC		0x0001		/* pre-op WCC data    */
@@ -251,6 +254,9 @@ struct nfs_setattrargs {
 	struct iattr *                  iap;
 	struct nfs4_getattr *           attr;
 	struct nfs_server *             server; /* Needed for name mapping */
+#ifdef CONFIG_NFS_V4
+	struct nfs4_acl *               acl;
+#endif /* CONFIG_NFS_V4 */
 };
 
 struct nfs_setattrres {
@@ -451,6 +457,7 @@ struct nfs4_getattr {
 	struct nfs_fsstat *		gt_fsstat;         /* response */
 	struct nfs_fsinfo *		gt_fsinfo;         /* response */
 	struct nfs_pathconf *		gt_pathconf;       /* response */
+	struct nfs4_acl **              gt_acl;	           /* response */
 	u32 *				gt_bmres;	   /* response */
 };
 
@@ -674,6 +681,10 @@ struct nfs_rpc_ops {
 	void	(*write_setup)  (struct nfs_write_data *, unsigned int count, int how);
 	void	(*commit_setup) (struct nfs_write_data *, u64 start, u32 len, int how);
 	int	(*file_open)   (struct inode *, struct file *);
+#ifdef CONFIG_NFS_V4
+	struct posix_acl *(*get_posix_acl) (struct inode *, int);
+	int               (*set_posix_acl) (struct inode *, int, struct posix_acl *);
+#endif /* CONFIG_NFS_V4 */
 };
 
 /*
diff -puN include/linux/nfs_fs.h~acl_client include/linux/nfs_fs.h
--- current/include/linux/nfs_fs.h~acl_client	Mon Jun  2 12:54:10 2003
+++ current-marius/include/linux/nfs_fs.h	Mon Jun  2 12:54:10 2003
@@ -22,6 +22,10 @@
 #include <linux/sunrpc/auth.h>
 #include <linux/sunrpc/clnt.h>
 
+#ifdef CONFIG_NFS_V4
+#include <linux/xattr_acl.h>
+#endif /* CONFIG_NFS_V4 */
+
 #include <linux/nfs.h>
 #include <linux/nfs2.h>
 #include <linux/nfs3.h>
@@ -240,11 +244,13 @@ extern struct inode *nfs_fhget(struct de
 				struct nfs_fattr *);
 extern int __nfs_refresh_inode(struct inode *, struct nfs_fattr *);
 extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
+extern ssize_t nfs_getxattr(struct dentry *, const char *, void *, size_t);
 extern int nfs_permission(struct inode *, int);
 extern int nfs_open(struct inode *, struct file *);
 extern int nfs_release(struct inode *, struct file *);
 extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
 extern int nfs_setattr(struct dentry *, struct iattr *);
+extern int nfs_setxattr(struct dentry *, const char *, const void *, size_t, int);
 
 /*
  * linux/fs/nfs/file.c
diff -puN fs/nfs/file.c~acl_client fs/nfs/file.c
--- current/fs/nfs/file.c~acl_client	Mon Jun  2 12:54:10 2003
+++ current-marius/fs/nfs/file.c	Mon Jun  2 12:54:10 2003
@@ -61,6 +61,8 @@ struct inode_operations nfs_file_inode_o
 	.permission	= nfs_permission,
 	.getattr	= nfs_getattr,
 	.setattr	= nfs_setattr,
+	.getxattr       = nfs_getxattr,
+	.setxattr       = nfs_setxattr,
 };
 
 /* Hack for future NFS swap support */
diff -puN fs/nfs/inode.c~acl_client fs/nfs/inode.c
--- current/fs/nfs/inode.c~acl_client	Mon Jun  2 12:54:10 2003
+++ current-marius/fs/nfs/inode.c	Mon Jun  2 12:54:10 2003
@@ -812,6 +812,58 @@ out:
 	return error;
 }
 
+int
+nfs_setxattr(struct dentry *dentry, const char *key, const void *buf,
+    size_t buflen, int flags)
+{
+#ifdef CONFIG_NFS_V4
+	struct posix_acl *acl;
+	int type, error;
+	struct inode *inode = dentry->d_inode;
+
+	if (NFS_PROTO(inode)->set_posix_acl == NULL)
+		return (-EOPNOTSUPP);
+
+	if (strlen(key) == sizeof(XATTR_NAME_ACL_ACCESS) - 1 &&
+	    memcmp(key, XATTR_NAME_ACL_ACCESS,
+		sizeof(XATTR_NAME_ACL_ACCESS) - 1) == 0)
+		type = ACL_TYPE_ACCESS;
+	else if (strlen(key) == sizeof(XATTR_NAME_ACL_DEFAULT) - 1 &&
+	    memcmp(key, XATTR_NAME_ACL_DEFAULT,
+		sizeof(XATTR_NAME_ACL_ACCESS) - 1) == 0)
+		type = ACL_TYPE_DEFAULT;
+	else
+		return (-EINVAL);
+
+        if (!S_ISREG(inode->i_mode) &&
+            (!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX))
+                return (-EPERM);
+
+	/* XXX MARIUS - ACL perms? */
+	error = permission(inode, MAY_WRITE);
+
+	if (error)
+		return (error);
+
+	if (buf == NULL)
+		return (-EINVAL);
+
+	acl = posix_acl_from_xattr(buf, buflen);
+	if (IS_ERR(acl))
+		return (PTR_ERR(acl));
+	if (acl == NULL)
+		return (-ENODATA);
+
+	error = posix_acl_valid(acl);
+	if (error)
+		return (error);
+
+	return (NFS_PROTO(inode)->set_posix_acl(inode, type, acl));
+#else
+	return (-EOPNOTSUPP);
+#endif /* CONFIG_NFS_V4 */
+}
+
 /*
  * Wait for the inode to get unlocked.
  * (Used for NFS_INO_LOCKED and NFS_INO_REVALIDATING).
@@ -841,6 +893,41 @@ int nfs_getattr(struct vfsmount *mnt, st
 	return err;
 }
 
+ssize_t
+nfs_getxattr(struct dentry *dentry, const char *key, void *buf,
+    size_t buflen)
+{
+#ifdef CONFIG_NFS_V4
+	int type = 0;
+	ssize_t error;
+	struct inode *inode = dentry->d_inode;
+	struct posix_acl *acl;
+
+	if (NFS_PROTO(inode)->get_posix_acl == NULL)
+		return (-EOPNOTSUPP);
+
+	if (strlen(key) == sizeof(XATTR_NAME_ACL_ACCESS) - 1 &&
+	    memcmp(key, XATTR_NAME_ACL_ACCESS,
+		sizeof(XATTR_NAME_ACL_ACCESS) - 1) == 0)
+		type = ACL_TYPE_ACCESS;
+	else if (strlen(key) == sizeof(XATTR_NAME_ACL_DEFAULT) - 1 &&
+	    memcmp(key, XATTR_NAME_ACL_DEFAULT,
+		sizeof(XATTR_NAME_ACL_ACCESS) - 1) == 0)
+		type = ACL_TYPE_DEFAULT;
+	else
+		return (-EINVAL);
+
+	acl = NFS_PROTO(inode)->get_posix_acl(inode, type);
+
+	if (IS_ERR(acl))
+		return (PTR_ERR(acl));
+
+	return (posix_acl_to_xattr(acl, buf, buflen));
+#else
+	return (-EOPNOTSUPP);
+#endif /* CONFIG_NFS_V4 */
+}
+
 /*
  * Ensure that mmap has a recent RPC credential for use when writing out
  * shared pages
diff -puN fs/nfs/nfs4proc.c~acl_client fs/nfs/nfs4proc.c
--- current/fs/nfs/nfs4proc.c~acl_client	Mon Jun  2 12:54:10 2003
+++ current-marius/fs/nfs/nfs4proc.c	Mon Jun  2 12:54:10 2003
@@ -45,6 +45,7 @@
 #include <linux/nfs_fs.h>
 #include <linux/nfs_page.h>
 #include <linux/smp_lock.h>
+#include <linux/nfs4_acl.h>
 
 #define NFSDBG_FACILITY		NFSDBG_PROC
 
@@ -213,12 +214,18 @@ u32 nfs4_mount_bitmap[2] = {
 	| FATTR4_WORD1_TIME_MODIFY
 };
 
+u32 nfs4_acl_bitmap[2] = {
+	FATTR4_WORD0_ACL,
+	0
+};
+
 static inline void
 __nfs4_setup_getattr(struct nfs4_compound *cp, u32 *bitmap,
 		     struct nfs_fattr *fattr,
 		     struct nfs_fsstat *fsstat,
 		     struct nfs_fsinfo *fsinfo,
 		     struct nfs_pathconf *pathconf,
+                     struct nfs4_acl **acl,
 		     u32 *bmres)
 {
         struct nfs4_getattr *getattr = GET_OP(cp, getattr);
@@ -229,6 +236,7 @@ __nfs4_setup_getattr(struct nfs4_compoun
 	getattr->gt_fsinfo = fsinfo;
 	getattr->gt_pathconf = pathconf;
 	getattr->gt_bmres = bmres;
+	getattr->gt_acl = acl;
 
         OPNUM(cp) = OP_GETATTR;
         cp->req_nops++;
@@ -240,7 +248,7 @@ nfs4_setup_getattr(struct nfs4_compound 
 		u32 *bmres)
 {
 	__nfs4_setup_getattr(cp, nfs4_fattr_bitmap, fattr,
-			NULL, NULL, NULL, bmres);
+			NULL, NULL, NULL, NULL, bmres);
 }
 
 static void
@@ -250,7 +258,7 @@ nfs4_setup_getrootattr(struct nfs4_compo
 		u32 *bmres)
 {
 	__nfs4_setup_getattr(cp, nfs4_mount_bitmap,
-			fattr, NULL, fsinfo, NULL, bmres);
+			fattr, NULL, fsinfo, NULL, NULL, bmres);
 }
 
 static void
@@ -259,7 +267,7 @@ nfs4_setup_statfs(struct nfs4_compound *
 		u32 *bmres)
 {
 	__nfs4_setup_getattr(cp, nfs4_statfs_bitmap,
-			NULL, fsstat, NULL, NULL, bmres);
+			NULL, fsstat, NULL, NULL, NULL, bmres);
 }
 
 static void
@@ -268,7 +276,7 @@ nfs4_setup_fsinfo(struct nfs4_compound *
 		u32 *bmres)
 {
 	__nfs4_setup_getattr(cp, nfs4_fsinfo_bitmap,
-			NULL, NULL, fsinfo, NULL, bmres);
+			NULL, NULL, fsinfo, NULL, NULL, bmres);
 }
 
 static void
@@ -277,7 +285,14 @@ nfs4_setup_pathconf(struct nfs4_compound
 		u32 *bmres)
 {
 	__nfs4_setup_getattr(cp, nfs4_pathconf_bitmap,
-			NULL, NULL, NULL, pathconf, bmres);
+			NULL, NULL, NULL, pathconf, NULL, bmres);
+}
+
+static void
+nfs4_setup_getacl(struct nfs4_compound *cp, struct nfs4_acl **acl, u32 *bmres)
+{
+	__nfs4_setup_getattr(cp, nfs4_acl_bitmap,
+	    NULL, NULL, NULL, NULL, acl, bmres);
 }
 
 static void
@@ -656,7 +671,7 @@ nfs4_do_open(struct inode *dir, struct q
 		};
 
 		memcpy(oc_arg.stateid, o_res.stateid, sizeof(nfs4_stateid));
-		status = rpc_call_sync(server->client, &msg, 0);
+ 		status = rpc_call_sync(server->client, &msg, 0);
 		if (status)
 			goto out_up;
 		nfs4_increment_seqid(status, sp);
@@ -898,6 +913,92 @@ no_open:
 	return status;
 }
 
+static struct posix_acl *
+nfs4_proc_get_posix_acl(struct inode *inode, int type)
+{
+	struct nfs4_compound compound;
+	struct nfs4_op ops[2];
+	struct nfs4_acl *acl;
+	u32 bmres[2];
+	int error;
+	struct posix_acl *pacl;
+
+	nfs4_setup_compound(&compound, ops, NFS_SERVER(inode), "getattr");
+	nfs4_setup_putfh(&compound, NFS_FH(inode));
+	nfs4_setup_getacl(&compound, &acl, bmres);
+
+	error = nfs4_call_compound(&compound, NULL, 0);
+
+	if (error < 0 || acl == NULL)
+		return (error < 0 ? ERR_PTR(error) : ERR_PTR(-ENODATA));
+
+	if (type == ACL_TYPE_ACCESS)
+		error = nfs4_acl_nfsv4_to_posix(inode, acl, &pacl, NULL);
+	else
+		error = nfs4_acl_nfsv4_to_posix(inode, acl, NULL, &pacl);
+
+	nfs4_acl_free(acl);
+
+	if (error < 0)
+		pacl = ERR_PTR(error);
+
+	return (pacl);
+}
+
+static int
+nfs4_proc_set_posix_acl(struct inode *inode, int type, struct posix_acl *pacl)
+{
+	struct iattr ia;
+        u32                      g_bmres[2];
+	struct nfs4_acl         *acl, *xacl;
+	struct nfs_fattr         fattr;
+	u32                      bmval[2];
+	int error;
+        struct nfs4_getattr     getattr = {
+                .gt_bmval       = bmval,
+                .gt_attrs       = &fattr,
+                .gt_bmres       = g_bmres,
+		.gt_acl         = &xacl,
+        };
+        struct nfs_setattrargs  arg = {
+                .fh             = NFS_FH(inode),
+                .iap            = &ia,
+                .attr           = &getattr,
+		.server		= NFS_SERVER(inode),
+        };
+        struct nfs_setattrres  res = {
+                .attr           = &getattr,
+		.server		= NFS_SERVER(inode),
+        };
+        struct rpc_message msg = {
+                .rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_SETATTR],
+                .rpc_argp       = &arg,
+                .rpc_resp       = &res,
+        };
+
+	bmval[0] = FATTR4_WORD0_ACL;
+	bmval[1] = 0;
+
+	ia.ia_valid = 0;
+        fattr.valid = 0;
+
+	if (type == ACL_TYPE_ACCESS)
+		acl = nfs4_acl_posix_to_nfsv4(inode, pacl, NULL);
+	else
+		acl = nfs4_acl_posix_to_nfsv4(inode, NULL, pacl);
+	if (IS_ERR(acl))
+		return (PTR_ERR(acl));
+
+	arg.acl = acl;
+
+	error = rpc_call_sync(NFS_SERVER(inode)->client, &msg, 0);
+
+	if (xacl != NULL)
+		nfs4_acl_free(xacl);
+
+	return (error);
+}
+
 static int
 nfs4_proc_lookup(struct inode *dir, struct qstr *name,
 		 struct nfs_fh *fhandle, struct nfs_fattr *fattr)
@@ -1772,6 +1873,8 @@ struct nfs_rpc_ops	nfs_v4_clientops = {
 	.write_setup	= nfs4_proc_write_setup,
 	.commit_setup	= nfs4_proc_commit_setup,
 	.file_open      = nfs4_proc_file_open,
+	.set_posix_acl  = nfs4_proc_set_posix_acl,
+	.get_posix_acl  = nfs4_proc_get_posix_acl,
 };
 
 /*
diff -puN fs/nfs/nfs4xdr.c~acl_client fs/nfs/nfs4xdr.c
--- current/fs/nfs/nfs4xdr.c~acl_client	Mon Jun  2 12:54:10 2003
+++ current-marius/fs/nfs/nfs4xdr.c	Mon Jun  2 18:00:59 2003
@@ -51,6 +51,7 @@
 #include <linux/nfs4.h>
 #include <linux/nfs_fs.h>
 #include <linux/nfs_idmap.h>
+#include <linux/nfs4_acl.h>
 
 #define NFSDBG_FACILITY		NFSDBG_XDR
 
@@ -235,7 +236,7 @@ encode_compound_hdr(struct xdr_stream *x
 }
 
 static int
-encode_attrs(struct xdr_stream *xdr, struct iattr *iap,
+encode_attrs(struct xdr_stream *xdr, struct iattr *iap, struct nfs4_acl *acl,
     struct nfs_server *server)
 {
 	char owner_name[256];
@@ -296,6 +297,17 @@ encode_attrs(struct xdr_stream *xdr, str
 		len += 16;
 	else if (iap->ia_valid & ATTR_MTIME)
 		len += 4;
+	if (acl != NULL) {
+		struct nfs4_ace *ace;
+		struct list_head *h;
+
+		len += acl->naces * 16 + 4;
+		list_for_each(h, &acl->ace_head) {
+			ace = list_entry(h, struct nfs4_ace, l_ace);
+			len += XDR_QUADLEN(ace->wholen) << 2;
+		}
+	}
+
 	RESERVE_SPACE(len);
 
 	/*
@@ -310,6 +322,22 @@ encode_attrs(struct xdr_stream *xdr, str
 		bmval0 |= FATTR4_WORD0_SIZE;
 		WRITE64(iap->ia_size);
 	}
+	if (acl != NULL) {
+		struct list_head *h;
+		struct nfs4_ace *ace;
+
+		bmval0 |= FATTR4_WORD0_ACL;
+
+		WRITE32(acl->naces);
+		list_for_each(h, &acl->ace_head) {
+			ace = list_entry(h, struct nfs4_ace, l_ace);
+			WRITE32(ace->type);
+			WRITE32(ace->flag);
+			WRITE32(ace->access_mask);
+			WRITE32(ace->wholen);
+			WRITEMEM(ace->who, ace->wholen);
+		}
+	}
 	if (iap->ia_valid & ATTR_MODE) {
 		bmval1 |= FATTR4_WORD1_MODE;
 		WRITE32(iap->ia_mode);
@@ -434,7 +462,7 @@ encode_create(struct xdr_stream *xdr, st
 	WRITE32(create->cr_namelen);
 	WRITEMEM(create->cr_name, create->cr_namelen);
 
-	return encode_attrs(xdr, create->cr_attrs, server);
+	return encode_attrs(xdr, create->cr_attrs, NULL, server);
 }
 
 static int
@@ -577,7 +605,7 @@ encode_open(struct xdr_stream *xdr, stru
 		else if (arg->u.attrs) {
 			RESERVE_SPACE(4);
 			WRITE32(arg->createmode);
-			if ((status = encode_attrs(xdr, arg->u.attrs, arg->server)))
+			if ((status = encode_attrs(xdr, arg->u.attrs, NULL, arg->server)))
 				return status;
 		}
 		else {
@@ -772,7 +800,7 @@ encode_setattr(struct xdr_stream *xdr, s
         WRITE32(OP_SETATTR);
 	WRITEMEM(arg->stateid, sizeof(nfs4_stateid));
 
-        if ((status = encode_attrs(xdr, arg->iap, server)))
+        if ((status = encode_attrs(xdr, arg->iap, arg->acl, server)))
 		return status;
 
         return 0;
@@ -1389,6 +1417,47 @@ decode_getattr(struct xdr_stream *xdr, s
                 READ32(fsinfo->lease_time);
                 dprintk("read_attrs: lease_time=%d\n", fsinfo->lease_time);
         }
+	if (bmval0 & FATTR4_WORD0_ACL) {
+		struct nfs4_acl *acl;
+		struct nfs4_ace ace;
+		int i;
+		u_int nace;
+
+		if (getattr->gt_acl == NULL)
+			goto xdr_error; /* XXX MARIUS */
+
+		READ_BUF(4); len += 4;
+		READ32(nace);
+
+		if (nace == 0) {
+			*getattr->gt_acl = NULL;
+			goto out_acl;
+		}
+
+		acl = *getattr->gt_acl = nfs4_acl_new();
+		if (acl == NULL) {
+			status = -ENOMEM;
+			goto out;
+		}
+
+		for (i = 0; i < nace; i++) {
+			READ_BUF(16); len += 16;
+			READ32(ace.type);
+			READ32(ace.flag);
+			READ32(ace.access_mask);
+			READ32(ace.wholen);
+			READ_BUF(ace.wholen);
+			len += XDR_QUADLEN(ace.wholen) << 2;
+			status = nfs4_acl_add_ace(acl, ace.type, ace.flag,
+			    ace.access_mask, (char *)p, ace.wholen);
+			if (status < 0)
+				goto out;
+			p += XDR_QUADLEN(ace.wholen);
+		}
+	out_acl:
+	} else if (getattr->gt_acl != NULL)
+		*getattr->gt_acl = NULL;
+
         if (bmval0 & FATTR4_WORD0_FILEID) {
                 READ_BUF(8);
                 len += 8;
diff -puN fs/nfs/dir.c~acl_client fs/nfs/dir.c
--- current/fs/nfs/dir.c~acl_client	Mon Jun  2 12:54:10 2003
+++ current-marius/fs/nfs/dir.c	Mon Jun  2 12:54:10 2003
@@ -70,6 +70,8 @@ struct inode_operations nfs_dir_inode_op
 	.permission	= nfs_permission,
 	.getattr	= nfs_getattr,
 	.setattr	= nfs_setattr,
+	.getxattr       = nfs_getxattr,
+	.setxattr       = nfs_setxattr,	
 };
 
 /*

_
