All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/5][v3][RFC] NFSv3: implement extended attribute protocol (XATTR)
@ 2010-02-26  4:33 James Morris
  2010-02-26  4:34 ` [PATCH 1/5] NFSv3: convert client to generic xattr API James Morris
                   ` (5 more replies)
  0 siblings, 6 replies; 39+ messages in thread
From: James Morris @ 2010-02-26  4:33 UTC (permalink / raw)
  To: linux-nfs
  Cc: linux-security-module, Trond Myklebust, J. Bruce Fields, Neil Brown

This is version 3 of the NFSv3 XATTR protocol extension patches, which 
I've previously posted:

v1: http://thread.gmane.org/gmane.linux.file-systems/35475
v2: http://thread.gmane.org/gmane.linux.nfs/30539

The main change in this version is the addition of support for storing 
xattrs in a local namespace on the server, following feedback from Trond.

The wire protocol and client view is unchanged.  The server now stores all 
xattrs received via the XATTR protocol in a special namespace: user._nfsd.  
This allows arbitrary xattrs to be manipulated by clients, with the server 
providing xattr storage only, and no interpretation of the xattrs.

For example, if the client sets an xattr named "user.icon", it will be 
transferred as such to the server via the XATTR protocol, and the server 
will store it locally as "user._nfsd.user.icon".

This is entirely transparent to the user and works similarly getxattr(2) 
and removexattr(2).  The server filters listxattr(2) to only return xattr 
names with this prefix (with the prefix stripped).

e.g. when the client calls getxattr(2) for "user.icon", this is translated 
at the server to "user._nfsd.user.icon", and the associated value 
is returned to the client.

The changes for this are in the last patch in the set (which also includes 
a bugfix), so they can be reviewed separately.

I chose the user._nfsd namespace, rather than, say, a system. namespace, 
because filesystems which support xattrs tend already have a generalized 
user. xattr handler.  If we don't use user., then new xattr handlers will 
need to be implemented for each backing fs.

An assumption is made that the server is under administrative control, and 
that end users do not have local access to the exported filesystems.

The '_nfsd' component of the namespace could be made a per-export 
configuration value (as also discussed with Trond), although I've kept 
things as simple as possible at this stage.

Note that only the user. and trusted. namespaces are supported on the 
client at this stage (except for system.posix_acl*, which is handled by 
the NFS_ACL protocol).  This is also keep things initially simple, as 
we'll need to make SELinux and possibly other security/system xattr users 
aware of the NFS_XATTR protocol, but aside from that, it should be 
possible to extend this scheme to arbitrary client xattr namespaces.

Please review and comment.


- James
-- 
James Morris
<jmorris@namei.org>

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH 1/5] NFSv3: convert client to generic xattr API
  2010-02-26  4:33 [PATCH 0/5][v3][RFC] NFSv3: implement extended attribute protocol (XATTR) James Morris
@ 2010-02-26  4:34 ` James Morris
  2010-02-26  4:35 ` [PATCH 2/5] NFSv3: add xattr API config option for client James Morris
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 39+ messages in thread
From: James Morris @ 2010-02-26  4:34 UTC (permalink / raw)
  To: linux-nfs
  Cc: linux-security-module, Trond Myklebust, J. Bruce Fields, Neil Brown

Convert existing NFSv3 client use (i.e. ACLs) of the xattrs to
the kernel's generic xattr API.

This helps simplify the code, and prepare for the subsequent
NFSv3 xattr protocol patches, which will also utilize the
generic xattr API.

Signed-off-by: James Morris <jmorris@namei.org>
---
 fs/nfs/dir.c           |    8 ++--
 fs/nfs/file.c          |    8 ++--
 fs/nfs/internal.h      |    4 ++
 fs/nfs/nfs3acl.c       |  122 ++++++++++++++++++++---------------------------
 fs/nfs/super.c         |    3 +
 include/linux/nfs_fs.h |   16 ------
 6 files changed, 67 insertions(+), 94 deletions(-)

diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 3c7f03b..b1cb729 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -94,10 +94,10 @@ const struct inode_operations nfs3_dir_inode_operations = {
 	.permission	= nfs_permission,
 	.getattr	= nfs_getattr,
 	.setattr	= nfs_setattr,
-	.listxattr	= nfs3_listxattr,
-	.getxattr	= nfs3_getxattr,
-	.setxattr	= nfs3_setxattr,
-	.removexattr	= nfs3_removexattr,
+	.listxattr	= generic_listxattr,
+	.getxattr	= generic_getxattr,
+	.setxattr	= generic_setxattr,
+	.removexattr	= generic_removexattr,
 };
 #endif  /* CONFIG_NFS_V3 */
 
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 63f2071..ddb7ab7 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -91,10 +91,10 @@ const struct inode_operations nfs3_file_inode_operations = {
 	.permission	= nfs_permission,
 	.getattr	= nfs_getattr,
 	.setattr	= nfs_setattr,
-	.listxattr	= nfs3_listxattr,
-	.getxattr	= nfs3_getxattr,
-	.setxattr	= nfs3_setxattr,
-	.removexattr	= nfs3_removexattr,
+	.listxattr	= generic_listxattr,
+	.getxattr	= generic_getxattr,
+	.setxattr	= generic_setxattr,
+	.removexattr	= generic_removexattr,
 };
 #endif  /* CONFIG_NFS_v3 */
 
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 29e464d..9bb918a 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -4,6 +4,7 @@
 
 #include "nfs4_fs.h"
 #include <linux/mount.h>
+#include <linux/xattr.h>
 #include <linux/security.h>
 
 #define NFS_MS_MASK (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_SYNCHRONOUS)
@@ -284,6 +285,9 @@ static inline char *nfs_devname(const struct vfsmount *mnt_parent,
 			dentry, buffer, buflen);
 }
 
+/* nfs3acl.c */
+extern struct xattr_handler *nfs3_xattr_handlers[];
+
 /*
  * Determine the actual block size (and log2 thereof)
  */
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c
index bac6051..c03f8e0 100644
--- a/fs/nfs/nfs3acl.c
+++ b/fs/nfs/nfs3acl.c
@@ -9,64 +9,41 @@
 
 #define NFSDBG_FACILITY	NFSDBG_PROC
 
-ssize_t nfs3_listxattr(struct dentry *dentry, char *buffer, size_t size)
+static size_t nfs3_acl_xattr_list(struct dentry *dentry,
+				  char *list, size_t list_len,
+				  const char *name, size_t name_len,
+				  int acl_type)
 {
-	struct inode *inode = dentry->d_inode;
 	struct posix_acl *acl;
-	int pos=0, len=0;
+	char *acl_name = ACL_TYPE_ACCESS ?
+		POSIX_ACL_XATTR_ACCESS : POSIX_ACL_XATTR_DEFAULT;
+	size_t size = strlen(acl_name) + 1;
 
-#	define output(s) do {						\
-			if (pos + sizeof(s) <= size) {			\
-				memcpy(buffer + pos, s, sizeof(s));	\
-				pos += sizeof(s);			\
-			}						\
-			len += sizeof(s);				\
-		} while(0)
+	acl = nfs3_proc_getacl(dentry->d_inode, acl_type);
+	if (!acl)
+		return 0;
 
-	acl = nfs3_proc_getacl(inode, ACL_TYPE_ACCESS);
 	if (IS_ERR(acl))
 		return PTR_ERR(acl);
-	if (acl) {
-		output("system.posix_acl_access");
-		posix_acl_release(acl);
-	}
 
-	if (S_ISDIR(inode->i_mode)) {
-		acl = nfs3_proc_getacl(inode, ACL_TYPE_DEFAULT);
-		if (IS_ERR(acl))
-			return PTR_ERR(acl);
-		if (acl) {
-			output("system.posix_acl_default");
-			posix_acl_release(acl);
-		}
-	}
-
-#	undef output
+	if (list && size <= list_len)
+		memcpy(list, acl_name, size);
 
-	if (!buffer || len <= size)
-		return len;
-	return -ERANGE;
+	posix_acl_release(acl);
+	return size;
 }
 
-ssize_t nfs3_getxattr(struct dentry *dentry, const char *name,
-		void *buffer, size_t size)
+static int nfs3_acl_xattr_get(struct dentry *dentry, const char *name,
+			      void *buffer, size_t size, int acl_type)
 {
-	struct inode *inode = dentry->d_inode;
 	struct posix_acl *acl;
-	int type, error = 0;
-
-	if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0)
-		type = ACL_TYPE_ACCESS;
-	else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0)
-		type = ACL_TYPE_DEFAULT;
-	else
-		return -EOPNOTSUPP;
+	int error = 0;
 
-	acl = nfs3_proc_getacl(inode, type);
+	acl = nfs3_proc_getacl(dentry->d_inode, acl_type);
 	if (IS_ERR(acl))
 		return PTR_ERR(acl);
 	else if (acl) {
-		if (type == ACL_TYPE_ACCESS && acl->a_count == 0)
+		if (acl_type == ACL_TYPE_ACCESS && acl->a_count == 0)
 			error = -ENODATA;
 		else
 			error = posix_acl_to_xattr(acl, buffer, size);
@@ -77,43 +54,48 @@ ssize_t nfs3_getxattr(struct dentry *dentry, const char *name,
 	return error;
 }
 
-int nfs3_setxattr(struct dentry *dentry, const char *name,
-	     const void *value, size_t size, int flags)
+static int nfs3_acl_xattr_set(struct dentry *dentry, const char *name,
+			      const void *value, size_t size, int flags,
+			      int acl_type)
 {
-	struct inode *inode = dentry->d_inode;
 	struct posix_acl *acl;
-	int type, error;
+	int error;
 
-	if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0)
-		type = ACL_TYPE_ACCESS;
-	else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0)
-		type = ACL_TYPE_DEFAULT;
-	else
-		return -EOPNOTSUPP;
+	if (value == NULL && (flags & XATTR_REPLACE))
+		acl = NULL;	/* remove xattr */
+	else {
+		acl = posix_acl_from_xattr(value, size);
+		if (IS_ERR(acl))
+			return PTR_ERR(acl);
+	}
 
-	acl = posix_acl_from_xattr(value, size);
-	if (IS_ERR(acl))
-		return PTR_ERR(acl);
-	error = nfs3_proc_setacl(inode, type, acl);
+	error = nfs3_proc_setacl(dentry->d_inode, acl_type, acl);
 	posix_acl_release(acl);
 
 	return error;
 }
 
-int nfs3_removexattr(struct dentry *dentry, const char *name)
-{
-	struct inode *inode = dentry->d_inode;
-	int type;
-
-	if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0)
-		type = ACL_TYPE_ACCESS;
-	else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0)
-		type = ACL_TYPE_DEFAULT;
-	else
-		return -EOPNOTSUPP;
-
-	return nfs3_proc_setacl(inode, type, NULL);
-}
+static struct xattr_handler nfs3_xattr_acl_access_handler = {
+	.prefix = POSIX_ACL_XATTR_ACCESS,
+	.flags	= ACL_TYPE_ACCESS,
+	.list   = nfs3_acl_xattr_list,
+	.get    = nfs3_acl_xattr_get,
+	.set    = nfs3_acl_xattr_set,
+};
+
+static struct xattr_handler nfs3_xattr_acl_default_handler = {
+	.prefix = POSIX_ACL_XATTR_DEFAULT,
+	.flags	= ACL_TYPE_DEFAULT,
+	.list   = nfs3_acl_xattr_list,
+	.get    = nfs3_acl_xattr_get,
+	.set    = nfs3_acl_xattr_set,
+};
+
+struct xattr_handler *nfs3_xattr_handlers[] = {
+	&nfs3_xattr_acl_access_handler,
+	&nfs3_xattr_acl_default_handler,
+	NULL
+};
 
 static void __nfs3_forget_cached_acls(struct nfs_inode *nfsi)
 {
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index f1afee4..31f5863 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -2018,6 +2018,9 @@ static void nfs_fill_super(struct super_block *sb,
 		 */
 		sb->s_flags |= MS_POSIXACL;
 		sb->s_time_gran = 1;
+#ifdef CONFIG_NFS_V3_ACL
+		sb->s_xattr = nfs3_xattr_handlers;
+#endif
 	}
 
 	sb->s_op = &nfs_sops;
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index d09db1b..34848b8 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -389,22 +389,6 @@ static inline struct rpc_cred *nfs_file_cred(struct file *file)
 }
 
 /*
- * linux/fs/nfs/xattr.c
- */
-#ifdef CONFIG_NFS_V3_ACL
-extern ssize_t nfs3_listxattr(struct dentry *, char *, size_t);
-extern ssize_t nfs3_getxattr(struct dentry *, const char *, void *, size_t);
-extern int nfs3_setxattr(struct dentry *, const char *,
-			const void *, size_t, int);
-extern int nfs3_removexattr (struct dentry *, const char *name);
-#else
-# define nfs3_listxattr NULL
-# define nfs3_getxattr NULL
-# define nfs3_setxattr NULL
-# define nfs3_removexattr NULL
-#endif
-
-/*
  * linux/fs/nfs/direct.c
  */
 extern ssize_t nfs_direct_IO(int, struct kiocb *, const struct iovec *, loff_t,
-- 
1.6.3.3


-- 
James Morris
<jmorris@namei.org>

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 2/5] NFSv3: add xattr API config option for client
  2010-02-26  4:33 [PATCH 0/5][v3][RFC] NFSv3: implement extended attribute protocol (XATTR) James Morris
  2010-02-26  4:34 ` [PATCH 1/5] NFSv3: convert client to generic xattr API James Morris
@ 2010-02-26  4:35 ` James Morris
       [not found] ` <alpine.LRH.2.00.1002261457420.25193-CK9fWmtY32x9JUWOpEiw7w@public.gmane.org>
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 39+ messages in thread
From: James Morris @ 2010-02-26  4:35 UTC (permalink / raw)
  To: linux-nfs
  Cc: linux-security-module, Trond Myklebust, J. Bruce Fields, Neil Brown

Add a separate configuration option for xattr API use by NFSv3 client 
code, and make it independent of ACLs, so other NFSv3 client code (e.g. 
the subsequent XATTR side-protocol) can use it.

Move the ACL handlers into the new xattr API file, where all such
handlers in the NFSv3 client code will live.

Signed-off-by: James Morris <jmorris@namei.org>
---
 fs/nfs/Kconfig     |    4 ++++
 fs/nfs/Makefile    |    1 +
 fs/nfs/internal.h  |    6 +++++-
 fs/nfs/nfs3acl.c   |   10 ++--------
 fs/nfs/nfs3xattr.c |   25 +++++++++++++++++++++++++
 5 files changed, 37 insertions(+), 9 deletions(-)
 create mode 100644 fs/nfs/nfs3xattr.c

diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig
index 59e5673..d27a88e 100644
--- a/fs/nfs/Kconfig
+++ b/fs/nfs/Kconfig
@@ -38,9 +38,13 @@ config NFS_V3
 
 	  If unsure, say Y.
 
+config NFS_V3_XATTR_API
+	def_bool n
+
 config NFS_V3_ACL
 	bool "NFS client support for the NFSv3 ACL protocol extension"
 	depends on NFS_V3
+	select NFS_V3_XATTR_API
 	help
 	  Some NFS servers support an auxiliary NFSv3 ACL protocol that
 	  Sun added to Solaris but never became an official part of the
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile
index da7fda6..1e2743e 100644
--- a/fs/nfs/Makefile
+++ b/fs/nfs/Makefile
@@ -11,6 +11,7 @@ nfs-y 			:= client.o dir.o file.o getroot.o inode.o super.o nfs2xdr.o \
 nfs-$(CONFIG_ROOT_NFS)	+= nfsroot.o
 nfs-$(CONFIG_NFS_V3)	+= nfs3proc.o nfs3xdr.o
 nfs-$(CONFIG_NFS_V3_ACL)	+= nfs3acl.o
+nfs-$(CONFIG_NFS_V3_XATTR_API)	+= nfs3xattr.o
 nfs-$(CONFIG_NFS_V4)	+= nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \
 			   delegation.o idmap.o \
 			   callback.o callback_xdr.o callback_proc.o \
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 9bb918a..48fcac9 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -285,9 +285,13 @@ static inline char *nfs_devname(const struct vfsmount *mnt_parent,
 			dentry, buffer, buflen);
 }
 
-/* nfs3acl.c */
+/* nfs3xattr.c */
 extern struct xattr_handler *nfs3_xattr_handlers[];
 
+/* nfs3acl.c */
+extern struct xattr_handler nfs3_xattr_acl_access_handler;
+extern struct xattr_handler nfs3_xattr_acl_default_handler;
+
 /*
  * Determine the actual block size (and log2 thereof)
  */
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c
index c03f8e0..6288ae4 100644
--- a/fs/nfs/nfs3acl.c
+++ b/fs/nfs/nfs3acl.c
@@ -75,7 +75,7 @@ static int nfs3_acl_xattr_set(struct dentry *dentry, const char *name,
 	return error;
 }
 
-static struct xattr_handler nfs3_xattr_acl_access_handler = {
+struct xattr_handler nfs3_xattr_acl_access_handler = {
 	.prefix = POSIX_ACL_XATTR_ACCESS,
 	.flags	= ACL_TYPE_ACCESS,
 	.list   = nfs3_acl_xattr_list,
@@ -83,7 +83,7 @@ static struct xattr_handler nfs3_xattr_acl_access_handler = {
 	.set    = nfs3_acl_xattr_set,
 };
 
-static struct xattr_handler nfs3_xattr_acl_default_handler = {
+struct xattr_handler nfs3_xattr_acl_default_handler = {
 	.prefix = POSIX_ACL_XATTR_DEFAULT,
 	.flags	= ACL_TYPE_DEFAULT,
 	.list   = nfs3_acl_xattr_list,
@@ -91,12 +91,6 @@ static struct xattr_handler nfs3_xattr_acl_default_handler = {
 	.set    = nfs3_acl_xattr_set,
 };
 
-struct xattr_handler *nfs3_xattr_handlers[] = {
-	&nfs3_xattr_acl_access_handler,
-	&nfs3_xattr_acl_default_handler,
-	NULL
-};
-
 static void __nfs3_forget_cached_acls(struct nfs_inode *nfsi)
 {
 	if (!IS_ERR(nfsi->acl_access)) {
diff --git a/fs/nfs/nfs3xattr.c b/fs/nfs/nfs3xattr.c
new file mode 100644
index 0000000..de69f1e
--- /dev/null
+++ b/fs/nfs/nfs3xattr.c
@@ -0,0 +1,25 @@
+/*
+ * Extended attribute (xattr) API and protocol for NFSv3.
+ *
+ * Copyright (C) 2009 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ */
+#include <linux/fs.h>
+#include <linux/nfs.h>
+#include <linux/nfs3.h>
+#include <linux/nfs_fs.h>
+
+#include "internal.h"
+
+#define NFSDBG_FACILITY	NFSDBG_PROC
+
+struct xattr_handler *nfs3_xattr_handlers[] = {
+#ifdef CONFIG_NFS_V3_ACL
+	&nfs3_xattr_acl_access_handler,
+	&nfs3_xattr_acl_default_handler,
+#endif
+	NULL
+};
-- 
1.6.3.3


-- 
James Morris
<jmorris@namei.org>

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* Subject: [PATCH 3/5] NFSv3: add client implementation of XATTR protocol
       [not found] ` <alpine.LRH.2.00.1002261457420.25193-CK9fWmtY32x9JUWOpEiw7w@public.gmane.org>
@ 2010-02-26  4:36   ` James Morris
  0 siblings, 0 replies; 39+ messages in thread
From: James Morris @ 2010-02-26  4:36 UTC (permalink / raw)
  To: linux-nfs
  Cc: linux-security-module, Trond Myklebust, J. Bruce Fields, Neil Brown

Add client support for the Linux NFSv3 extended attribute
side protocol (XATTR).

This extends Linux extended attributes over the network to
servers which support the protocol.

Operation is currently limited to the user.* namespace.

Signed-off-by: James Morris <jmorris@namei.org>
---
 fs/nfs/Kconfig            |   32 ++++++
 fs/nfs/Makefile           |    1 +
 fs/nfs/client.c           |   51 ++++++++++-
 fs/nfs/internal.h         |   11 ++
 fs/nfs/nfs3xattr.c        |  239 +++++++++++++++++++++++++++++++++++++++++++++
 fs/nfs/nfs3xattr_user.c   |   52 ++++++++++
 fs/nfs/nfs3xdr.c          |  187 +++++++++++++++++++++++++++++++++++
 include/linux/nfs_fs_sb.h |    3 +-
 include/linux/nfs_mount.h |    3 +
 include/linux/nfs_xattr.h |   21 ++++
 include/linux/nfs_xdr.h   |   45 +++++++++
 11 files changed, 643 insertions(+), 2 deletions(-)
 create mode 100644 fs/nfs/nfs3xattr_user.c
 create mode 100644 include/linux/nfs_xattr.h

diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig
index d27a88e..e0e2535 100644
--- a/fs/nfs/Kconfig
+++ b/fs/nfs/Kconfig
@@ -64,6 +64,38 @@ config NFS_V3_ACL
 
 	  If unsure, say N.
 
+config NFS_V3_XATTR
+	bool "NFS client support for the NFSv3 XATTR protocol extension (EXPERIMENTAL)"
+	depends on NFS_V3 && EXPERIMENTAL
+	select NFS_V3_XATTR_API
+	help
+	  This option selects client suport for the Linux NFSv3 extended
+	  attribute protocol extension (XATTR).
+
+	  This is a side-protocol which extends general support for Linux
+	  extended attributes over the network, and is based on the GPLd
+	  IRIX implmentation (although not wire-compatible with it).
+
+	  Only the user.* namespace is currently supported.  When connected
+	  to a server which also supports XATTR, the full range of extended
+	  attribute system calls:
+
+	    getxattr(2), listxattr(2), setxattr(2) and removexattr(2)
+
+	  should work as expected.
+
+	  If unsure, say N.
+
+config NFS_V3_XATTR_USER
+	bool "Extended attributes in the user namespace (EXPERIMENTAL)"
+	depends on NFS_V3_XATTR
+	help
+	  This option selects extended attributes in the user.* namespace,
+	  which are arbitrarily named and managed by users, and conveyed
+	  via the XATTR protocol extension for NFS version 3.
+
+	  If unsure, say N.
+
 config NFS_V4
 	bool "NFS client support for NFS version 4 (EXPERIMENTAL)"
 	depends on NFS_FS && EXPERIMENTAL
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile
index 1e2743e..54018ee 100644
--- a/fs/nfs/Makefile
+++ b/fs/nfs/Makefile
@@ -12,6 +12,7 @@ nfs-$(CONFIG_ROOT_NFS)	+= nfsroot.o
 nfs-$(CONFIG_NFS_V3)	+= nfs3proc.o nfs3xdr.o
 nfs-$(CONFIG_NFS_V3_ACL)	+= nfs3acl.o
 nfs-$(CONFIG_NFS_V3_XATTR_API)	+= nfs3xattr.o
+nfs-$(CONFIG_NFS_V3_XATTR_USER)	+= nfs3xattr_user.o
 nfs-$(CONFIG_NFS_V4)	+= nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \
 			   delegation.o idmap.o \
 			   callback.o callback_xdr.o callback_proc.o \
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index ee77713..6be7f19 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -97,6 +97,21 @@ struct rpc_program		nfsacl_program = {
 };
 #endif  /* CONFIG_NFS_V3_ACL */
 
+#ifdef CONFIG_NFS_V3_XATTR
+static struct rpc_stat		nfs_xattr_rpcstat = { &nfs_xattr_program };
+static struct rpc_version *	nfs_xattr_version[] = {
+	[3]			= &nfs_xattr_version3,
+};
+
+struct rpc_program		nfs_xattr_program = {
+	.name			= "nfsxattr",
+	.number			= NFS_XATTR_PROGRAM,
+	.nrvers			= ARRAY_SIZE(nfs_xattr_version),
+	.version		= nfs_xattr_version,
+	.stats			= &nfs_xattr_rpcstat,
+};
+#endif  /* CONFIG_NFS_V3_XATTR */
+
 struct nfs_client_initdata {
 	const char *hostname;
 	const struct sockaddr *addr;
@@ -706,6 +721,36 @@ static inline void nfs_init_server_aclclient(struct nfs_server *server)
 #endif
 
 /*
+ * Initialise an NFSv3 XATTR client connection
+ */
+#ifdef CONFIG_NFS_V3_XATTR
+static void nfs_init_server_xattrclient(struct nfs_server *server)
+{
+	if (server->nfs_client->rpc_ops->version != 3)
+		goto out_no_xattr;
+	if (server->flags & NFS_MOUNT_NOXATTR)
+		goto out_no_xattr;
+
+	server->client_xattr = rpc_bind_new_program(server->client, &nfs_xattr_program, 3);
+	if (IS_ERR(server->client_xattr))
+		goto out_no_xattr;
+
+	/* No errors! Assume that XATTR is supported */
+	server->caps |= NFS_CAP_XATTR;
+	return;
+
+out_no_xattr:
+	server->caps &= ~NFS_CAP_XATTR;
+}
+#else
+static inline void nfs_init_server_xattrclient(struct nfs_server *server)
+{
+	server->flags &= ~NFS_MOUNT_NOXATTR;
+	server->caps &= ~NFS_CAP_XATTR;
+}
+#endif
+
+/*
  * Create a general RPC client
  */
 static int nfs_init_server_rpcclient(struct nfs_server *server,
@@ -851,8 +896,12 @@ static int nfs_init_server(struct nfs_server *server,
 	server->mountd_protocol = data->mount_server.protocol;
 
 	server->namelen  = data->namlen;
-	/* Create a client RPC handle for the NFSv3 ACL management interface */
+	/*
+	 * Create client RPC handles for the NFSv3 ACL and XATTR management
+	 * interfaces
+	 */
 	nfs_init_server_aclclient(server);
+	nfs_init_server_xattrclient(server);
 	dprintk("<-- nfs_init_server() = 0 [new %p]\n", clp);
 	return 0;
 
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 48fcac9..3661a64 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -288,6 +288,17 @@ static inline char *nfs_devname(const struct vfsmount *mnt_parent,
 /* nfs3xattr.c */
 extern struct xattr_handler *nfs3_xattr_handlers[];
 
+extern int nfs3_proc_getxattr(struct inode *inode, const char *namespace,
+			      const char *name, void *value, size_t size);
+extern int nfs3_proc_setxattr(struct inode *inode, const char *namespace,
+			      const char *name, const void *value,
+			      size_t size, int flags);
+extern int nfs3_proc_listxattr(struct inode *inode, char *list,
+			       size_t list_len);
+
+/* nfs3xattr_user.c */
+extern struct xattr_handler nfs3_xattr_user_handler;
+
 /* nfs3acl.c */
 extern struct xattr_handler nfs3_xattr_acl_access_handler;
 extern struct xattr_handler nfs3_xattr_acl_default_handler;
diff --git a/fs/nfs/nfs3xattr.c b/fs/nfs/nfs3xattr.c
index de69f1e..7ff651b 100644
--- a/fs/nfs/nfs3xattr.c
+++ b/fs/nfs/nfs3xattr.c
@@ -1,6 +1,8 @@
 /*
  * Extended attribute (xattr) API and protocol for NFSv3.
  *
+ * Based on the ACL code.
+ *
  * Copyright (C) 2009 Red Hat, Inc., James Morris <jmorris@redhat.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -17,9 +19,246 @@
 #define NFSDBG_FACILITY	NFSDBG_PROC
 
 struct xattr_handler *nfs3_xattr_handlers[] = {
+#ifdef CONFIG_NFS_V3_XATTR_USER
+	&nfs3_xattr_user_handler,
+#endif
 #ifdef CONFIG_NFS_V3_ACL
 	&nfs3_xattr_acl_access_handler,
 	&nfs3_xattr_acl_default_handler,
 #endif
 	NULL
 };
+
+#ifdef CONFIG_NFS_V3_XATTR
+/*
+ * XATTR protocol
+ */
+
+/*
+ * Call GETXATTR
+ *
+ * FIXME:
+ * - Cache xattrs
+ * - Handle size probing
+ */
+int nfs3_proc_getxattr(struct inode *inode, const char *namespace,
+		       const char *name, void *value, size_t size)
+{
+	int status;
+	struct nfs_fattr fattr;
+	struct nfs_server *server = NFS_SERVER(inode);
+	struct nfs3_getxattrargs args = {
+		.fh		= NFS_FH(inode),
+	};
+	struct nfs3_getxattrres res = {
+		.fattr		= &fattr,
+	};
+	struct rpc_message msg = {
+		.rpc_argp	= &args,
+		.rpc_resp	= &res,
+	};
+
+	if (!name || !*name)
+		return -EINVAL;
+
+	if (size > XATTR_SIZE_MAX)
+		return -EINVAL;
+
+	if (!nfs_server_capable(inode, NFS_CAP_XATTR))
+		return -EOPNOTSUPP;
+
+	status = nfs_revalidate_inode(server, inode);
+	if (status < 0)
+		return status;
+
+	/*
+	 * Applications usually first probe the xattr value size, then
+	 * perform a full call.  For now, just return a dummy value.
+	 */
+	if (!size || !value)
+		return 4096;
+
+	args.xattr_namespace = namespace;
+	args.xattr_name = name;
+	args.xattr_size_max = size;
+
+	/*
+	 * FIXME
+	 *
+	 * This is ugly.  We pre-allocate a buffer for the XDR layer to use,
+	 * passing the size of the buffer via xattr_val_len, which is
+	 * updated with the actual length decoded.  We should investigate
+	 * using the page-based interface used by ACLs and others, or some
+	 * other better way.
+	 */
+	res.xattr_val_len = size;
+	res.xattr_val = kmalloc(size, GFP_KERNEL);
+	if (!res.xattr_val)
+		return -ENOMEM;
+
+	dprintk("NFS call getxattr %s%s %zd\n", namespace, name, size);
+
+	msg.rpc_proc = &server->client_xattr->cl_procinfo[XATTRPROC3_GETXATTR];
+	nfs_fattr_init(&fattr);
+	status = rpc_call_sync(server->client_xattr, &msg, 0);
+
+	dprintk("NFS reply getxattr: status=%d len=%d\n",
+		status, res.xattr_val_len);
+
+	switch (status) {
+	case 0:
+		status = nfs_refresh_inode(inode, &fattr);
+		break;
+	case -EPFNOSUPPORT:
+	case -EPROTONOSUPPORT:
+		dprintk("NFS_V3_XATTR extension not supported; disabling\n");
+		server->caps &= ~NFS_CAP_XATTR;
+	case -ENOTSUPP:
+		status = -EOPNOTSUPP;
+	default:
+		goto cleanup;
+	}
+
+	status = res.xattr_val_len;
+	if (status <= size)
+		memcpy(value, res.xattr_val, status);
+
+cleanup:
+	kfree(res.xattr_val);
+	return status;
+}
+
+/*
+ * Call SETXATTR or RMXATTR
+ *
+ * RMXATTR is invoked with a NULL buffer and XATTR_REPLACE.
+ *
+ */
+int nfs3_proc_setxattr(struct inode *inode, const char *namespace,
+		       const char *name, const void *value,
+		       size_t size, int flags)
+
+{
+	int status;
+	struct nfs_fattr fattr;
+	struct nfs_server *server = NFS_SERVER(inode);
+	struct nfs3_setxattrargs args = {
+		.fh		= NFS_FH(inode),
+	};
+	struct nfs3_setxattrres res = {
+		.fattr		= &fattr,
+	};
+	struct rpc_message msg = {
+		.rpc_argp	= &args,
+		.rpc_resp	= &res,
+	};
+
+	if (!name || !*name)
+		return -EINVAL;
+
+	if (!nfs_server_capable(inode, NFS_CAP_XATTR))
+		return -EOPNOTSUPP;
+
+	status = nfs_revalidate_inode(server, inode);
+	if (status < 0)
+		return status;
+
+	args.xattr_namespace = namespace;
+	args.xattr_name = name;
+	args.xattr_flags = flags;
+	args.xattr_val = value;
+	args.xattr_val_len = size;
+
+	dprintk("NFS call setxattr %s%s %zd 0x%08x\n",
+		namespace, name, size, flags);
+
+	msg.rpc_proc = &server->client_xattr->cl_procinfo[XATTRPROC3_SETXATTR];
+	nfs_fattr_init(&fattr);
+	status = rpc_call_sync(server->client_xattr, &msg, 0);
+
+	dprintk("NFS reply setxattr: status=%d\n", status);
+
+	switch (status) {
+	case 0:
+		status = nfs_refresh_inode(inode, &fattr);
+		break;
+	case -EPFNOSUPPORT:
+	case -EPROTONOSUPPORT:
+		dprintk("NFS_V3_XATTR extension not supported; disabling\n");
+		server->caps &= ~NFS_CAP_XATTR;
+	case -ENOTSUPP:
+		status = -EOPNOTSUPP;
+	default:
+		break;
+	}
+	return status;
+}
+
+/*
+ * Call LISTXATTR
+ */
+int nfs3_proc_listxattr(struct inode *inode, char *list, size_t list_len)
+{
+	int status;
+	struct nfs_fattr fattr;
+	struct nfs_server *server = NFS_SERVER(inode);
+	struct nfs3_listxattrargs args = {
+		.fh		= NFS_FH(inode),
+	};
+	struct nfs3_listxattrres res = {
+		.fattr		= &fattr,
+	};
+	struct rpc_message msg = {
+		.rpc_argp	= &args,
+		.rpc_resp	= &res,
+	};
+
+	if (list_len > XATTR_LIST_MAX)
+		return -EINVAL;
+
+	if (!nfs_server_capable(inode, NFS_CAP_XATTR))
+		return -EOPNOTSUPP;
+
+	dprintk("NFS call listxattr %zd\n", list_len);
+
+	/* FIXME: handle probes */
+	if (!list || !list_len)
+		return 1024;
+
+	args.xattr_list_max = list_len;
+
+	/* FIXME (see comments for getxattr) */
+	res.xattr_list_len = list_len;
+	res.xattr_list = kmalloc(list_len, GFP_KERNEL);
+	if (!res.xattr_list)
+		return -ENOMEM;
+
+	msg.rpc_proc = &server->client_xattr->cl_procinfo[XATTRPROC3_LISTXATTR];
+	nfs_fattr_init(&fattr);
+	status = rpc_call_sync(server->client_xattr, &msg, 0);
+
+	dprintk("NFS reply listxattr: status=%d\n", status);
+
+	switch (status) {
+	case 0:
+		status = nfs_refresh_inode(inode, &fattr);
+		break;
+	case -EPFNOSUPPORT:
+	case -EPROTONOSUPPORT:
+		dprintk("NFS_V3_XATTR extension not supported; disabling\n");
+		server->caps &= ~NFS_CAP_XATTR;
+	case -ENOTSUPP:
+		status = -EOPNOTSUPP;
+	default:
+		goto cleanup;
+	}
+
+	status = res.xattr_list_len;
+	if (status <= list_len)
+		memcpy(list, res.xattr_list, status);
+
+cleanup:
+	kfree(res.xattr_list);
+	return status;
+}
+#endif	/* CONFIG_NFS_V3_XATTR */
diff --git a/fs/nfs/nfs3xattr_user.c b/fs/nfs/nfs3xattr_user.c
new file mode 100644
index 0000000..61ae019
--- /dev/null
+++ b/fs/nfs/nfs3xattr_user.c
@@ -0,0 +1,52 @@
+/*
+ * Support for extended attributes in the the user.* namespace, which are
+ * arbitrarily named and managed by users and conveyed via the XATTR
+ * protocol extension.
+ *
+ * Copyright (C) 2009 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ */
+#include <linux/fs.h>
+#include <linux/nfs.h>
+#include <linux/nfs3.h>
+#include <linux/nfs_fs.h>
+
+#include "internal.h"
+
+#define NFSDBG_FACILITY	NFSDBG_PROC
+
+/*
+ * The generic xattr code will call this for each helper, which is ok for
+ * now, because we only support this single namespace.  If support is
+ * expanded to more namespaces, we we'll need a custom listxattr operation.
+ */
+static size_t nfs3_user_xattr_list(struct inode *inode, char *list,
+				   size_t list_len, const char *name,
+				   size_t name_len)
+{
+	return nfs3_proc_listxattr(inode, list, list_len);
+}
+
+static int nfs3_user_xattr_get(struct inode *inode, const char *name,
+			       void *buffer, size_t size)
+{
+	return nfs3_proc_getxattr(inode, XATTR_USER_PREFIX,
+				  name, buffer, size);
+}
+
+static int nfs3_user_xattr_set(struct inode *inode, const char *name,
+			       const void *value, size_t size, int flags)
+{
+	return nfs3_proc_setxattr(inode, XATTR_USER_PREFIX,
+				  name, value, size, flags);
+}
+
+struct xattr_handler nfs3_xattr_user_handler = {
+	.prefix = XATTR_USER_PREFIX,
+	.list   = nfs3_user_xattr_list,
+	.get    = nfs3_user_xattr_get,
+	.set    = nfs3_user_xattr_set,
+};
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
index 5fe5492..1552e6e 100644
--- a/fs/nfs/nfs3xdr.c
+++ b/fs/nfs/nfs3xdr.c
@@ -88,6 +88,26 @@
 #define ACL3_setaclres_sz	(1+NFS3_post_op_attr_sz)
 
 /*
+ * FIXME: currently, the RPC layer will allocate the maximum buffer size
+ * here for each call (which can be ~ 64k).  The Labeled NFS prototype code
+ * uses 4k, although we should not impose limits for NFS which don't exist
+ * in the OS unless absolutely necsssary.  We likely need a dynamic scheme
+ * here, possibly using pages.
+ */
+#define XATTR3_xattrname_sz	(1+(XATTR_NAME_MAX>>2))
+#define XATTR3_xattrval_sz	(1+(XATTR_SIZE_MAX>>2))
+#define XATTR3_xattrlist_sz	(1+(XATTR_LIST_MAX>>2))
+
+#define XATTR3_getxattrargs_sz	(NFS3_fh_sz+XATTR3_xattrname_sz+1)
+#define XATTR3_getxattrres_sz	(1+NFS3_post_op_attr_sz+XATTR3_xattrval_sz)
+
+#define XATTR3_setxattrargs_sz	(NFS3_fh_sz+XATTR3_xattrname_sz+XATTR3_xattrval_sz+1)
+#define XATTR3_setxattrres_sz	(1+NFS3_post_op_attr_sz)
+
+#define XATTR3_listxattrargs_sz	(NFS3_fh_sz+1)
+#define XATTR3_listxattrres_sz	(1+NFS3_post_op_attr_sz+XATTR3_xattrlist_sz)
+
+/*
  * Map file type to S_IFMT bits
  */
 static const umode_t nfs_type2fmt[] = {
@@ -727,6 +747,72 @@ nfs3_xdr_setaclargs(struct rpc_rqst *req, __be32 *p,
 }
 #endif  /* CONFIG_NFS_V3_ACL */
 
+#ifdef CONFIG_NFS_V3_XATTR
+/*
+ * Special case of xdr_encode_opaque, where the xattr helpers hand us
+ * separate namespace and name buffers, which we encode as a single XDR
+ * string over the wire.  Neither namespace nor name may be empty or null.
+ */
+static __be32 *xattr_encode_name(__be32 *p, const char *namespace, const char *name)
+{
+	unsigned int nslen, namelen, totlen, quadlen, padding;
+
+	nslen = strlen(namespace);
+	namelen = strlen(name);
+	totlen = nslen + namelen;
+	quadlen = XDR_QUADLEN(totlen);
+	padding = (quadlen << 2) - totlen;
+
+	*p++ = cpu_to_be32(totlen);
+	memcpy(p, namespace, nslen);
+	memcpy((char *)p + nslen, name, namelen);
+
+	if (padding != 0)
+		memset((char *)p + totlen, 0, padding);
+	p += quadlen;
+	return p;
+}
+
+/*
+ * Encode GETXATTR arguments
+ */
+static int nfs3_xdr_getxattrargs(struct rpc_rqst *req, __be32 *p,
+				 struct nfs3_getxattrargs *args)
+{
+	p = xdr_encode_fhandle(p, args->fh);
+	p = xattr_encode_name(p, args->xattr_namespace, args->xattr_name);
+	*p++ = htonl(args->xattr_size_max);
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	return 0;
+}
+
+/*
+ * Encode SETXATTR arguments
+ */
+static int nfs3_xdr_setxattrargs(struct rpc_rqst *req, __be32 *p,
+				 struct nfs3_setxattrargs *args)
+{
+	p = xdr_encode_fhandle(p, args->fh);
+	p = xattr_encode_name(p, args->xattr_namespace, args->xattr_name);
+	p = xdr_encode_array(p, args->xattr_val, args->xattr_val_len);
+	*p++ = htonl(args->xattr_flags);
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	return 0;
+}
+
+/*
+ * Encode LISTXATTR arguments
+ */
+static int nfs3_xdr_listxattrargs(struct rpc_rqst *req, __be32 *p,
+				  struct nfs3_listxattrargs *args)
+{
+	p = xdr_encode_fhandle(p, args->fh);
+	*p++ = htonl(args->xattr_list_max);
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	return 0;
+}
+#endif	/* CONFIG_NFS_V3_XATTR */
+
 /*
  * NFS XDR decode functions
  */
@@ -1136,6 +1222,69 @@ nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
 }
 #endif  /* CONFIG_NFS_V3_ACL */
 
+#ifdef CONFIG_NFS_V3_XATTR
+/*
+ * Decode GETXATTR reply
+ *
+ * FIXME: determine appropriate error returns
+ */
+static int nfs3_xdr_getxattrres(struct rpc_rqst *req, __be32 *p,
+				struct nfs3_getxattrres *res)
+{
+	char *xattr_val;
+	unsigned int xattr_max_size = res->xattr_val_len;
+	int status = ntohl(*p++);
+
+	if (status != 0)
+		return nfs_stat_to_errno(status);
+
+	p = xdr_decode_post_op_attr(p, res->fattr);
+	p = xdr_decode_string_inplace(p, &xattr_val,
+	                              &res->xattr_val_len,
+	                              xattr_max_size);
+	if (p == NULL)
+		return -EINVAL;
+	memcpy(res->xattr_val, xattr_val, res->xattr_val_len);
+	return 0;
+}
+
+/*
+ * Decode SETXATTR reply
+ */
+static int nfs3_xdr_setxattrres(struct rpc_rqst *req, __be32 *p,
+				struct nfs3_setxattrres *res)
+{
+	int status = ntohl(*p++);
+
+	if (status)
+		return nfs_stat_to_errno(status);
+	xdr_decode_post_op_attr(p, res->fattr);
+	return 0;
+}
+
+/*
+ * Decode LISTXATTR reply
+ */
+static int nfs3_xdr_listxattrres(struct rpc_rqst *req, __be32 *p,
+				 struct nfs3_listxattrres *res)
+{
+	char *xattr_list;
+	unsigned int size = res->xattr_list_len;
+	int status = ntohl(*p++);
+
+	if (status != 0)
+		return nfs_stat_to_errno(status);
+
+	p = xdr_decode_post_op_attr(p, res->fattr);
+	p = xdr_decode_string_inplace(p, &xattr_list,
+	                              &res->xattr_list_len, size);
+	if (p == NULL)
+		return -EINVAL;
+	memcpy(res->xattr_list, xattr_list, res->xattr_list_len);
+	return 0;
+}
+#endif	/* CONFIG_NFS_V3_XATTR */
+
 #define PROC(proc, argtype, restype, timer)				\
 [NFS3PROC_##proc] = {							\
 	.p_proc      = NFS3PROC_##proc,					\
@@ -1207,3 +1356,41 @@ struct rpc_version		nfsacl_version3 = {
 	.procs			= nfs3_acl_procedures,
 };
 #endif  /* CONFIG_NFS_V3_ACL */
+
+#ifdef CONFIG_NFS_V3_XATTR
+static struct rpc_procinfo	nfs3_xattr_procedures[] = {
+	[XATTRPROC3_GETXATTR] = {
+		.p_proc		= XATTRPROC3_GETXATTR,
+		.p_encode	= (kxdrproc_t) nfs3_xdr_getxattrargs,
+		.p_decode	= (kxdrproc_t) nfs3_xdr_getxattrres,
+		.p_arglen	= XATTR3_getxattrargs_sz,
+		.p_replen	= XATTR3_getxattrres_sz,
+		.p_timer	= 1,
+		.p_name		= "GETXATTR",
+	},
+	[XATTRPROC3_SETXATTR] = {
+		.p_proc		= XATTRPROC3_SETXATTR,
+		.p_encode	= (kxdrproc_t) nfs3_xdr_setxattrargs,
+		.p_decode	= (kxdrproc_t) nfs3_xdr_setxattrres,
+		.p_arglen	= XATTR3_setxattrargs_sz,
+		.p_replen	= XATTR3_setxattrres_sz,
+		.p_timer	= 1,
+		.p_name		= "SETXATTR",
+	},
+	[XATTRPROC3_LISTXATTR] = {
+		.p_proc		= XATTRPROC3_LISTXATTR,
+		.p_encode	= (kxdrproc_t) nfs3_xdr_listxattrargs,
+		.p_decode	= (kxdrproc_t) nfs3_xdr_listxattrres,
+		.p_arglen	= XATTR3_listxattrargs_sz,
+		.p_replen	= XATTR3_listxattrres_sz,
+		.p_timer	= 1,
+		.p_name		= "LISTXATTR",
+	},
+};
+
+struct rpc_version		nfs_xattr_version3 = {
+	.number			= 3,
+	.nrprocs		= ARRAY_SIZE(nfs3_xattr_procedures),
+	.procs			= nfs3_xattr_procedures,
+};
+#endif	/* CONFIG_NFS_V3_XATTR */
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index 34fc6be..c881ac4 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -104,6 +104,7 @@ struct nfs_server {
 	struct list_head	master_link;	/* link in master servers list */
 	struct rpc_clnt *	client;		/* RPC client handle */
 	struct rpc_clnt *	client_acl;	/* ACL RPC client handle */
+	struct rpc_clnt *	client_xattr;	/* XATTR RPC client handle */
 	struct nlm_host		*nlm_host;	/* NLM client handle */
 	struct nfs_iostats *	io_stats;	/* I/O statistics */
 	struct backing_dev_info	backing_dev_info;
@@ -176,7 +177,7 @@ struct nfs_server {
 #define NFS_CAP_ATIME		(1U << 11)
 #define NFS_CAP_CTIME		(1U << 12)
 #define NFS_CAP_MTIME		(1U << 13)
-
+#define NFS_CAP_XATTR		(1U << 14)
 
 /* maximum number of slots to use */
 #define NFS4_MAX_SLOT_TABLE RPC_MAX_SLOT_TABLE
diff --git a/include/linux/nfs_mount.h b/include/linux/nfs_mount.h
index 4499016..04bb4ee 100644
--- a/include/linux/nfs_mount.h
+++ b/include/linux/nfs_mount.h
@@ -70,4 +70,7 @@ struct nfs_mount_data {
 #define NFS_MOUNT_LOOKUP_CACHE_NONE	0x20000
 #define NFS_MOUNT_NORESVPORT		0x40000
 
+/* FIXME: determine semantics and modify flagmask if exposed to userland */
+#define NFS_MOUNT_NOXATTR		0x80000
+
 #endif
diff --git a/include/linux/nfs_xattr.h b/include/linux/nfs_xattr.h
new file mode 100644
index 0000000..98fdbed
--- /dev/null
+++ b/include/linux/nfs_xattr.h
@@ -0,0 +1,21 @@
+/*
+ * Extended attribute protocol for NFSv3 (XATTR)
+ *
+ *
+ * Copyright (C) 2009 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ *
+ */
+#ifndef __LINUX_NFS_XATTR_H
+#define __LINUX_NFS_XATTR_H
+
+#include <linux/xattr.h>
+
+#define NFS_XATTR_PROGRAM	391063	/* TODO: find another value */
+
+/* xattr procedure numbers */
+#define XATTRPROC3_GETXATTR	1
+#define XATTRPROC3_SETXATTR	2
+#define XATTRPROC3_LISTXATTR	3
+#define XATTRPROC3_RMXATTR	4
+
+#endif  /* __LINUX_NFS_XATTR_H */
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 89b2881..5e79744 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -2,6 +2,7 @@
 #define _LINUX_NFS_XDR_H
 
 #include <linux/nfsacl.h>
+#include <linux/nfs_xattr.h>
 #include <linux/nfs3.h>
 
 /*
@@ -514,6 +515,27 @@ struct nfs3_setaclargs {
 	struct page **		pages;
 };
 
+struct nfs3_getxattrargs {
+	struct nfs_fh *		fh;
+	const char *		xattr_namespace;
+	const char *		xattr_name;
+	unsigned int		xattr_size_max;
+};
+
+struct nfs3_setxattrargs {
+	struct nfs_fh *		fh;
+	unsigned int		xattr_flags;
+	const char *		xattr_namespace;
+	const char *		xattr_name;
+	const char *		xattr_val;
+	int			xattr_val_len;
+};
+
+struct nfs3_listxattrargs {
+	struct nfs_fh *		fh;
+	unsigned int		xattr_list_max;
+};
+
 struct nfs_diropok {
 	struct nfs_fh *		fh;
 	struct nfs_fattr *	fattr;
@@ -646,6 +668,26 @@ struct nfs3_getaclres {
 	struct posix_acl *	acl_default;
 };
 
+struct nfs3_getxattrres {
+	struct nfs_fattr *	fattr;
+	char *			xattr_val;
+	int			xattr_val_len;
+};
+
+/*
+ * Note: if we don't add any more fields, we can get rid of this struct and
+ * just use fattr in the calling code.
+ */
+struct nfs3_setxattrres {
+	struct nfs_fattr *	fattr;
+};
+
+struct nfs3_listxattrres {
+	struct nfs_fattr *	fattr;
+	char *			xattr_list;
+	int			xattr_list_len;
+};
+
 #ifdef CONFIG_NFS_V4
 
 typedef u64 clientid4;
@@ -1074,4 +1116,7 @@ extern struct rpc_version	nfs_version4;
 extern struct rpc_version	nfsacl_version3;
 extern struct rpc_program	nfsacl_program;
 
+extern struct rpc_version	nfs_xattr_version3;
+extern struct rpc_program	nfs_xattr_program;
+
 #endif
-- 
1.6.3.3


-- 
James Morris
<jmorris@namei.org>

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 4/5] NFSv3: add server implementation of XATTR protocol
  2010-02-26  4:33 [PATCH 0/5][v3][RFC] NFSv3: implement extended attribute protocol (XATTR) James Morris
                   ` (2 preceding siblings ...)
       [not found] ` <alpine.LRH.2.00.1002261457420.25193-CK9fWmtY32x9JUWOpEiw7w@public.gmane.org>
@ 2010-02-26  4:36 ` James Morris
  2010-02-26  4:37 ` [PATCH 5/5] NFSv3: Add server namespace support for XATTR protocol implementation James Morris
  2010-03-08 10:42 ` [PATCH 0/6][v4][RFC] NFSv3: implement extended attribute protocol (XATTR) James Morris
  5 siblings, 0 replies; 39+ messages in thread
From: James Morris @ 2010-02-26  4:36 UTC (permalink / raw)
  To: linux-nfs
  Cc: linux-security-module, Trond Myklebust, J. Bruce Fields, Neil Brown

Add server support for the Linux NFSv3 extended attribute
side protocol (XATTR).

Signed-off-by: James Morris <jmorris@namei.org>
---
 fs/nfs/nfs3xattr_user.c    |   19 ++-
 fs/nfsd/Kconfig            |    8 +
 fs/nfsd/Makefile           |    1 +
 fs/nfsd/nfs3xattr.c        |  354 ++++++++++++++++++++++++++++++++++++++++++++
 fs/nfsd/nfsctl.c           |    3 +
 fs/nfsd/nfssvc.c           |   60 +++++++-
 fs/nfsd/vfs.c              |    5 +-
 fs/nfsd/vfs.h              |   13 ++
 fs/nfsd/xdr3.h             |   46 ++++++
 include/linux/sunrpc/svc.h |    2 +-
 10 files changed, 496 insertions(+), 15 deletions(-)
 create mode 100644 fs/nfsd/nfs3xattr.c

diff --git a/fs/nfs/nfs3xattr_user.c b/fs/nfs/nfs3xattr_user.c
index 61ae019..c544fcb 100644
--- a/fs/nfs/nfs3xattr_user.c
+++ b/fs/nfs/nfs3xattr_user.c
@@ -23,24 +23,25 @@
  * now, because we only support this single namespace.  If support is
  * expanded to more namespaces, we we'll need a custom listxattr operation.
  */
-static size_t nfs3_user_xattr_list(struct inode *inode, char *list,
+static size_t nfs3_user_xattr_list(struct dentry *dentry, char *list,
 				   size_t list_len, const char *name,
-				   size_t name_len)
+				   size_t name_len, int hflags)
 {
-	return nfs3_proc_listxattr(inode, list, list_len);
+	return nfs3_proc_listxattr(dentry->d_inode, list, list_len);
 }
 
-static int nfs3_user_xattr_get(struct inode *inode, const char *name,
-			       void *buffer, size_t size)
+static int nfs3_user_xattr_get(struct dentry *dentry, const char *name,
+			       void *buffer, size_t size, int hflags)
 {
-	return nfs3_proc_getxattr(inode, XATTR_USER_PREFIX,
+	return nfs3_proc_getxattr(dentry->d_inode, XATTR_USER_PREFIX,
 				  name, buffer, size);
 }
 
-static int nfs3_user_xattr_set(struct inode *inode, const char *name,
-			       const void *value, size_t size, int flags)
+static int nfs3_user_xattr_set(struct dentry *dentry, const char *name,
+			       const void *value, size_t size,
+			       int flags, int hflags)
 {
-	return nfs3_proc_setxattr(inode, XATTR_USER_PREFIX,
+	return nfs3_proc_setxattr(dentry->d_inode, XATTR_USER_PREFIX,
 				  name, value, size, flags);
 }
 
diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig
index 503b9da..4252d16 100644
--- a/fs/nfsd/Kconfig
+++ b/fs/nfsd/Kconfig
@@ -64,6 +64,14 @@ config NFSD_V3_ACL
 
 	  If unsure, say N.
 
+config NFSD_V3_XATTR
+	bool "NFS server support for the NFSv3 XATTR protocol extension (EXPERIMENTAL)"
+	depends on NFSD_V3 && EXPERIMENTAL
+	help
+	  NFS server support for the NFSv3 XATTR protocol.
+
+	  If unsure, say N.
+
 config NFSD_V4
 	bool "NFS server support for NFS version 4 (EXPERIMENTAL)"
 	depends on NFSD && PROC_FS && EXPERIMENTAL
diff --git a/fs/nfsd/Makefile b/fs/nfsd/Makefile
index 9b118ee..e206b52 100644
--- a/fs/nfsd/Makefile
+++ b/fs/nfsd/Makefile
@@ -9,5 +9,6 @@ nfsd-y 			:= nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \
 nfsd-$(CONFIG_NFSD_V2_ACL) += nfs2acl.o
 nfsd-$(CONFIG_NFSD_V3)	+= nfs3proc.o nfs3xdr.o
 nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o
+nfsd-$(CONFIG_NFSD_V3_XATTR) += nfs3xattr.o
 nfsd-$(CONFIG_NFSD_V4)	+= nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \
 			   nfs4acl.o nfs4callback.o nfs4recover.o
diff --git a/fs/nfsd/nfs3xattr.c b/fs/nfsd/nfs3xattr.c
new file mode 100644
index 0000000..b5a5faa
--- /dev/null
+++ b/fs/nfsd/nfs3xattr.c
@@ -0,0 +1,354 @@
+/*
+ * Process version 3 NFSXATTR requests.
+ *
+ * Based on the NFSACL code by:
+ * Copyright (C) 2002-2003 Andreas Gruenbacher <agruen@suse.de>
+ *
+ * Copyright (C) 2009 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ */
+#include <linux/sunrpc/svc.h>
+#include <linux/nfs3.h>
+#include <linux/xattr.h>
+#include <linux/nfs_xattr.h>
+
+#include "nfsd.h"
+#include "xdr3.h"
+#include "vfs.h"
+#include "cache.h"
+
+#define NFSDDBG_FACILITY	NFSDDBG_PROC
+#define RETURN_STATUS(st)	{ resp->status = (st); return (st); }
+
+/* NULL call */
+static __be32 nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
+{
+	return nfs_ok;
+}
+
+/*
+ * GETXATTR
+ *
+ * FIXME:
+ *  - Implement shared xattr cache
+ *  - Audit nfs error returns
+ */
+static __be32 nfsd3_proc_getxattr(struct svc_rqst * rqstp,
+				  struct nfsd3_getxattrargs *argp,
+				  struct nfsd3_getxattrres *resp)
+{
+	__be32 nfserr = nfserrno(-EINVAL);
+	svc_fh *fh;
+	void *value;
+	int ret;
+	char *name, *xattr_name = argp->xattr_name;
+	unsigned int size_max = argp->xattr_size_max;
+	unsigned int name_len = argp->xattr_name_len;
+
+	dprintk("nfsd: GETXATTR(3)  %s %.*s %u\n", SVCFH_fmt(&argp->fh),
+	        name_len, xattr_name, size_max);
+
+	if (name_len > XATTR_NAME_MAX)
+		RETURN_STATUS(nfserr);
+
+	if (size_max > XATTR_SIZE_MAX)
+		RETURN_STATUS(nfserr);
+
+	/* Probes must be handled by the client */
+	if (size_max == 0)
+		RETURN_STATUS(nfserr);
+
+	fh = fh_copy(&resp->fh, &argp->fh);
+	nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_READ);
+	if (nfserr)
+		RETURN_STATUS(nfserr);
+
+	/* Convert xdr string to real string */
+	name = kmalloc(name_len + 1, GFP_KERNEL);
+	if (name == NULL)
+		RETURN_STATUS(nfserrno(-ENOMEM));
+
+	ret = snprintf(name, name_len + 1, "%.*s", name_len, xattr_name);
+	if (ret > name_len) {
+		nfserr = nfserrno(-EINVAL);
+		goto cleanup;
+	}
+
+	/* Only the user namespace is currently supported by the server */
+	if (strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) {
+		nfserr = nfserrno(-EINVAL);
+		goto cleanup;
+	}
+
+	ret = nfsd_getxattr(fh->fh_dentry, name, &value);
+	if (ret <= 0) {
+		if (ret == 0)
+			ret = -ENODATA;
+		nfserr = nfserrno(ret);
+		goto cleanup;
+	}
+
+	nfserr = 0;
+	resp->xattr_val = value;
+	resp->xattr_val_len = ret;
+
+cleanup:
+	kfree(name);
+	RETURN_STATUS(nfserr);
+}
+
+/* cribbed from decode pathname */
+static __be32 *decode_xattrname(__be32 *p, char **namp, unsigned int *lenp)
+{
+	char *name;
+	unsigned int i;
+
+	p = xdr_decode_string_inplace(p, namp, lenp, XATTR_NAME_MAX);
+	if (p != NULL)
+		for (i = 0, name = *namp; i < *lenp; i++, name++)
+			if (*name == '\0')
+				return NULL;
+	return p;
+}
+
+static int nfs3svc_decode_getxattrargs(struct svc_rqst *rqstp, __be32 *p,
+				       struct nfsd3_getxattrargs *argp)
+{
+	if (!(p = nfs3svc_decode_fh(p, &argp->fh)))
+		return 0;
+	if (!(p = decode_xattrname(p, &argp->xattr_name, &argp->xattr_name_len)))
+		return 0;
+	argp->xattr_size_max = ntohl(*p++);
+	return xdr_argsize_check(rqstp, p);
+}
+
+static int nfs3svc_encode_getxattrres(struct svc_rqst *rqstp, __be32 *p,
+				      struct nfsd3_getxattrres *resp)
+{
+	p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh);
+	if (resp->status == 0)
+		p = xdr_encode_array(p, resp->xattr_val, resp->xattr_val_len);
+	return xdr_ressize_check(rqstp, p);
+}
+
+static int nfs3svc_release_getxattr(struct svc_rqst *rqstp, __be32 *p,
+				    struct nfsd3_getxattrres *resp)
+{
+	fh_put(&resp->fh);
+	kfree(resp->xattr_val);
+	return 1;
+}
+
+/*
+ * SETXATTR and RMXATTR
+ *
+ * RMXATTR is detected with zero buffer len and XATTR_REPLACE.
+ *
+ */
+static __be32 nfsd3_proc_setxattr(struct svc_rqst * rqstp,
+				  struct nfsd3_setxattrargs *argp,
+				  struct nfsd3_setxattrres *resp)
+{
+	__be32 nfserr = nfserrno(-EINVAL);
+	svc_fh *fh;
+	int ret;
+	char *name, *xattr_name = argp->xattr_name;
+	unsigned int name_len = argp->xattr_name_len;
+	unsigned int val_len = argp->xattr_val_len;
+	unsigned int flags = argp->xattr_flags;
+
+	dprintk("nfsd: SETXATTR(3)  %s %.*s %u %#x\n", SVCFH_fmt(&argp->fh),
+		name_len, xattr_name, val_len, flags);
+
+	if (name_len > XATTR_NAME_MAX)
+		RETURN_STATUS(nfserr);
+
+	if (val_len > XATTR_SIZE_MAX)
+		RETURN_STATUS(nfserr);
+
+	if (flags & ~(XATTR_CREATE|XATTR_REPLACE))
+		RETURN_STATUS(nfserr);
+
+	fh = fh_copy(&resp->fh, &argp->fh);
+	nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR);
+	if (nfserr)
+		RETURN_STATUS(nfserr);
+
+	/* Convert xdr string to real string */
+	name = kmalloc(name_len + 1, GFP_KERNEL);
+	if (name == NULL)
+		RETURN_STATUS(nfserrno(-ENOMEM));
+
+	ret = snprintf(name, name_len + 1, "%.*s", name_len, xattr_name);
+	if (ret > name_len) {
+		nfserr = nfserrno(-EINVAL);
+		goto cleanup;
+	}
+
+	/* Only the user namespace is currently supported by the server */
+	if (strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) {
+		nfserr = nfserrno(-EINVAL);
+		goto cleanup;
+	}
+
+	if (!val_len) {
+		if (flags & ~XATTR_REPLACE) {
+			nfserr = nfserrno(-EINVAL);
+			goto cleanup;
+		}
+		ret = vfs_removexattr(fh->fh_dentry, name);
+	} else
+		ret = vfs_setxattr(fh->fh_dentry, name,
+				   argp->xattr_val, val_len, flags);
+
+	nfserr = nfserrno(ret);
+
+cleanup:
+	kfree(name);
+	RETURN_STATUS(nfserr);
+}
+
+static int nfs3svc_decode_setxattrargs(struct svc_rqst *rqstp, __be32 *p,
+				       struct nfsd3_setxattrargs *argp)
+{
+	if (!(p = nfs3svc_decode_fh(p, &argp->fh)))
+		return 0;
+	if (!(p = decode_xattrname(p, &argp->xattr_name, &argp->xattr_name_len)))
+		return 0;
+	if (!(p = xdr_decode_string_inplace(p, &argp->xattr_val,
+					&argp->xattr_val_len, XATTR_SIZE_MAX)))
+		return 0;
+	argp->xattr_flags = ntohl(*p++);
+	return xdr_argsize_check(rqstp, p);
+}
+
+static int nfs3svc_encode_setxattrres(struct svc_rqst *rqstp, __be32 *p,
+				      struct nfsd3_setxattrres *resp)
+{
+	p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh);
+	return xdr_ressize_check(rqstp, p);
+}
+
+static int nfs3svc_release_setxattr(struct svc_rqst *rqstp, __be32 *p,
+				    struct nfsd3_setxattrres *resp)
+{
+	fh_put(&resp->fh);
+	return 1;
+}
+
+/*
+ * LISTXATTR
+ *
+ * TODO: namespace filtering?
+ */
+static __be32 nfsd3_proc_listxattr(struct svc_rqst * rqstp,
+				   struct nfsd3_listxattrargs *argp,
+				   struct nfsd3_listxattrres *resp)
+{
+	__be32 nfserr = nfserrno(-EINVAL);
+	svc_fh *fh;
+	char *list;
+	int ret;
+	unsigned int list_max = argp->xattr_list_max;
+
+	dprintk("nfsd: LISTXATTR(3)  %s %u\n", SVCFH_fmt(&argp->fh), list_max);
+
+	if (list_max > XATTR_LIST_MAX)
+		RETURN_STATUS(nfserr);
+
+	/* Probes must be handled by the client */
+	if (list_max == 0)
+		RETURN_STATUS(nfserr);
+
+	fh = fh_copy(&resp->fh, &argp->fh);
+	nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_READ);
+	if (nfserr)
+		RETURN_STATUS(nfserr);
+
+	list = kmalloc(list_max, GFP_ATOMIC);
+	if (list == NULL)
+		RETURN_STATUS(nfserrno(-ENOMEM));
+
+	ret = vfs_listxattr(fh->fh_dentry, list, list_max);
+	if (ret <= 0) {
+		if (ret == 0)
+			ret = -ENODATA;
+		RETURN_STATUS(nfserrno(ret));
+	}
+
+	nfserr = 0;
+	resp->xattr_list = list;
+	resp->xattr_list_len = ret;
+
+	RETURN_STATUS(nfserr);
+}
+
+static int nfs3svc_decode_listxattrargs(struct svc_rqst *rqstp, __be32 *p,
+				        struct nfsd3_listxattrargs *argp)
+{
+	if (!(p = nfs3svc_decode_fh(p, &argp->fh)))
+		return 0;
+	argp->xattr_list_max = ntohl(*p++);
+	return xdr_argsize_check(rqstp, p);
+}
+
+static int nfs3svc_encode_listxattrres(struct svc_rqst *rqstp, __be32 *p,
+				       struct nfsd3_listxattrres *resp)
+{
+	p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh);
+	if (resp->status == 0)
+		p = xdr_encode_array(p, resp->xattr_list, resp->xattr_list_len);
+	return xdr_ressize_check(rqstp, p);
+}
+
+static int nfs3svc_release_listxattr(struct svc_rqst *rqstp, __be32 *p,
+				     struct nfsd3_listxattrres *resp)
+{
+	fh_put(&resp->fh);
+	kfree(resp->xattr_list);
+	return 1;
+}
+
+#define ST 1		/* status */
+#define AT 21           /* attributes */
+#define pAT (1+AT)      /* post attributes - conditional */
+
+#define nfs3svc_decode_voidargs		NULL
+#define nfs3svc_release_void		NULL
+#define nfsd3_voidres			nfsd3_voidargs
+struct nfsd3_voidargs { int dummy; };
+
+#define PROC(name, argt, rest, relt, cache, respsize)	\
+ { (svc_procfunc) nfsd3_proc_##name,		\
+   (kxdrproc_t) nfs3svc_decode_##argt##args,	\
+   (kxdrproc_t) nfs3svc_encode_##rest##res,	\
+   (kxdrproc_t) nfs3svc_release_##relt,		\
+   sizeof(struct nfsd3_##argt##args),		\
+   sizeof(struct nfsd3_##rest##res),		\
+   0,						\
+   cache,					\
+   respsize,					\
+ }
+
+#define G_RSZ	(ST+pAT+1+(XATTR_SIZE_MAX>>2))
+#define S_RSZ	(ST+pAT)
+#define L_RSZ	(ST+pAT+1+(XATTR_LIST_MAX>>2))
+
+static struct svc_procedure nfsd_xattr_procedures3[] = {
+  PROC(null,       void,       void,       void,       RC_NOCACHE, ST),
+  PROC(getxattr,   getxattr,   getxattr,   getxattr,   RC_NOCACHE, G_RSZ),
+  PROC(setxattr,   setxattr,   setxattr,   setxattr,   RC_NOCACHE, S_RSZ),
+  PROC(listxattr,  listxattr,  listxattr,  listxattr,  RC_NOCACHE, L_RSZ),
+};
+
+struct svc_version	nfsd_xattr_version3 = {
+	.vs_vers	= 3,
+	.vs_nproc	= 4,
+	.vs_proc	= nfsd_xattr_procedures3,
+	.vs_dispatch	= nfsd_dispatch,
+	.vs_xdrsize	= NFS3_SVC_XDRSIZE,
+	.vs_hidden	= 1,
+};
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 2604c3e..0fc6608 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -1378,6 +1378,8 @@ static int create_proc_exports_entry(void)
 }
 #endif
 
+extern void __init nfsd_prog_init(void);
+
 static int __init init_nfsd(void)
 {
 	int retval;
@@ -1386,6 +1388,7 @@ static int __init init_nfsd(void)
 	retval = nfs4_state_init(); /* nfs4 locking state */
 	if (retval)
 		return retval;
+	nfsd_prog_init();
 	nfsd_stat_init();	/* Statistics */
 	retval = nfsd_reply_cache_init();
 	if (retval)
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 171699e..6f0f472 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -15,6 +15,7 @@
 #include <linux/sunrpc/svcsock.h>
 #include <linux/lockd/bind.h>
 #include <linux/nfsacl.h>
+#include <linux/nfs_xattr.h>
 #include <linux/seq_file.h>
 #include "nfsd.h"
 #include "cache.h"
@@ -87,6 +88,27 @@ static struct svc_stat	nfsd_acl_svcstats = {
 };
 #endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */
 
+#ifdef CONFIG_NFSD_V3_XATTR
+static struct svc_stat	nfsd_xattr_svcstats;
+static struct svc_version *	nfsd_xattr_version[] = {
+	[3] = &nfsd_xattr_version3,
+};
+
+#define NFSD_XATTR_MINVERS	3
+#define NFSD_XATTR_NRVERS	ARRAY_SIZE(nfsd_xattr_version)
+static struct svc_version *nfsd_xattr_versions[NFSD_XATTR_NRVERS];
+
+static struct svc_program	nfsd_xattr_program = {
+	.pg_prog		= NFS_XATTR_PROGRAM,
+	.pg_nvers		= NFSD_XATTR_NRVERS,
+	.pg_vers		= nfsd_xattr_versions,
+	.pg_name		= "nfsxattr",
+	.pg_class		= "nfsd",		/* share nfsd auth */
+	.pg_stats		= &nfsd_xattr_svcstats,
+	.pg_authenticate	= &svc_set_client,
+};
+#endif	/* CONFIG_NFSD_V3_XATTR */
+
 static struct svc_version *	nfsd_version[] = {
 	[2] = &nfsd_version2,
 #if defined(CONFIG_NFSD_V3)
@@ -102,9 +124,6 @@ static struct svc_version *	nfsd_version[] = {
 static struct svc_version *nfsd_versions[NFSD_NRVERS];
 
 struct svc_program		nfsd_program = {
-#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
-	.pg_next		= &nfsd_acl_program,
-#endif
 	.pg_prog		= NFS_PROGRAM,		/* program number */
 	.pg_nvers		= NFSD_NRVERS,		/* nr of entries in nfsd_version */
 	.pg_vers		= nfsd_versions,	/* version table */
@@ -115,6 +134,28 @@ struct svc_program		nfsd_program = {
 
 };
 
+static void __init nfsd_prog_add(struct svc_program *new)
+{
+	struct svc_program *p = &nfsd_program;
+
+	while (p->pg_next)
+		p = p->pg_next;
+
+	p->pg_next = new;
+}
+
+/* Dynamically initialize list of service programs */
+void __init nfsd_prog_init(void)
+{
+#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
+	nfsd_prog_add(&nfsd_acl_program);
+#endif
+
+#ifdef CONFIG_NFSD_V3_XATTR
+	nfsd_prog_add(&nfsd_xattr_program);
+#endif
+}
+
 u32 nfsd_supported_minorversion;
 
 int nfsd_vers(int vers, enum vers_op change)
@@ -128,6 +169,10 @@ int nfsd_vers(int vers, enum vers_op change)
 		if (vers < NFSD_ACL_NRVERS)
 			nfsd_acl_versions[vers] = nfsd_acl_version[vers];
 #endif
+#ifdef CONFIG_NFSD_V3_XATTR
+		if (vers < NFSD_XATTR_NRVERS)
+			nfsd_xattr_versions[vers] = nfsd_xattr_version[vers];
+#endif
 		break;
 	case NFSD_CLEAR:
 		nfsd_versions[vers] = NULL;
@@ -135,6 +180,10 @@ int nfsd_vers(int vers, enum vers_op change)
 		if (vers < NFSD_ACL_NRVERS)
 			nfsd_acl_versions[vers] = NULL;
 #endif
+#ifdef CONFIG_NFSD_V3_XATTR
+		if (vers < NFSD_XATTR_NRVERS)
+			nfsd_xattr_versions[vers] = NULL;
+#endif
 		break;
 	case NFSD_TEST:
 		return nfsd_versions[vers] != NULL;
@@ -213,6 +262,11 @@ void nfsd_reset_versions(void)
 			nfsd_acl_program.pg_vers[i] =
 				nfsd_acl_version[i];
 #endif
+#ifdef CONFIG_NFSD_V3_XATTR
+		for (i = NFSD_XATTR_MINVERS; i < NFSD_XATTR_NRVERS; i++)
+			nfsd_xattr_program.pg_vers[i] =
+				nfsd_xattr_version[i];
+#endif
 	}
 }
 
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 8715d19..72f24ad 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -428,8 +428,9 @@ out_nfserr:
 
 #if defined(CONFIG_NFSD_V2_ACL) || \
     defined(CONFIG_NFSD_V3_ACL) || \
-    defined(CONFIG_NFSD_V4)
-static ssize_t nfsd_getxattr(struct dentry *dentry, char *key, void **buf)
+    defined(CONFIG_NFSD_V4) || \
+    defined(CONFIG_NFSD_V3_XATTR)
+ssize_t nfsd_getxattr(struct dentry *dentry, char *key, void **buf)
 {
 	ssize_t buflen;
 	ssize_t ret;
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
index 4b1de0a..f8132f3 100644
--- a/fs/nfsd/vfs.h
+++ b/fs/nfsd/vfs.h
@@ -98,4 +98,17 @@ struct posix_acl *nfsd_get_posix_acl(struct svc_fh *, int);
 int nfsd_set_posix_acl(struct svc_fh *, int, struct posix_acl *);
 #endif
 
+#if defined(CONFIG_NFSD_V2_ACL) || \
+    defined(CONFIG_NFSD_V3_ACL) || \
+    defined(CONFIG_NFSD_V4) || \
+    defined(CONFIG_NFSD_V3_XATTR)
+ssize_t nfsd_getxattr(struct dentry *dentry, char *key, void **buf);
+#endif
+
+#ifdef CONFIG_NFSD_V3_XATTR
+extern struct svc_version nfsd_xattr_version3;
+#else
+#define nfsd_xattr_version3 NULL
+#endif
+
 #endif /* LINUX_NFSD_VFS_H */
diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h
index 7df980e..e6ccc60 100644
--- a/fs/nfsd/xdr3.h
+++ b/fs/nfsd/xdr3.h
@@ -119,6 +119,27 @@ struct nfsd3_setaclargs {
 	struct posix_acl	*acl_default;
 };
 
+struct nfsd3_getxattrargs {
+	struct svc_fh           fh;
+	char *                  xattr_name;
+	unsigned int            xattr_name_len;
+	unsigned int            xattr_size_max;
+};
+
+struct nfsd3_setxattrargs {
+	struct svc_fh           fh;
+	unsigned int            xattr_flags;
+	char *                  xattr_name;
+	unsigned int            xattr_name_len;
+	char *                  xattr_val;
+	int                     xattr_val_len;
+};
+
+struct nfsd3_listxattrargs {
+	struct svc_fh           fh;
+	unsigned int            xattr_list_max;
+};
+
 struct nfsd3_attrstat {
 	__be32			status;
 	struct svc_fh		fh;
@@ -227,6 +248,25 @@ struct nfsd3_getaclres {
 	struct posix_acl	*acl_default;
 };
 
+struct nfsd3_getxattrres {
+	__be32                  status;
+	struct svc_fh           fh;
+	char *                  xattr_val;
+	unsigned int            xattr_val_len;
+};
+
+struct nfsd3_setxattrres {
+	__be32                  status;
+	struct svc_fh           fh;
+};
+
+struct nfsd3_listxattrres {
+	__be32                  status;
+	struct svc_fh           fh;
+	char *                  xattr_list;
+	unsigned int            xattr_list_len;
+};
+
 /* dummy type for release */
 struct nfsd3_fhandle_pair {
 	__u32			dummy;
@@ -247,6 +287,9 @@ union nfsd3_xdrstore {
 	struct nfsd3_linkargs		linkargs;
 	struct nfsd3_symlinkargs	symlinkargs;
 	struct nfsd3_readdirargs	readdirargs;
+	struct nfsd3_getxattrargs	getxattrargs;
+	struct nfsd3_setxattrargs	setxattrargs;
+	struct nfsd3_listxattrargs	listxattrargs;
 	struct nfsd3_diropres 		diropres;
 	struct nfsd3_accessres		accessres;
 	struct nfsd3_readlinkres	readlinkres;
@@ -260,6 +303,9 @@ union nfsd3_xdrstore {
 	struct nfsd3_pathconfres	pathconfres;
 	struct nfsd3_commitres		commitres;
 	struct nfsd3_getaclres		getaclres;
+	struct nfsd3_getxattrres	getxattrres;
+	struct nfsd3_setxattrres	setxattrres;
+	struct nfsd3_listxattrres	listxattrres;
 };
 
 #define NFS3_SVC_XDRSIZE		sizeof(union nfsd3_xdrstore)
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index 5a3085b..8bde5c1 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -371,7 +371,7 @@ struct svc_version {
 	u32			vs_xdrsize;	/* xdrsize needed for this version */
 
 	unsigned int		vs_hidden : 1;	/* Don't register with portmapper.
-						 * Only used for nfsacl so far. */
+						 * Used for nfsacl and nfsxattr. */
 
 	/* Override dispatch function (e.g. when caching replies).
 	 * A return value of 0 means drop the request. 
-- 
1.6.3.3


-- 
James Morris
<jmorris@namei.org>

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 5/5] NFSv3: Add server namespace support for XATTR protocol implementation
  2010-02-26  4:33 [PATCH 0/5][v3][RFC] NFSv3: implement extended attribute protocol (XATTR) James Morris
                   ` (3 preceding siblings ...)
  2010-02-26  4:36 ` [PATCH 4/5] NFSv3: add server " James Morris
@ 2010-02-26  4:37 ` James Morris
  2010-02-26 13:46   ` Stephen Smalley
  2010-03-08 10:42 ` [PATCH 0/6][v4][RFC] NFSv3: implement extended attribute protocol (XATTR) James Morris
  5 siblings, 1 reply; 39+ messages in thread
From: James Morris @ 2010-02-26  4:37 UTC (permalink / raw)
  To: linux-nfs
  Cc: linux-security-module, Trond Myklebust, J. Bruce Fields, Neil Brown

Add support for a server namespace for storing and retrieving
client-supplied xattrs.  All xattrs are now stored on the server under
the user._nfsd namespace, and are not interpreted by the server at all.
This allows clients to utilize arbitrary xattr namespaces and for the
server to act only as a storage mechanism for the xattrs.

The user._nfsd namespace was chosen because filesystems generally have
a user. xattr handler implemented.  Using something like system. would
require implementing a generalized handler for each backing fs on the
server, as well as requiring privilege to access.

Currently, only the user and trusted namespaces are supported by
the client, as system and security namespaces require further analysis,
and some special-case handling will be required (for security.selinux,
at least).

NFS ACLs continue to work as expected, because they implement a
hard-coded system xattr namespace which is invoked before the
NFS layer.  e.g. any access to a system.posix_acl_access xattr
is invokes the NFS_ACL protocol.

Signed-off-by: James Morris <jmorris@namei.org>
---
 fs/nfs/Kconfig              |   10 -----
 fs/nfs/Makefile             |    2 +-
 fs/nfs/internal.h           |    3 +-
 fs/nfs/nfs3acl.c            |    2 +-
 fs/nfs/nfs3xattr.c          |    3 +-
 fs/nfs/nfs3xattr_handlers.c |   80 +++++++++++++++++++++++++++++++++++++++++
 fs/nfs/nfs3xattr_user.c     |   53 ---------------------------
 fs/nfsd/nfs3xattr.c         |   83 +++++++++++++++++++++++++++++--------------
 fs/nfsd/vfs.h               |   10 +++++
 9 files changed, 152 insertions(+), 94 deletions(-)
 create mode 100644 fs/nfs/nfs3xattr_handlers.c
 delete mode 100644 fs/nfs/nfs3xattr_user.c

diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig
index e0e2535..317259e 100644
--- a/fs/nfs/Kconfig
+++ b/fs/nfs/Kconfig
@@ -86,16 +86,6 @@ config NFS_V3_XATTR
 
 	  If unsure, say N.
 
-config NFS_V3_XATTR_USER
-	bool "Extended attributes in the user namespace (EXPERIMENTAL)"
-	depends on NFS_V3_XATTR
-	help
-	  This option selects extended attributes in the user.* namespace,
-	  which are arbitrarily named and managed by users, and conveyed
-	  via the XATTR protocol extension for NFS version 3.
-
-	  If unsure, say N.
-
 config NFS_V4
 	bool "NFS client support for NFS version 4 (EXPERIMENTAL)"
 	depends on NFS_FS && EXPERIMENTAL
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile
index 54018ee..b289d7e 100644
--- a/fs/nfs/Makefile
+++ b/fs/nfs/Makefile
@@ -12,7 +12,7 @@ nfs-$(CONFIG_ROOT_NFS)	+= nfsroot.o
 nfs-$(CONFIG_NFS_V3)	+= nfs3proc.o nfs3xdr.o
 nfs-$(CONFIG_NFS_V3_ACL)	+= nfs3acl.o
 nfs-$(CONFIG_NFS_V3_XATTR_API)	+= nfs3xattr.o
-nfs-$(CONFIG_NFS_V3_XATTR_USER)	+= nfs3xattr_user.o
+nfs-$(CONFIG_NFS_V3_XATTR)	+= nfs3xattr_handlers.o
 nfs-$(CONFIG_NFS_V4)	+= nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \
 			   delegation.o idmap.o \
 			   callback.o callback_xdr.o callback_proc.o \
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 3661a64..a631daf 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -296,8 +296,9 @@ extern int nfs3_proc_setxattr(struct inode *inode, const char *namespace,
 extern int nfs3_proc_listxattr(struct inode *inode, char *list,
 			       size_t list_len);
 
-/* nfs3xattr_user.c */
+/* nfs3xattr_handers.c */
 extern struct xattr_handler nfs3_xattr_user_handler;
+extern struct xattr_handler nfs3_xattr_trusted_handler;
 
 /* nfs3acl.c */
 extern struct xattr_handler nfs3_xattr_acl_access_handler;
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c
index 6288ae4..9b1a3f5 100644
--- a/fs/nfs/nfs3acl.c
+++ b/fs/nfs/nfs3acl.c
@@ -15,7 +15,7 @@ static size_t nfs3_acl_xattr_list(struct dentry *dentry,
 				  int acl_type)
 {
 	struct posix_acl *acl;
-	char *acl_name = ACL_TYPE_ACCESS ?
+	char *acl_name = (acl_type == ACL_TYPE_ACCESS) ?
 		POSIX_ACL_XATTR_ACCESS : POSIX_ACL_XATTR_DEFAULT;
 	size_t size = strlen(acl_name) + 1;
 
diff --git a/fs/nfs/nfs3xattr.c b/fs/nfs/nfs3xattr.c
index 7ff651b..a1e054f 100644
--- a/fs/nfs/nfs3xattr.c
+++ b/fs/nfs/nfs3xattr.c
@@ -19,8 +19,9 @@
 #define NFSDBG_FACILITY	NFSDBG_PROC
 
 struct xattr_handler *nfs3_xattr_handlers[] = {
-#ifdef CONFIG_NFS_V3_XATTR_USER
+#ifdef CONFIG_NFS_V3_XATTR
 	&nfs3_xattr_user_handler,
+	&nfs3_xattr_trusted_handler,
 #endif
 #ifdef CONFIG_NFS_V3_ACL
 	&nfs3_xattr_acl_access_handler,
diff --git a/fs/nfs/nfs3xattr_handlers.c b/fs/nfs/nfs3xattr_handlers.c
new file mode 100644
index 0000000..e0be08d
--- /dev/null
+++ b/fs/nfs/nfs3xattr_handlers.c
@@ -0,0 +1,80 @@
+/*
+ * Client support for the NFS_XATTR protocol.
+ *
+ * Copyright (C) 2009 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ */
+#include <linux/fs.h>
+#include <linux/nfs.h>
+#include <linux/nfs3.h>
+#include <linux/nfs_fs.h>
+
+#include "internal.h"
+
+#define NFSDBG_FACILITY	NFSDBG_PROC
+
+/*
+ * Call the LISTXATTR procedure only once per syscall, when the user
+ * handler is invoked.
+ */
+static size_t nfs3_user_xattr_list(struct dentry *dentry, char *list,
+				   size_t list_len, const char *name,
+				   size_t name_len, int hflags)
+{
+
+	return nfs3_proc_listxattr(dentry->d_inode, list, list_len);
+}
+
+static size_t nfs3_noop_xattr_list(struct dentry *dentry, char *list,
+				   size_t list_len, const char *name,
+				   size_t name_len, int hflags)
+{
+	return 0;
+}
+
+static int nfs3_user_xattr_get(struct dentry *dentry, const char *name,
+			       void *buffer, size_t size, int hflags)
+{
+	return nfs3_proc_getxattr(dentry->d_inode, XATTR_USER_PREFIX,
+				  name, buffer, size);
+}
+
+static int nfs3_user_xattr_set(struct dentry *dentry, const char *name,
+			       const void *value, size_t size,
+			       int flags, int hflags)
+{
+	return nfs3_proc_setxattr(dentry->d_inode, XATTR_USER_PREFIX,
+				  name, value, size, flags);
+}
+
+struct xattr_handler nfs3_xattr_user_handler = {
+	.prefix = XATTR_USER_PREFIX,
+	.list	= nfs3_user_xattr_list,
+	.get    = nfs3_user_xattr_get,
+	.set    = nfs3_user_xattr_set,
+};
+
+static int nfs3_trusted_xattr_get(struct dentry *dentry, const char *name,
+				  void *buffer, size_t size, int hflags)
+{
+	return nfs3_proc_getxattr(dentry->d_inode, XATTR_TRUSTED_PREFIX,
+				  name, buffer, size);
+}
+
+static int nfs3_trusted_xattr_set(struct dentry *dentry, const char *name,
+				  const void *value, size_t size,
+				  int flags, int hflags)
+{
+	return nfs3_proc_setxattr(dentry->d_inode, XATTR_TRUSTED_PREFIX,
+				  name, value, size, flags);
+}
+
+struct xattr_handler nfs3_xattr_trusted_handler = {
+	.prefix = XATTR_TRUSTED_PREFIX,
+	.list	= nfs3_noop_xattr_list,
+	.get    = nfs3_trusted_xattr_get,
+	.set    = nfs3_trusted_xattr_set,
+};
diff --git a/fs/nfs/nfs3xattr_user.c b/fs/nfs/nfs3xattr_user.c
deleted file mode 100644
index c544fcb..0000000
--- a/fs/nfs/nfs3xattr_user.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Support for extended attributes in the the user.* namespace, which are
- * arbitrarily named and managed by users and conveyed via the XATTR
- * protocol extension.
- *
- * Copyright (C) 2009 Red Hat, Inc., James Morris <jmorris@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2,
- * as published by the Free Software Foundation.
- */
-#include <linux/fs.h>
-#include <linux/nfs.h>
-#include <linux/nfs3.h>
-#include <linux/nfs_fs.h>
-
-#include "internal.h"
-
-#define NFSDBG_FACILITY	NFSDBG_PROC
-
-/*
- * The generic xattr code will call this for each helper, which is ok for
- * now, because we only support this single namespace.  If support is
- * expanded to more namespaces, we we'll need a custom listxattr operation.
- */
-static size_t nfs3_user_xattr_list(struct dentry *dentry, char *list,
-				   size_t list_len, const char *name,
-				   size_t name_len, int hflags)
-{
-	return nfs3_proc_listxattr(dentry->d_inode, list, list_len);
-}
-
-static int nfs3_user_xattr_get(struct dentry *dentry, const char *name,
-			       void *buffer, size_t size, int hflags)
-{
-	return nfs3_proc_getxattr(dentry->d_inode, XATTR_USER_PREFIX,
-				  name, buffer, size);
-}
-
-static int nfs3_user_xattr_set(struct dentry *dentry, const char *name,
-			       const void *value, size_t size,
-			       int flags, int hflags)
-{
-	return nfs3_proc_setxattr(dentry->d_inode, XATTR_USER_PREFIX,
-				  name, value, size, flags);
-}
-
-struct xattr_handler nfs3_xattr_user_handler = {
-	.prefix = XATTR_USER_PREFIX,
-	.list   = nfs3_user_xattr_list,
-	.get    = nfs3_user_xattr_get,
-	.set    = nfs3_user_xattr_set,
-};
diff --git a/fs/nfsd/nfs3xattr.c b/fs/nfsd/nfs3xattr.c
index b5a5faa..41e0aef 100644
--- a/fs/nfsd/nfs3xattr.c
+++ b/fs/nfsd/nfs3xattr.c
@@ -47,11 +47,12 @@ static __be32 nfsd3_proc_getxattr(struct svc_rqst * rqstp,
 	char *name, *xattr_name = argp->xattr_name;
 	unsigned int size_max = argp->xattr_size_max;
 	unsigned int name_len = argp->xattr_name_len;
+	unsigned int name_tot_len = name_len + NFSD_XATTR_PREFIX_LEN;
 
 	dprintk("nfsd: GETXATTR(3)  %s %.*s %u\n", SVCFH_fmt(&argp->fh),
 	        name_len, xattr_name, size_max);
 
-	if (name_len > XATTR_NAME_MAX)
+	if (name_tot_len > XATTR_NAME_MAX)
 		RETURN_STATUS(nfserr);
 
 	if (size_max > XATTR_SIZE_MAX)
@@ -66,19 +67,14 @@ static __be32 nfsd3_proc_getxattr(struct svc_rqst * rqstp,
 	if (nfserr)
 		RETURN_STATUS(nfserr);
 
-	/* Convert xdr string to real string */
-	name = kmalloc(name_len + 1, GFP_KERNEL);
+	/* Convert xattr name to real string and add local prefix */
+	name = kmalloc(name_tot_len + 1, GFP_KERNEL);
 	if (name == NULL)
 		RETURN_STATUS(nfserrno(-ENOMEM));
 
-	ret = snprintf(name, name_len + 1, "%.*s", name_len, xattr_name);
-	if (ret > name_len) {
-		nfserr = nfserrno(-EINVAL);
-		goto cleanup;
-	}
-
-	/* Only the user namespace is currently supported by the server */
-	if (strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) {
+	ret = snprintf(name, name_tot_len + 1, "%s%.*s",
+		       NFSD_XATTR_PREFIX, name_len, xattr_name);
+	if (ret > name_tot_len) {
 		nfserr = nfserrno(-EINVAL);
 		goto cleanup;
 	}
@@ -159,11 +155,12 @@ static __be32 nfsd3_proc_setxattr(struct svc_rqst * rqstp,
 	unsigned int name_len = argp->xattr_name_len;
 	unsigned int val_len = argp->xattr_val_len;
 	unsigned int flags = argp->xattr_flags;
+	unsigned int name_tot_len = name_len + NFSD_XATTR_PREFIX_LEN;
 
 	dprintk("nfsd: SETXATTR(3)  %s %.*s %u %#x\n", SVCFH_fmt(&argp->fh),
 		name_len, xattr_name, val_len, flags);
 
-	if (name_len > XATTR_NAME_MAX)
+	if (name_tot_len > XATTR_NAME_MAX)
 		RETURN_STATUS(nfserr);
 
 	if (val_len > XATTR_SIZE_MAX)
@@ -177,19 +174,15 @@ static __be32 nfsd3_proc_setxattr(struct svc_rqst * rqstp,
 	if (nfserr)
 		RETURN_STATUS(nfserr);
 
-	/* Convert xdr string to real string */
-	name = kmalloc(name_len + 1, GFP_KERNEL);
+	/* Convert xattr name to real string and add prefix */
+	name = kmalloc(name_tot_len + 1, GFP_KERNEL);
 	if (name == NULL)
 		RETURN_STATUS(nfserrno(-ENOMEM));
 
-	ret = snprintf(name, name_len + 1, "%.*s", name_len, xattr_name);
-	if (ret > name_len) {
-		nfserr = nfserrno(-EINVAL);
-		goto cleanup;
-	}
+	ret = snprintf(name, name_tot_len + 1, "%s%.*s",
+		       NFSD_XATTR_PREFIX, name_len, xattr_name);
 
-	/* Only the user namespace is currently supported by the server */
-	if (strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) {
+	if (ret > name_tot_len) {
 		nfserr = nfserrno(-EINVAL);
 		goto cleanup;
 	}
@@ -240,9 +233,30 @@ static int nfs3svc_release_setxattr(struct svc_rqst *rqstp, __be32 *p,
 }
 
 /*
+ * Search the xattr list for those which match the local NFSD prefix. For
+ * each, strip the prefix and copy out the rest of the xattr.
+ */
+static int nfsd3_filter_xattrs(const char *in, char *out, int i_len)
+{
+	int i_idx = 0, o_idx = 0;
+
+	while (i_idx < i_len) {
+		const char *curr = in + i_idx;
+		int c_len = strlen(curr);
+
+		if (!strncmp(NFSD_XATTR_PREFIX, curr, NFSD_XATTR_PREFIX_LEN)) {
+			strcpy(out + o_idx, curr + NFSD_XATTR_PREFIX_LEN);
+			o_idx += c_len - NFSD_XATTR_PREFIX_LEN + 1;
+		}
+
+		i_idx += c_len + 1;
+	}
+
+	return o_idx;
+}
+
+/*
  * LISTXATTR
- *
- * TODO: namespace filtering?
  */
 static __be32 nfsd3_proc_listxattr(struct svc_rqst * rqstp,
 				   struct nfsd3_listxattrargs *argp,
@@ -250,8 +264,8 @@ static __be32 nfsd3_proc_listxattr(struct svc_rqst * rqstp,
 {
 	__be32 nfserr = nfserrno(-EINVAL);
 	svc_fh *fh;
-	char *list;
-	int ret;
+	char *list, *f_list;
+	int ret, f_len;
 	unsigned int list_max = argp->xattr_list_max;
 
 	dprintk("nfsd: LISTXATTR(3)  %s %u\n", SVCFH_fmt(&argp->fh), list_max);
@@ -276,12 +290,27 @@ static __be32 nfsd3_proc_listxattr(struct svc_rqst * rqstp,
 	if (ret <= 0) {
 		if (ret == 0)
 			ret = -ENODATA;
+		kfree(list);
 		RETURN_STATUS(nfserrno(ret));
 	}
 
+	/*
+	 * Filter the xattr list: translate and return only those stored
+	 * with the correct prefix.  The list is a series of nul-terminated
+	 * strings.
+	 */
+	f_list = kmalloc(ret, GFP_ATOMIC);
+	if (f_list == NULL) {
+		kfree(list);
+		RETURN_STATUS(nfserrno(-ENOMEM));
+	}
+
+	f_len = nfsd3_filter_xattrs(list, f_list, ret);
+	kfree(list);
+
 	nfserr = 0;
-	resp->xattr_list = list;
-	resp->xattr_list_len = ret;
+	resp->xattr_list = f_list;
+	resp->xattr_list_len = f_len;
 
 	RETURN_STATUS(nfserr);
 }
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
index f8132f3..4122a46 100644
--- a/fs/nfsd/vfs.h
+++ b/fs/nfsd/vfs.h
@@ -107,6 +107,16 @@ ssize_t nfsd_getxattr(struct dentry *dentry, char *key, void **buf);
 
 #ifdef CONFIG_NFSD_V3_XATTR
 extern struct svc_version nfsd_xattr_version3;
+
+/*
+ * Translation prefix for local storage of remote xattrs.  This is currently
+ * hard-coded, but could be made a configurable per-export option.  We're
+ * using the user namespace, which is widely supported by filesystems, and
+ * allows arbitrary manipulation.
+ */
+#define NFSD_XATTR_PREFIX "user._nfsd."
+#define NFSD_XATTR_PREFIX_LEN (strlen(NFSD_XATTR_PREFIX))
+
 #else
 #define nfsd_xattr_version3 NULL
 #endif
-- 
1.6.3.3


-- 
James Morris
<jmorris@namei.org>

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* Re: [PATCH 5/5] NFSv3: Add server namespace support for XATTR protocol implementation
  2010-02-26  4:37 ` [PATCH 5/5] NFSv3: Add server namespace support for XATTR protocol implementation James Morris
@ 2010-02-26 13:46   ` Stephen Smalley
  2010-03-01  0:49     ` Casey Schaufler
  0 siblings, 1 reply; 39+ messages in thread
From: Stephen Smalley @ 2010-02-26 13:46 UTC (permalink / raw)
  To: James Morris
  Cc: linux-nfs, linux-security-module, Trond Myklebust,
	J. Bruce Fields, Neil Brown, Dave Quigley, Serge E. Hallyn

On Fri, 2010-02-26 at 15:37 +1100, James Morris wrote:
> Add support for a server namespace for storing and retrieving
> client-supplied xattrs.  All xattrs are now stored on the server under
> the user._nfsd namespace, and are not interpreted by the server at all.
> This allows clients to utilize arbitrary xattr namespaces and for the
> server to act only as a storage mechanism for the xattrs.
> 
> The user._nfsd namespace was chosen because filesystems generally have
> a user. xattr handler implemented.  Using something like system. would
> require implementing a generalized handler for each backing fs on the
> server, as well as requiring privilege to access.

I'm wondering whether the user. namespace is best for storage on the
server given that:
- the user. namespace is restricted to regular files or directories (see
xattr_permission()), and
- the user. namespace applies its own set of permission checking logic
that we don't necessarily want applied in the case of trusted. or
security. attributes (e.g. special rules on sticky directories and read
or write access to the file, see xattr_permission()), and
- storing the attributes in the user. namespace would allow local users
on the server to manipulate them directly.  I know that you stated an
assumption that end users do not have local access to the exported
filesystem, but it would be better if the system itself would restrict
the ability to set these attributes to privileged processes on the
server.

Using the security. or trusted. namespace would avoid the restriction on
file type and require CAP_SYS_ADMIN on setxattr.  That would prevent
local modification by non-admins and should have no effect on clients
(since nfsd doesn't drop CAP_SYS_ADMIN).

> Currently, only the user and trusted namespaces are supported by
> the client, as system and security namespaces require further analysis,
> and some special-case handling will be required (for security.selinux,
> at least).
> 
> NFS ACLs continue to work as expected, because they implement a
> hard-coded system xattr namespace which is invoked before the
> NFS layer.  e.g. any access to a system.posix_acl_access xattr
> is invokes the NFS_ACL protocol.

-- 
Stephen Smalley
National Security Agency


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 5/5] NFSv3: Add server namespace support for XATTR protocol implementation
  2010-02-26 13:46   ` Stephen Smalley
@ 2010-03-01  0:49     ` Casey Schaufler
  2010-03-01  1:17       ` Trond Myklebust
  0 siblings, 1 reply; 39+ messages in thread
From: Casey Schaufler @ 2010-03-01  0:49 UTC (permalink / raw)
  To: Stephen Smalley
  Cc: James Morris, linux-nfs, linux-security-module, Trond Myklebust,
	J. Bruce Fields, Neil Brown, Dave Quigley, Serge E. Hallyn,
	Casey Schaufler

Stephen Smalley wrote:
> On Fri, 2010-02-26 at 15:37 +1100, James Morris wrote:
>   
>> Add support for a server namespace for storing and retrieving
>> client-supplied xattrs.  All xattrs are now stored on the server under
>> the user._nfsd namespace, and are not interpreted by the server at all.
>> This allows clients to utilize arbitrary xattr namespaces and for the
>> server to act only as a storage mechanism for the xattrs.
>>
>> The user._nfsd namespace was chosen because filesystems generally have
>> a user. xattr handler implemented.  Using something like system. would
>> require implementing a generalized handler for each backing fs on the
>> server, as well as requiring privilege to access.
>>     
>
> I'm wondering whether the user. namespace is best for storage on the
> server given that:
> - the user. namespace is restricted to regular files or directories (see
> xattr_permission()), and
> - the user. namespace applies its own set of permission checking logic
> that we don't necessarily want applied in the case of trusted. or
> security. attributes (e.g. special rules on sticky directories and read
> or write access to the file, see xattr_permission()), and
> - storing the attributes in the user. namespace would allow local users
> on the server to manipulate them directly.  I know that you stated an
> assumption that end users do not have local access to the exported
> filesystem, but it would be better if the system itself would restrict
> the ability to set these attributes to privileged processes on the
> server.
>
> Using the security. or trusted. namespace would avoid the restriction on
> file type and require CAP_SYS_ADMIN on setxattr.  That would prevent
> local modification by non-admins and should have no effect on clients
> (since nfsd doesn't drop CAP_SYS_ADMIN).
>
>   

I'm mostly in agreement with Stephen. I wouldn't object to a separate
"nfsd." namespace, as opposed to "security." or "trusted." because I
think that in reality you're not going to get very far without treating
is a special case in any event. May as well acknowledge it up front.

>> Currently, only the user and trusted namespaces are supported by
>> the client, as system and security namespaces require further analysis,
>> and some special-case handling will be required (for security.selinux,
>> at least).
>>
>> NFS ACLs continue to work as expected, because they implement a
>> hard-coded system xattr namespace which is invoked before the
>> NFS layer.  e.g. any access to a system.posix_acl_access xattr
>> is invokes the NFS_ACL protocol.
>>     
>
>   


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 5/5] NFSv3: Add server namespace support for XATTR protocol implementation
  2010-03-01  0:49     ` Casey Schaufler
@ 2010-03-01  1:17       ` Trond Myklebust
  2010-03-01  8:09         ` James Morris
  0 siblings, 1 reply; 39+ messages in thread
From: Trond Myklebust @ 2010-03-01  1:17 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: Stephen Smalley, James Morris, linux-nfs, linux-security-module,
	J. Bruce Fields, Neil Brown, Dave Quigley, Serge E. Hallyn

On Sun, 2010-02-28 at 16:49 -0800, Casey Schaufler wrote:

> I'm mostly in agreement with Stephen. I wouldn't object to a separate
> "nfsd." namespace, as opposed to "security." or "trusted." because I
> think that in reality you're not going to get very far without treating
> is a special case in any event. May as well acknowledge it up front.

That was indeed what I envisioned when I suggested it to James
originally, but I may have been a bit unclear on the subject.

I don't think that either 'security' or 'trusted' are a good fit here,
since they both have special meanings to local applications on the
server. 'user' is just wrong, since that means that ordinary local users
may end up with the power to change the security settings for remote
applications.

The intention of the 'nfsd' namespace was to separate the local and
remote xattr/security realms entirely. That includes allowing the server
to set up separate policies to determine who is allowed to change those
in the 'nfsd.*' namespace vs those who can change the ordinary
'security', 'trusted' and 'user' namespaces.

Cheers
  Trond

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 5/5] NFSv3: Add server namespace support for XATTR protocol implementation
  2010-03-01  1:17       ` Trond Myklebust
@ 2010-03-01  8:09         ` James Morris
  0 siblings, 0 replies; 39+ messages in thread
From: James Morris @ 2010-03-01  8:09 UTC (permalink / raw)
  To: Trond Myklebust
  Cc: Casey Schaufler, Stephen Smalley, linux-nfs,
	linux-security-module, J. Bruce Fields, Neil Brown, Dave Quigley,
	Serge E. Hallyn

On Sun, 28 Feb 2010, Trond Myklebust wrote:

> The intention of the 'nfsd' namespace was to separate the local and
> remote xattr/security realms entirely. That includes allowing the server
> to set up separate policies to determine who is allowed to change those
> in the 'nfsd.*' namespace vs those who can change the ordinary
> 'security', 'trusted' and 'user' namespaces.

Ok -- this definitely sounds like a better approach.  I'll post an updated 
version soon.


- James
-- 
James Morris
<jmorris@namei.org>

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH 0/6][v4][RFC] NFSv3: implement extended attribute protocol (XATTR)
  2010-02-26  4:33 [PATCH 0/5][v3][RFC] NFSv3: implement extended attribute protocol (XATTR) James Morris
                   ` (4 preceding siblings ...)
  2010-02-26  4:37 ` [PATCH 5/5] NFSv3: Add server namespace support for XATTR protocol implementation James Morris
@ 2010-03-08 10:42 ` James Morris
  2010-03-08 10:43   ` [PATCH 1/6] NFSv3: convert client to generic xattr API James Morris
                     ` (5 more replies)
  5 siblings, 6 replies; 39+ messages in thread
From: James Morris @ 2010-03-08 10:42 UTC (permalink / raw)
  To: linux-nfs
  Cc: linux-security-module, Trond Myklebust, J. Bruce Fields,
	Neil Brown, linux-fsdevel

This is version 4 of the NFSv3 XATTR protocol extension patches, which 
I've previously posted:
 
v1: http://thread.gmane.org/gmane.linux.file-systems/35475
v2: http://thread.gmane.org/gmane.linux.nfs/30539
v3: http://thread.gmane.org/gmane.linux.nfs/30971

Since the last version, I've incorporated feedback to add a new top-level 
xattr namespace "nfsd", for storing client-origin xattrs on the server.  
Support for the new namespace has been implemented on ext3 for testing 
purposes.

Access to this namespace locally requires CAP_SYS_ADMIN, and it is not 
accessible over the wire.  Note that there is still potential for 
confusion between local and remote users, e.g.

$ setfattr -n user.foo -v bar file.txt

on an NFS mounted fs will create an xattr on the server called 
nfsd.user.foo, and then if the user logs in locally, they will not see the 
xattr at all.  Similarly, if they create xattrs locally, they will not be 
exported via XATTR.

Comments welcome.


- James
-- 
James Morris
<jmorris@namei.org>

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH 1/6] NFSv3: convert client to generic xattr API
  2010-03-08 10:42 ` [PATCH 0/6][v4][RFC] NFSv3: implement extended attribute protocol (XATTR) James Morris
@ 2010-03-08 10:43   ` James Morris
  2010-03-08 10:44   ` [PATCH 3/6] NFSv3: add client implementation of XATTR protocol James Morris
                     ` (4 subsequent siblings)
  5 siblings, 0 replies; 39+ messages in thread
From: James Morris @ 2010-03-08 10:43 UTC (permalink / raw)
  To: linux-nfs
  Cc: linux-security-module, Trond Myklebust, J. Bruce Fields,
	Neil Brown, linux-fsdevel

Convert existing NFSv3 client use (i.e. ACLs) of the xattrs to
the kernel's generic xattr API.

This helps simplify the code, and prepare for the subsequent
NFSv3 xattr protocol patches, which will also utilize the
generic xattr API.

Signed-off-by: James Morris <jmorris@namei.org>
---
 fs/nfs/dir.c           |    8 ++--
 fs/nfs/file.c          |    8 ++--
 fs/nfs/internal.h      |    4 ++
 fs/nfs/nfs3acl.c       |  122 ++++++++++++++++++++---------------------------
 fs/nfs/super.c         |    3 +
 include/linux/nfs_fs.h |   16 ------
 6 files changed, 67 insertions(+), 94 deletions(-)

diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 3c7f03b..b1cb729 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -94,10 +94,10 @@ const struct inode_operations nfs3_dir_inode_operations = {
 	.permission	= nfs_permission,
 	.getattr	= nfs_getattr,
 	.setattr	= nfs_setattr,
-	.listxattr	= nfs3_listxattr,
-	.getxattr	= nfs3_getxattr,
-	.setxattr	= nfs3_setxattr,
-	.removexattr	= nfs3_removexattr,
+	.listxattr	= generic_listxattr,
+	.getxattr	= generic_getxattr,
+	.setxattr	= generic_setxattr,
+	.removexattr	= generic_removexattr,
 };
 #endif  /* CONFIG_NFS_V3 */
 
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 63f2071..ddb7ab7 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -91,10 +91,10 @@ const struct inode_operations nfs3_file_inode_operations = {
 	.permission	= nfs_permission,
 	.getattr	= nfs_getattr,
 	.setattr	= nfs_setattr,
-	.listxattr	= nfs3_listxattr,
-	.getxattr	= nfs3_getxattr,
-	.setxattr	= nfs3_setxattr,
-	.removexattr	= nfs3_removexattr,
+	.listxattr	= generic_listxattr,
+	.getxattr	= generic_getxattr,
+	.setxattr	= generic_setxattr,
+	.removexattr	= generic_removexattr,
 };
 #endif  /* CONFIG_NFS_v3 */
 
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 29e464d..9bb918a 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -4,6 +4,7 @@
 
 #include "nfs4_fs.h"
 #include <linux/mount.h>
+#include <linux/xattr.h>
 #include <linux/security.h>
 
 #define NFS_MS_MASK (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_SYNCHRONOUS)
@@ -284,6 +285,9 @@ static inline char *nfs_devname(const struct vfsmount *mnt_parent,
 			dentry, buffer, buflen);
 }
 
+/* nfs3acl.c */
+extern struct xattr_handler *nfs3_xattr_handlers[];
+
 /*
  * Determine the actual block size (and log2 thereof)
  */
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c
index bac6051..6a6127b 100644
--- a/fs/nfs/nfs3acl.c
+++ b/fs/nfs/nfs3acl.c
@@ -9,64 +9,41 @@
 
 #define NFSDBG_FACILITY	NFSDBG_PROC
 
-ssize_t nfs3_listxattr(struct dentry *dentry, char *buffer, size_t size)
+static size_t nfs3_acl_xattr_list(struct dentry *dentry,
+				  char *list, size_t list_len,
+				  const char *name, size_t name_len,
+				  int acl_type)
 {
-	struct inode *inode = dentry->d_inode;
 	struct posix_acl *acl;
-	int pos=0, len=0;
+	char *acl_name = (acl_type == ACL_TYPE_ACCESS) ?
+		POSIX_ACL_XATTR_ACCESS : POSIX_ACL_XATTR_DEFAULT;
+	size_t size = strlen(acl_name) + 1;
 
-#	define output(s) do {						\
-			if (pos + sizeof(s) <= size) {			\
-				memcpy(buffer + pos, s, sizeof(s));	\
-				pos += sizeof(s);			\
-			}						\
-			len += sizeof(s);				\
-		} while(0)
+	acl = nfs3_proc_getacl(dentry->d_inode, acl_type);
+	if (!acl)
+		return 0;
 
-	acl = nfs3_proc_getacl(inode, ACL_TYPE_ACCESS);
 	if (IS_ERR(acl))
 		return PTR_ERR(acl);
-	if (acl) {
-		output("system.posix_acl_access");
-		posix_acl_release(acl);
-	}
 
-	if (S_ISDIR(inode->i_mode)) {
-		acl = nfs3_proc_getacl(inode, ACL_TYPE_DEFAULT);
-		if (IS_ERR(acl))
-			return PTR_ERR(acl);
-		if (acl) {
-			output("system.posix_acl_default");
-			posix_acl_release(acl);
-		}
-	}
-
-#	undef output
+	if (list && size <= list_len)
+		memcpy(list, acl_name, size);
 
-	if (!buffer || len <= size)
-		return len;
-	return -ERANGE;
+	posix_acl_release(acl);
+	return size;
 }
 
-ssize_t nfs3_getxattr(struct dentry *dentry, const char *name,
-		void *buffer, size_t size)
+static int nfs3_acl_xattr_get(struct dentry *dentry, const char *name,
+			      void *buffer, size_t size, int acl_type)
 {
-	struct inode *inode = dentry->d_inode;
 	struct posix_acl *acl;
-	int type, error = 0;
-
-	if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0)
-		type = ACL_TYPE_ACCESS;
-	else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0)
-		type = ACL_TYPE_DEFAULT;
-	else
-		return -EOPNOTSUPP;
+	int error = 0;
 
-	acl = nfs3_proc_getacl(inode, type);
+	acl = nfs3_proc_getacl(dentry->d_inode, acl_type);
 	if (IS_ERR(acl))
 		return PTR_ERR(acl);
 	else if (acl) {
-		if (type == ACL_TYPE_ACCESS && acl->a_count == 0)
+		if (acl_type == ACL_TYPE_ACCESS && acl->a_count == 0)
 			error = -ENODATA;
 		else
 			error = posix_acl_to_xattr(acl, buffer, size);
@@ -77,43 +54,48 @@ ssize_t nfs3_getxattr(struct dentry *dentry, const char *name,
 	return error;
 }
 
-int nfs3_setxattr(struct dentry *dentry, const char *name,
-	     const void *value, size_t size, int flags)
+static int nfs3_acl_xattr_set(struct dentry *dentry, const char *name,
+			      const void *value, size_t size, int flags,
+			      int acl_type)
 {
-	struct inode *inode = dentry->d_inode;
 	struct posix_acl *acl;
-	int type, error;
+	int error;
 
-	if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0)
-		type = ACL_TYPE_ACCESS;
-	else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0)
-		type = ACL_TYPE_DEFAULT;
-	else
-		return -EOPNOTSUPP;
+	if (value == NULL && (flags & XATTR_REPLACE))
+		acl = NULL;	/* remove xattr */
+	else {
+		acl = posix_acl_from_xattr(value, size);
+		if (IS_ERR(acl))
+			return PTR_ERR(acl);
+	}
 
-	acl = posix_acl_from_xattr(value, size);
-	if (IS_ERR(acl))
-		return PTR_ERR(acl);
-	error = nfs3_proc_setacl(inode, type, acl);
+	error = nfs3_proc_setacl(dentry->d_inode, acl_type, acl);
 	posix_acl_release(acl);
 
 	return error;
 }
 
-int nfs3_removexattr(struct dentry *dentry, const char *name)
-{
-	struct inode *inode = dentry->d_inode;
-	int type;
-
-	if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0)
-		type = ACL_TYPE_ACCESS;
-	else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0)
-		type = ACL_TYPE_DEFAULT;
-	else
-		return -EOPNOTSUPP;
-
-	return nfs3_proc_setacl(inode, type, NULL);
-}
+static struct xattr_handler nfs3_xattr_acl_access_handler = {
+	.prefix = POSIX_ACL_XATTR_ACCESS,
+	.flags	= ACL_TYPE_ACCESS,
+	.list   = nfs3_acl_xattr_list,
+	.get    = nfs3_acl_xattr_get,
+	.set    = nfs3_acl_xattr_set,
+};
+
+static struct xattr_handler nfs3_xattr_acl_default_handler = {
+	.prefix = POSIX_ACL_XATTR_DEFAULT,
+	.flags	= ACL_TYPE_DEFAULT,
+	.list   = nfs3_acl_xattr_list,
+	.get    = nfs3_acl_xattr_get,
+	.set    = nfs3_acl_xattr_set,
+};
+
+struct xattr_handler *nfs3_xattr_handlers[] = {
+	&nfs3_xattr_acl_access_handler,
+	&nfs3_xattr_acl_default_handler,
+	NULL
+};
 
 static void __nfs3_forget_cached_acls(struct nfs_inode *nfsi)
 {
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index f1afee4..31f5863 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -2018,6 +2018,9 @@ static void nfs_fill_super(struct super_block *sb,
 		 */
 		sb->s_flags |= MS_POSIXACL;
 		sb->s_time_gran = 1;
+#ifdef CONFIG_NFS_V3_ACL
+		sb->s_xattr = nfs3_xattr_handlers;
+#endif
 	}
 
 	sb->s_op = &nfs_sops;
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index d09db1b..34848b8 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -389,22 +389,6 @@ static inline struct rpc_cred *nfs_file_cred(struct file *file)
 }
 
 /*
- * linux/fs/nfs/xattr.c
- */
-#ifdef CONFIG_NFS_V3_ACL
-extern ssize_t nfs3_listxattr(struct dentry *, char *, size_t);
-extern ssize_t nfs3_getxattr(struct dentry *, const char *, void *, size_t);
-extern int nfs3_setxattr(struct dentry *, const char *,
-			const void *, size_t, int);
-extern int nfs3_removexattr (struct dentry *, const char *name);
-#else
-# define nfs3_listxattr NULL
-# define nfs3_getxattr NULL
-# define nfs3_setxattr NULL
-# define nfs3_removexattr NULL
-#endif
-
-/*
  * linux/fs/nfs/direct.c
  */
 extern ssize_t nfs_direct_IO(int, struct kiocb *, const struct iovec *, loff_t,
-- 
1.6.3.3


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 2/6] NFSv3: add xattr API config option for client
       [not found]   ` <alpine.LRH.2.00.1003082122340.6314-CK9fWmtY32x9JUWOpEiw7w@public.gmane.org>
@ 2010-03-08 10:43       ` James Morris
  2010-03-08 10:47       ` James Morris
  1 sibling, 0 replies; 39+ messages in thread
From: James Morris @ 2010-03-08 10:43 UTC (permalink / raw)
  To: linux-nfs-u79uwXL29TY76Z2rM5mHXA
  Cc: linux-security-module-u79uwXL29TY76Z2rM5mHXA, Trond Myklebust,
	J. Bruce Fields, Neil Brown,
	linux-fsdevel-u79uwXL29TY76Z2rM5mHXA

Add a separate configuration option for xattr API use by NFSv3 client
code, and make it independent of ACLs, so other NFSv3 client code (e.g.
the subsequent XATTR side-protocol) can use it.

Move the ACL handlers into the new xattr API file, where all such
handlers in the NFSv3 client code will live.

Signed-off-by: James Morris <jmorris-gx6/JNMH7DfYtjvyW6yDsg@public.gmane.org>
---
 fs/nfs/Kconfig     |    4 ++++
 fs/nfs/Makefile    |    1 +
 fs/nfs/internal.h  |    6 +++++-
 fs/nfs/nfs3acl.c   |   10 ++--------
 fs/nfs/nfs3xattr.c |   25 +++++++++++++++++++++++++
 5 files changed, 37 insertions(+), 9 deletions(-)
 create mode 100644 fs/nfs/nfs3xattr.c

diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig
index 59e5673..d27a88e 100644
--- a/fs/nfs/Kconfig
+++ b/fs/nfs/Kconfig
@@ -38,9 +38,13 @@ config NFS_V3
 
 	  If unsure, say Y.
 
+config NFS_V3_XATTR_API
+	def_bool n
+
 config NFS_V3_ACL
 	bool "NFS client support for the NFSv3 ACL protocol extension"
 	depends on NFS_V3
+	select NFS_V3_XATTR_API
 	help
 	  Some NFS servers support an auxiliary NFSv3 ACL protocol that
 	  Sun added to Solaris but never became an official part of the
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile
index da7fda6..1e2743e 100644
--- a/fs/nfs/Makefile
+++ b/fs/nfs/Makefile
@@ -11,6 +11,7 @@ nfs-y 			:= client.o dir.o file.o getroot.o inode.o super.o nfs2xdr.o \
 nfs-$(CONFIG_ROOT_NFS)	+= nfsroot.o
 nfs-$(CONFIG_NFS_V3)	+= nfs3proc.o nfs3xdr.o
 nfs-$(CONFIG_NFS_V3_ACL)	+= nfs3acl.o
+nfs-$(CONFIG_NFS_V3_XATTR_API)	+= nfs3xattr.o
 nfs-$(CONFIG_NFS_V4)	+= nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \
 			   delegation.o idmap.o \
 			   callback.o callback_xdr.o callback_proc.o \
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 9bb918a..48fcac9 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -285,9 +285,13 @@ static inline char *nfs_devname(const struct vfsmount *mnt_parent,
 			dentry, buffer, buflen);
 }
 
-/* nfs3acl.c */
+/* nfs3xattr.c */
 extern struct xattr_handler *nfs3_xattr_handlers[];
 
+/* nfs3acl.c */
+extern struct xattr_handler nfs3_xattr_acl_access_handler;
+extern struct xattr_handler nfs3_xattr_acl_default_handler;
+
 /*
  * Determine the actual block size (and log2 thereof)
  */
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c
index 6a6127b..9b1a3f5 100644
--- a/fs/nfs/nfs3acl.c
+++ b/fs/nfs/nfs3acl.c
@@ -75,7 +75,7 @@ static int nfs3_acl_xattr_set(struct dentry *dentry, const char *name,
 	return error;
 }
 
-static struct xattr_handler nfs3_xattr_acl_access_handler = {
+struct xattr_handler nfs3_xattr_acl_access_handler = {
 	.prefix = POSIX_ACL_XATTR_ACCESS,
 	.flags	= ACL_TYPE_ACCESS,
 	.list   = nfs3_acl_xattr_list,
@@ -83,7 +83,7 @@ static struct xattr_handler nfs3_xattr_acl_access_handler = {
 	.set    = nfs3_acl_xattr_set,
 };
 
-static struct xattr_handler nfs3_xattr_acl_default_handler = {
+struct xattr_handler nfs3_xattr_acl_default_handler = {
 	.prefix = POSIX_ACL_XATTR_DEFAULT,
 	.flags	= ACL_TYPE_DEFAULT,
 	.list   = nfs3_acl_xattr_list,
@@ -91,12 +91,6 @@ static struct xattr_handler nfs3_xattr_acl_default_handler = {
 	.set    = nfs3_acl_xattr_set,
 };
 
-struct xattr_handler *nfs3_xattr_handlers[] = {
-	&nfs3_xattr_acl_access_handler,
-	&nfs3_xattr_acl_default_handler,
-	NULL
-};
-
 static void __nfs3_forget_cached_acls(struct nfs_inode *nfsi)
 {
 	if (!IS_ERR(nfsi->acl_access)) {
diff --git a/fs/nfs/nfs3xattr.c b/fs/nfs/nfs3xattr.c
new file mode 100644
index 0000000..de69f1e
--- /dev/null
+++ b/fs/nfs/nfs3xattr.c
@@ -0,0 +1,25 @@
+/*
+ * Extended attribute (xattr) API and protocol for NFSv3.
+ *
+ * Copyright (C) 2009 Red Hat, Inc., James Morris <jmorris-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ */
+#include <linux/fs.h>
+#include <linux/nfs.h>
+#include <linux/nfs3.h>
+#include <linux/nfs_fs.h>
+
+#include "internal.h"
+
+#define NFSDBG_FACILITY	NFSDBG_PROC
+
+struct xattr_handler *nfs3_xattr_handlers[] = {
+#ifdef CONFIG_NFS_V3_ACL
+	&nfs3_xattr_acl_access_handler,
+	&nfs3_xattr_acl_default_handler,
+#endif
+	NULL
+};
-- 
1.6.3.3

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 2/6] NFSv3: add xattr API config option for client
@ 2010-03-08 10:43       ` James Morris
  0 siblings, 0 replies; 39+ messages in thread
From: James Morris @ 2010-03-08 10:43 UTC (permalink / raw)
  To: linux-nfs
  Cc: linux-security-module, Trond Myklebust, J. Bruce Fields,
	Neil Brown, linux-fsdevel

Add a separate configuration option for xattr API use by NFSv3 client
code, and make it independent of ACLs, so other NFSv3 client code (e.g.
the subsequent XATTR side-protocol) can use it.

Move the ACL handlers into the new xattr API file, where all such
handlers in the NFSv3 client code will live.

Signed-off-by: James Morris <jmorris@namei.org>
---
 fs/nfs/Kconfig     |    4 ++++
 fs/nfs/Makefile    |    1 +
 fs/nfs/internal.h  |    6 +++++-
 fs/nfs/nfs3acl.c   |   10 ++--------
 fs/nfs/nfs3xattr.c |   25 +++++++++++++++++++++++++
 5 files changed, 37 insertions(+), 9 deletions(-)
 create mode 100644 fs/nfs/nfs3xattr.c

diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig
index 59e5673..d27a88e 100644
--- a/fs/nfs/Kconfig
+++ b/fs/nfs/Kconfig
@@ -38,9 +38,13 @@ config NFS_V3
 
 	  If unsure, say Y.
 
+config NFS_V3_XATTR_API
+	def_bool n
+
 config NFS_V3_ACL
 	bool "NFS client support for the NFSv3 ACL protocol extension"
 	depends on NFS_V3
+	select NFS_V3_XATTR_API
 	help
 	  Some NFS servers support an auxiliary NFSv3 ACL protocol that
 	  Sun added to Solaris but never became an official part of the
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile
index da7fda6..1e2743e 100644
--- a/fs/nfs/Makefile
+++ b/fs/nfs/Makefile
@@ -11,6 +11,7 @@ nfs-y 			:= client.o dir.o file.o getroot.o inode.o super.o nfs2xdr.o \
 nfs-$(CONFIG_ROOT_NFS)	+= nfsroot.o
 nfs-$(CONFIG_NFS_V3)	+= nfs3proc.o nfs3xdr.o
 nfs-$(CONFIG_NFS_V3_ACL)	+= nfs3acl.o
+nfs-$(CONFIG_NFS_V3_XATTR_API)	+= nfs3xattr.o
 nfs-$(CONFIG_NFS_V4)	+= nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \
 			   delegation.o idmap.o \
 			   callback.o callback_xdr.o callback_proc.o \
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 9bb918a..48fcac9 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -285,9 +285,13 @@ static inline char *nfs_devname(const struct vfsmount *mnt_parent,
 			dentry, buffer, buflen);
 }
 
-/* nfs3acl.c */
+/* nfs3xattr.c */
 extern struct xattr_handler *nfs3_xattr_handlers[];
 
+/* nfs3acl.c */
+extern struct xattr_handler nfs3_xattr_acl_access_handler;
+extern struct xattr_handler nfs3_xattr_acl_default_handler;
+
 /*
  * Determine the actual block size (and log2 thereof)
  */
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c
index 6a6127b..9b1a3f5 100644
--- a/fs/nfs/nfs3acl.c
+++ b/fs/nfs/nfs3acl.c
@@ -75,7 +75,7 @@ static int nfs3_acl_xattr_set(struct dentry *dentry, const char *name,
 	return error;
 }
 
-static struct xattr_handler nfs3_xattr_acl_access_handler = {
+struct xattr_handler nfs3_xattr_acl_access_handler = {
 	.prefix = POSIX_ACL_XATTR_ACCESS,
 	.flags	= ACL_TYPE_ACCESS,
 	.list   = nfs3_acl_xattr_list,
@@ -83,7 +83,7 @@ static struct xattr_handler nfs3_xattr_acl_access_handler = {
 	.set    = nfs3_acl_xattr_set,
 };
 
-static struct xattr_handler nfs3_xattr_acl_default_handler = {
+struct xattr_handler nfs3_xattr_acl_default_handler = {
 	.prefix = POSIX_ACL_XATTR_DEFAULT,
 	.flags	= ACL_TYPE_DEFAULT,
 	.list   = nfs3_acl_xattr_list,
@@ -91,12 +91,6 @@ static struct xattr_handler nfs3_xattr_acl_default_handler = {
 	.set    = nfs3_acl_xattr_set,
 };
 
-struct xattr_handler *nfs3_xattr_handlers[] = {
-	&nfs3_xattr_acl_access_handler,
-	&nfs3_xattr_acl_default_handler,
-	NULL
-};
-
 static void __nfs3_forget_cached_acls(struct nfs_inode *nfsi)
 {
 	if (!IS_ERR(nfsi->acl_access)) {
diff --git a/fs/nfs/nfs3xattr.c b/fs/nfs/nfs3xattr.c
new file mode 100644
index 0000000..de69f1e
--- /dev/null
+++ b/fs/nfs/nfs3xattr.c
@@ -0,0 +1,25 @@
+/*
+ * Extended attribute (xattr) API and protocol for NFSv3.
+ *
+ * Copyright (C) 2009 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ */
+#include <linux/fs.h>
+#include <linux/nfs.h>
+#include <linux/nfs3.h>
+#include <linux/nfs_fs.h>
+
+#include "internal.h"
+
+#define NFSDBG_FACILITY	NFSDBG_PROC
+
+struct xattr_handler *nfs3_xattr_handlers[] = {
+#ifdef CONFIG_NFS_V3_ACL
+	&nfs3_xattr_acl_access_handler,
+	&nfs3_xattr_acl_default_handler,
+#endif
+	NULL
+};
-- 
1.6.3.3


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 3/6] NFSv3: add client implementation of XATTR protocol
  2010-03-08 10:42 ` [PATCH 0/6][v4][RFC] NFSv3: implement extended attribute protocol (XATTR) James Morris
  2010-03-08 10:43   ` [PATCH 1/6] NFSv3: convert client to generic xattr API James Morris
@ 2010-03-08 10:44   ` James Morris
  2010-03-08 10:45   ` [PATCH 4/6] NFSv3: add server " James Morris
                     ` (3 subsequent siblings)
  5 siblings, 0 replies; 39+ messages in thread
From: James Morris @ 2010-03-08 10:44 UTC (permalink / raw)
  To: linux-nfs
  Cc: linux-security-module, Trond Myklebust, J. Bruce Fields,
	Neil Brown, linux-fsdevel

Add client support for the Linux NFSv3 extended attribute
side protocol (XATTR).

This extends Linux extended attributes over the network to
servers which support the protocol.

Operation is currently limited to the user.* namespace.

Signed-off-by: James Morris <jmorris@namei.org>
---
 fs/nfs/Kconfig            |   32 ++++++
 fs/nfs/Makefile           |    1 +
 fs/nfs/client.c           |   51 ++++++++++-
 fs/nfs/internal.h         |   11 ++
 fs/nfs/nfs3xattr.c        |  239 +++++++++++++++++++++++++++++++++++++++++++++
 fs/nfs/nfs3xattr_user.c   |   52 ++++++++++
 fs/nfs/nfs3xdr.c          |  187 +++++++++++++++++++++++++++++++++++
 include/linux/nfs_fs_sb.h |    3 +-
 include/linux/nfs_mount.h |    3 +
 include/linux/nfs_xattr.h |   21 ++++
 include/linux/nfs_xdr.h   |   45 +++++++++
 11 files changed, 643 insertions(+), 2 deletions(-)
 create mode 100644 fs/nfs/nfs3xattr_user.c
 create mode 100644 include/linux/nfs_xattr.h

diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig
index d27a88e..e0e2535 100644
--- a/fs/nfs/Kconfig
+++ b/fs/nfs/Kconfig
@@ -64,6 +64,38 @@ config NFS_V3_ACL
 
 	  If unsure, say N.
 
+config NFS_V3_XATTR
+	bool "NFS client support for the NFSv3 XATTR protocol extension (EXPERIMENTAL)"
+	depends on NFS_V3 && EXPERIMENTAL
+	select NFS_V3_XATTR_API
+	help
+	  This option selects client suport for the Linux NFSv3 extended
+	  attribute protocol extension (XATTR).
+
+	  This is a side-protocol which extends general support for Linux
+	  extended attributes over the network, and is based on the GPLd
+	  IRIX implmentation (although not wire-compatible with it).
+
+	  Only the user.* namespace is currently supported.  When connected
+	  to a server which also supports XATTR, the full range of extended
+	  attribute system calls:
+
+	    getxattr(2), listxattr(2), setxattr(2) and removexattr(2)
+
+	  should work as expected.
+
+	  If unsure, say N.
+
+config NFS_V3_XATTR_USER
+	bool "Extended attributes in the user namespace (EXPERIMENTAL)"
+	depends on NFS_V3_XATTR
+	help
+	  This option selects extended attributes in the user.* namespace,
+	  which are arbitrarily named and managed by users, and conveyed
+	  via the XATTR protocol extension for NFS version 3.
+
+	  If unsure, say N.
+
 config NFS_V4
 	bool "NFS client support for NFS version 4 (EXPERIMENTAL)"
 	depends on NFS_FS && EXPERIMENTAL
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile
index 1e2743e..54018ee 100644
--- a/fs/nfs/Makefile
+++ b/fs/nfs/Makefile
@@ -12,6 +12,7 @@ nfs-$(CONFIG_ROOT_NFS)	+= nfsroot.o
 nfs-$(CONFIG_NFS_V3)	+= nfs3proc.o nfs3xdr.o
 nfs-$(CONFIG_NFS_V3_ACL)	+= nfs3acl.o
 nfs-$(CONFIG_NFS_V3_XATTR_API)	+= nfs3xattr.o
+nfs-$(CONFIG_NFS_V3_XATTR_USER)	+= nfs3xattr_user.o
 nfs-$(CONFIG_NFS_V4)	+= nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \
 			   delegation.o idmap.o \
 			   callback.o callback_xdr.o callback_proc.o \
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index ee77713..6be7f19 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -97,6 +97,21 @@ struct rpc_program		nfsacl_program = {
 };
 #endif  /* CONFIG_NFS_V3_ACL */
 
+#ifdef CONFIG_NFS_V3_XATTR
+static struct rpc_stat		nfs_xattr_rpcstat = { &nfs_xattr_program };
+static struct rpc_version *	nfs_xattr_version[] = {
+	[3]			= &nfs_xattr_version3,
+};
+
+struct rpc_program		nfs_xattr_program = {
+	.name			= "nfsxattr",
+	.number			= NFS_XATTR_PROGRAM,
+	.nrvers			= ARRAY_SIZE(nfs_xattr_version),
+	.version		= nfs_xattr_version,
+	.stats			= &nfs_xattr_rpcstat,
+};
+#endif  /* CONFIG_NFS_V3_XATTR */
+
 struct nfs_client_initdata {
 	const char *hostname;
 	const struct sockaddr *addr;
@@ -706,6 +721,36 @@ static inline void nfs_init_server_aclclient(struct nfs_server *server)
 #endif
 
 /*
+ * Initialise an NFSv3 XATTR client connection
+ */
+#ifdef CONFIG_NFS_V3_XATTR
+static void nfs_init_server_xattrclient(struct nfs_server *server)
+{
+	if (server->nfs_client->rpc_ops->version != 3)
+		goto out_no_xattr;
+	if (server->flags & NFS_MOUNT_NOXATTR)
+		goto out_no_xattr;
+
+	server->client_xattr = rpc_bind_new_program(server->client, &nfs_xattr_program, 3);
+	if (IS_ERR(server->client_xattr))
+		goto out_no_xattr;
+
+	/* No errors! Assume that XATTR is supported */
+	server->caps |= NFS_CAP_XATTR;
+	return;
+
+out_no_xattr:
+	server->caps &= ~NFS_CAP_XATTR;
+}
+#else
+static inline void nfs_init_server_xattrclient(struct nfs_server *server)
+{
+	server->flags &= ~NFS_MOUNT_NOXATTR;
+	server->caps &= ~NFS_CAP_XATTR;
+}
+#endif
+
+/*
  * Create a general RPC client
  */
 static int nfs_init_server_rpcclient(struct nfs_server *server,
@@ -851,8 +896,12 @@ static int nfs_init_server(struct nfs_server *server,
 	server->mountd_protocol = data->mount_server.protocol;
 
 	server->namelen  = data->namlen;
-	/* Create a client RPC handle for the NFSv3 ACL management interface */
+	/*
+	 * Create client RPC handles for the NFSv3 ACL and XATTR management
+	 * interfaces
+	 */
 	nfs_init_server_aclclient(server);
+	nfs_init_server_xattrclient(server);
 	dprintk("<-- nfs_init_server() = 0 [new %p]\n", clp);
 	return 0;
 
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 48fcac9..3661a64 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -288,6 +288,17 @@ static inline char *nfs_devname(const struct vfsmount *mnt_parent,
 /* nfs3xattr.c */
 extern struct xattr_handler *nfs3_xattr_handlers[];
 
+extern int nfs3_proc_getxattr(struct inode *inode, const char *namespace,
+			      const char *name, void *value, size_t size);
+extern int nfs3_proc_setxattr(struct inode *inode, const char *namespace,
+			      const char *name, const void *value,
+			      size_t size, int flags);
+extern int nfs3_proc_listxattr(struct inode *inode, char *list,
+			       size_t list_len);
+
+/* nfs3xattr_user.c */
+extern struct xattr_handler nfs3_xattr_user_handler;
+
 /* nfs3acl.c */
 extern struct xattr_handler nfs3_xattr_acl_access_handler;
 extern struct xattr_handler nfs3_xattr_acl_default_handler;
diff --git a/fs/nfs/nfs3xattr.c b/fs/nfs/nfs3xattr.c
index de69f1e..7ff651b 100644
--- a/fs/nfs/nfs3xattr.c
+++ b/fs/nfs/nfs3xattr.c
@@ -1,6 +1,8 @@
 /*
  * Extended attribute (xattr) API and protocol for NFSv3.
  *
+ * Based on the ACL code.
+ *
  * Copyright (C) 2009 Red Hat, Inc., James Morris <jmorris@redhat.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -17,9 +19,246 @@
 #define NFSDBG_FACILITY	NFSDBG_PROC
 
 struct xattr_handler *nfs3_xattr_handlers[] = {
+#ifdef CONFIG_NFS_V3_XATTR_USER
+	&nfs3_xattr_user_handler,
+#endif
 #ifdef CONFIG_NFS_V3_ACL
 	&nfs3_xattr_acl_access_handler,
 	&nfs3_xattr_acl_default_handler,
 #endif
 	NULL
 };
+
+#ifdef CONFIG_NFS_V3_XATTR
+/*
+ * XATTR protocol
+ */
+
+/*
+ * Call GETXATTR
+ *
+ * FIXME:
+ * - Cache xattrs
+ * - Handle size probing
+ */
+int nfs3_proc_getxattr(struct inode *inode, const char *namespace,
+		       const char *name, void *value, size_t size)
+{
+	int status;
+	struct nfs_fattr fattr;
+	struct nfs_server *server = NFS_SERVER(inode);
+	struct nfs3_getxattrargs args = {
+		.fh		= NFS_FH(inode),
+	};
+	struct nfs3_getxattrres res = {
+		.fattr		= &fattr,
+	};
+	struct rpc_message msg = {
+		.rpc_argp	= &args,
+		.rpc_resp	= &res,
+	};
+
+	if (!name || !*name)
+		return -EINVAL;
+
+	if (size > XATTR_SIZE_MAX)
+		return -EINVAL;
+
+	if (!nfs_server_capable(inode, NFS_CAP_XATTR))
+		return -EOPNOTSUPP;
+
+	status = nfs_revalidate_inode(server, inode);
+	if (status < 0)
+		return status;
+
+	/*
+	 * Applications usually first probe the xattr value size, then
+	 * perform a full call.  For now, just return a dummy value.
+	 */
+	if (!size || !value)
+		return 4096;
+
+	args.xattr_namespace = namespace;
+	args.xattr_name = name;
+	args.xattr_size_max = size;
+
+	/*
+	 * FIXME
+	 *
+	 * This is ugly.  We pre-allocate a buffer for the XDR layer to use,
+	 * passing the size of the buffer via xattr_val_len, which is
+	 * updated with the actual length decoded.  We should investigate
+	 * using the page-based interface used by ACLs and others, or some
+	 * other better way.
+	 */
+	res.xattr_val_len = size;
+	res.xattr_val = kmalloc(size, GFP_KERNEL);
+	if (!res.xattr_val)
+		return -ENOMEM;
+
+	dprintk("NFS call getxattr %s%s %zd\n", namespace, name, size);
+
+	msg.rpc_proc = &server->client_xattr->cl_procinfo[XATTRPROC3_GETXATTR];
+	nfs_fattr_init(&fattr);
+	status = rpc_call_sync(server->client_xattr, &msg, 0);
+
+	dprintk("NFS reply getxattr: status=%d len=%d\n",
+		status, res.xattr_val_len);
+
+	switch (status) {
+	case 0:
+		status = nfs_refresh_inode(inode, &fattr);
+		break;
+	case -EPFNOSUPPORT:
+	case -EPROTONOSUPPORT:
+		dprintk("NFS_V3_XATTR extension not supported; disabling\n");
+		server->caps &= ~NFS_CAP_XATTR;
+	case -ENOTSUPP:
+		status = -EOPNOTSUPP;
+	default:
+		goto cleanup;
+	}
+
+	status = res.xattr_val_len;
+	if (status <= size)
+		memcpy(value, res.xattr_val, status);
+
+cleanup:
+	kfree(res.xattr_val);
+	return status;
+}
+
+/*
+ * Call SETXATTR or RMXATTR
+ *
+ * RMXATTR is invoked with a NULL buffer and XATTR_REPLACE.
+ *
+ */
+int nfs3_proc_setxattr(struct inode *inode, const char *namespace,
+		       const char *name, const void *value,
+		       size_t size, int flags)
+
+{
+	int status;
+	struct nfs_fattr fattr;
+	struct nfs_server *server = NFS_SERVER(inode);
+	struct nfs3_setxattrargs args = {
+		.fh		= NFS_FH(inode),
+	};
+	struct nfs3_setxattrres res = {
+		.fattr		= &fattr,
+	};
+	struct rpc_message msg = {
+		.rpc_argp	= &args,
+		.rpc_resp	= &res,
+	};
+
+	if (!name || !*name)
+		return -EINVAL;
+
+	if (!nfs_server_capable(inode, NFS_CAP_XATTR))
+		return -EOPNOTSUPP;
+
+	status = nfs_revalidate_inode(server, inode);
+	if (status < 0)
+		return status;
+
+	args.xattr_namespace = namespace;
+	args.xattr_name = name;
+	args.xattr_flags = flags;
+	args.xattr_val = value;
+	args.xattr_val_len = size;
+
+	dprintk("NFS call setxattr %s%s %zd 0x%08x\n",
+		namespace, name, size, flags);
+
+	msg.rpc_proc = &server->client_xattr->cl_procinfo[XATTRPROC3_SETXATTR];
+	nfs_fattr_init(&fattr);
+	status = rpc_call_sync(server->client_xattr, &msg, 0);
+
+	dprintk("NFS reply setxattr: status=%d\n", status);
+
+	switch (status) {
+	case 0:
+		status = nfs_refresh_inode(inode, &fattr);
+		break;
+	case -EPFNOSUPPORT:
+	case -EPROTONOSUPPORT:
+		dprintk("NFS_V3_XATTR extension not supported; disabling\n");
+		server->caps &= ~NFS_CAP_XATTR;
+	case -ENOTSUPP:
+		status = -EOPNOTSUPP;
+	default:
+		break;
+	}
+	return status;
+}
+
+/*
+ * Call LISTXATTR
+ */
+int nfs3_proc_listxattr(struct inode *inode, char *list, size_t list_len)
+{
+	int status;
+	struct nfs_fattr fattr;
+	struct nfs_server *server = NFS_SERVER(inode);
+	struct nfs3_listxattrargs args = {
+		.fh		= NFS_FH(inode),
+	};
+	struct nfs3_listxattrres res = {
+		.fattr		= &fattr,
+	};
+	struct rpc_message msg = {
+		.rpc_argp	= &args,
+		.rpc_resp	= &res,
+	};
+
+	if (list_len > XATTR_LIST_MAX)
+		return -EINVAL;
+
+	if (!nfs_server_capable(inode, NFS_CAP_XATTR))
+		return -EOPNOTSUPP;
+
+	dprintk("NFS call listxattr %zd\n", list_len);
+
+	/* FIXME: handle probes */
+	if (!list || !list_len)
+		return 1024;
+
+	args.xattr_list_max = list_len;
+
+	/* FIXME (see comments for getxattr) */
+	res.xattr_list_len = list_len;
+	res.xattr_list = kmalloc(list_len, GFP_KERNEL);
+	if (!res.xattr_list)
+		return -ENOMEM;
+
+	msg.rpc_proc = &server->client_xattr->cl_procinfo[XATTRPROC3_LISTXATTR];
+	nfs_fattr_init(&fattr);
+	status = rpc_call_sync(server->client_xattr, &msg, 0);
+
+	dprintk("NFS reply listxattr: status=%d\n", status);
+
+	switch (status) {
+	case 0:
+		status = nfs_refresh_inode(inode, &fattr);
+		break;
+	case -EPFNOSUPPORT:
+	case -EPROTONOSUPPORT:
+		dprintk("NFS_V3_XATTR extension not supported; disabling\n");
+		server->caps &= ~NFS_CAP_XATTR;
+	case -ENOTSUPP:
+		status = -EOPNOTSUPP;
+	default:
+		goto cleanup;
+	}
+
+	status = res.xattr_list_len;
+	if (status <= list_len)
+		memcpy(list, res.xattr_list, status);
+
+cleanup:
+	kfree(res.xattr_list);
+	return status;
+}
+#endif	/* CONFIG_NFS_V3_XATTR */
diff --git a/fs/nfs/nfs3xattr_user.c b/fs/nfs/nfs3xattr_user.c
new file mode 100644
index 0000000..61ae019
--- /dev/null
+++ b/fs/nfs/nfs3xattr_user.c
@@ -0,0 +1,52 @@
+/*
+ * Support for extended attributes in the the user.* namespace, which are
+ * arbitrarily named and managed by users and conveyed via the XATTR
+ * protocol extension.
+ *
+ * Copyright (C) 2009 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ */
+#include <linux/fs.h>
+#include <linux/nfs.h>
+#include <linux/nfs3.h>
+#include <linux/nfs_fs.h>
+
+#include "internal.h"
+
+#define NFSDBG_FACILITY	NFSDBG_PROC
+
+/*
+ * The generic xattr code will call this for each helper, which is ok for
+ * now, because we only support this single namespace.  If support is
+ * expanded to more namespaces, we we'll need a custom listxattr operation.
+ */
+static size_t nfs3_user_xattr_list(struct inode *inode, char *list,
+				   size_t list_len, const char *name,
+				   size_t name_len)
+{
+	return nfs3_proc_listxattr(inode, list, list_len);
+}
+
+static int nfs3_user_xattr_get(struct inode *inode, const char *name,
+			       void *buffer, size_t size)
+{
+	return nfs3_proc_getxattr(inode, XATTR_USER_PREFIX,
+				  name, buffer, size);
+}
+
+static int nfs3_user_xattr_set(struct inode *inode, const char *name,
+			       const void *value, size_t size, int flags)
+{
+	return nfs3_proc_setxattr(inode, XATTR_USER_PREFIX,
+				  name, value, size, flags);
+}
+
+struct xattr_handler nfs3_xattr_user_handler = {
+	.prefix = XATTR_USER_PREFIX,
+	.list   = nfs3_user_xattr_list,
+	.get    = nfs3_user_xattr_get,
+	.set    = nfs3_user_xattr_set,
+};
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
index 5fe5492..1552e6e 100644
--- a/fs/nfs/nfs3xdr.c
+++ b/fs/nfs/nfs3xdr.c
@@ -88,6 +88,26 @@
 #define ACL3_setaclres_sz	(1+NFS3_post_op_attr_sz)
 
 /*
+ * FIXME: currently, the RPC layer will allocate the maximum buffer size
+ * here for each call (which can be ~ 64k).  The Labeled NFS prototype code
+ * uses 4k, although we should not impose limits for NFS which don't exist
+ * in the OS unless absolutely necsssary.  We likely need a dynamic scheme
+ * here, possibly using pages.
+ */
+#define XATTR3_xattrname_sz	(1+(XATTR_NAME_MAX>>2))
+#define XATTR3_xattrval_sz	(1+(XATTR_SIZE_MAX>>2))
+#define XATTR3_xattrlist_sz	(1+(XATTR_LIST_MAX>>2))
+
+#define XATTR3_getxattrargs_sz	(NFS3_fh_sz+XATTR3_xattrname_sz+1)
+#define XATTR3_getxattrres_sz	(1+NFS3_post_op_attr_sz+XATTR3_xattrval_sz)
+
+#define XATTR3_setxattrargs_sz	(NFS3_fh_sz+XATTR3_xattrname_sz+XATTR3_xattrval_sz+1)
+#define XATTR3_setxattrres_sz	(1+NFS3_post_op_attr_sz)
+
+#define XATTR3_listxattrargs_sz	(NFS3_fh_sz+1)
+#define XATTR3_listxattrres_sz	(1+NFS3_post_op_attr_sz+XATTR3_xattrlist_sz)
+
+/*
  * Map file type to S_IFMT bits
  */
 static const umode_t nfs_type2fmt[] = {
@@ -727,6 +747,72 @@ nfs3_xdr_setaclargs(struct rpc_rqst *req, __be32 *p,
 }
 #endif  /* CONFIG_NFS_V3_ACL */
 
+#ifdef CONFIG_NFS_V3_XATTR
+/*
+ * Special case of xdr_encode_opaque, where the xattr helpers hand us
+ * separate namespace and name buffers, which we encode as a single XDR
+ * string over the wire.  Neither namespace nor name may be empty or null.
+ */
+static __be32 *xattr_encode_name(__be32 *p, const char *namespace, const char *name)
+{
+	unsigned int nslen, namelen, totlen, quadlen, padding;
+
+	nslen = strlen(namespace);
+	namelen = strlen(name);
+	totlen = nslen + namelen;
+	quadlen = XDR_QUADLEN(totlen);
+	padding = (quadlen << 2) - totlen;
+
+	*p++ = cpu_to_be32(totlen);
+	memcpy(p, namespace, nslen);
+	memcpy((char *)p + nslen, name, namelen);
+
+	if (padding != 0)
+		memset((char *)p + totlen, 0, padding);
+	p += quadlen;
+	return p;
+}
+
+/*
+ * Encode GETXATTR arguments
+ */
+static int nfs3_xdr_getxattrargs(struct rpc_rqst *req, __be32 *p,
+				 struct nfs3_getxattrargs *args)
+{
+	p = xdr_encode_fhandle(p, args->fh);
+	p = xattr_encode_name(p, args->xattr_namespace, args->xattr_name);
+	*p++ = htonl(args->xattr_size_max);
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	return 0;
+}
+
+/*
+ * Encode SETXATTR arguments
+ */
+static int nfs3_xdr_setxattrargs(struct rpc_rqst *req, __be32 *p,
+				 struct nfs3_setxattrargs *args)
+{
+	p = xdr_encode_fhandle(p, args->fh);
+	p = xattr_encode_name(p, args->xattr_namespace, args->xattr_name);
+	p = xdr_encode_array(p, args->xattr_val, args->xattr_val_len);
+	*p++ = htonl(args->xattr_flags);
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	return 0;
+}
+
+/*
+ * Encode LISTXATTR arguments
+ */
+static int nfs3_xdr_listxattrargs(struct rpc_rqst *req, __be32 *p,
+				  struct nfs3_listxattrargs *args)
+{
+	p = xdr_encode_fhandle(p, args->fh);
+	*p++ = htonl(args->xattr_list_max);
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	return 0;
+}
+#endif	/* CONFIG_NFS_V3_XATTR */
+
 /*
  * NFS XDR decode functions
  */
@@ -1136,6 +1222,69 @@ nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
 }
 #endif  /* CONFIG_NFS_V3_ACL */
 
+#ifdef CONFIG_NFS_V3_XATTR
+/*
+ * Decode GETXATTR reply
+ *
+ * FIXME: determine appropriate error returns
+ */
+static int nfs3_xdr_getxattrres(struct rpc_rqst *req, __be32 *p,
+				struct nfs3_getxattrres *res)
+{
+	char *xattr_val;
+	unsigned int xattr_max_size = res->xattr_val_len;
+	int status = ntohl(*p++);
+
+	if (status != 0)
+		return nfs_stat_to_errno(status);
+
+	p = xdr_decode_post_op_attr(p, res->fattr);
+	p = xdr_decode_string_inplace(p, &xattr_val,
+	                              &res->xattr_val_len,
+	                              xattr_max_size);
+	if (p == NULL)
+		return -EINVAL;
+	memcpy(res->xattr_val, xattr_val, res->xattr_val_len);
+	return 0;
+}
+
+/*
+ * Decode SETXATTR reply
+ */
+static int nfs3_xdr_setxattrres(struct rpc_rqst *req, __be32 *p,
+				struct nfs3_setxattrres *res)
+{
+	int status = ntohl(*p++);
+
+	if (status)
+		return nfs_stat_to_errno(status);
+	xdr_decode_post_op_attr(p, res->fattr);
+	return 0;
+}
+
+/*
+ * Decode LISTXATTR reply
+ */
+static int nfs3_xdr_listxattrres(struct rpc_rqst *req, __be32 *p,
+				 struct nfs3_listxattrres *res)
+{
+	char *xattr_list;
+	unsigned int size = res->xattr_list_len;
+	int status = ntohl(*p++);
+
+	if (status != 0)
+		return nfs_stat_to_errno(status);
+
+	p = xdr_decode_post_op_attr(p, res->fattr);
+	p = xdr_decode_string_inplace(p, &xattr_list,
+	                              &res->xattr_list_len, size);
+	if (p == NULL)
+		return -EINVAL;
+	memcpy(res->xattr_list, xattr_list, res->xattr_list_len);
+	return 0;
+}
+#endif	/* CONFIG_NFS_V3_XATTR */
+
 #define PROC(proc, argtype, restype, timer)				\
 [NFS3PROC_##proc] = {							\
 	.p_proc      = NFS3PROC_##proc,					\
@@ -1207,3 +1356,41 @@ struct rpc_version		nfsacl_version3 = {
 	.procs			= nfs3_acl_procedures,
 };
 #endif  /* CONFIG_NFS_V3_ACL */
+
+#ifdef CONFIG_NFS_V3_XATTR
+static struct rpc_procinfo	nfs3_xattr_procedures[] = {
+	[XATTRPROC3_GETXATTR] = {
+		.p_proc		= XATTRPROC3_GETXATTR,
+		.p_encode	= (kxdrproc_t) nfs3_xdr_getxattrargs,
+		.p_decode	= (kxdrproc_t) nfs3_xdr_getxattrres,
+		.p_arglen	= XATTR3_getxattrargs_sz,
+		.p_replen	= XATTR3_getxattrres_sz,
+		.p_timer	= 1,
+		.p_name		= "GETXATTR",
+	},
+	[XATTRPROC3_SETXATTR] = {
+		.p_proc		= XATTRPROC3_SETXATTR,
+		.p_encode	= (kxdrproc_t) nfs3_xdr_setxattrargs,
+		.p_decode	= (kxdrproc_t) nfs3_xdr_setxattrres,
+		.p_arglen	= XATTR3_setxattrargs_sz,
+		.p_replen	= XATTR3_setxattrres_sz,
+		.p_timer	= 1,
+		.p_name		= "SETXATTR",
+	},
+	[XATTRPROC3_LISTXATTR] = {
+		.p_proc		= XATTRPROC3_LISTXATTR,
+		.p_encode	= (kxdrproc_t) nfs3_xdr_listxattrargs,
+		.p_decode	= (kxdrproc_t) nfs3_xdr_listxattrres,
+		.p_arglen	= XATTR3_listxattrargs_sz,
+		.p_replen	= XATTR3_listxattrres_sz,
+		.p_timer	= 1,
+		.p_name		= "LISTXATTR",
+	},
+};
+
+struct rpc_version		nfs_xattr_version3 = {
+	.number			= 3,
+	.nrprocs		= ARRAY_SIZE(nfs3_xattr_procedures),
+	.procs			= nfs3_xattr_procedures,
+};
+#endif	/* CONFIG_NFS_V3_XATTR */
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index 34fc6be..c881ac4 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -104,6 +104,7 @@ struct nfs_server {
 	struct list_head	master_link;	/* link in master servers list */
 	struct rpc_clnt *	client;		/* RPC client handle */
 	struct rpc_clnt *	client_acl;	/* ACL RPC client handle */
+	struct rpc_clnt *	client_xattr;	/* XATTR RPC client handle */
 	struct nlm_host		*nlm_host;	/* NLM client handle */
 	struct nfs_iostats *	io_stats;	/* I/O statistics */
 	struct backing_dev_info	backing_dev_info;
@@ -176,7 +177,7 @@ struct nfs_server {
 #define NFS_CAP_ATIME		(1U << 11)
 #define NFS_CAP_CTIME		(1U << 12)
 #define NFS_CAP_MTIME		(1U << 13)
-
+#define NFS_CAP_XATTR		(1U << 14)
 
 /* maximum number of slots to use */
 #define NFS4_MAX_SLOT_TABLE RPC_MAX_SLOT_TABLE
diff --git a/include/linux/nfs_mount.h b/include/linux/nfs_mount.h
index 4499016..04bb4ee 100644
--- a/include/linux/nfs_mount.h
+++ b/include/linux/nfs_mount.h
@@ -70,4 +70,7 @@ struct nfs_mount_data {
 #define NFS_MOUNT_LOOKUP_CACHE_NONE	0x20000
 #define NFS_MOUNT_NORESVPORT		0x40000
 
+/* FIXME: determine semantics and modify flagmask if exposed to userland */
+#define NFS_MOUNT_NOXATTR		0x80000
+
 #endif
diff --git a/include/linux/nfs_xattr.h b/include/linux/nfs_xattr.h
new file mode 100644
index 0000000..98fdbed
--- /dev/null
+++ b/include/linux/nfs_xattr.h
@@ -0,0 +1,21 @@
+/*
+ * Extended attribute protocol for NFSv3 (XATTR)
+ *
+ *
+ * Copyright (C) 2009 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ *
+ */
+#ifndef __LINUX_NFS_XATTR_H
+#define __LINUX_NFS_XATTR_H
+
+#include <linux/xattr.h>
+
+#define NFS_XATTR_PROGRAM	391063	/* TODO: find another value */
+
+/* xattr procedure numbers */
+#define XATTRPROC3_GETXATTR	1
+#define XATTRPROC3_SETXATTR	2
+#define XATTRPROC3_LISTXATTR	3
+#define XATTRPROC3_RMXATTR	4
+
+#endif  /* __LINUX_NFS_XATTR_H */
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 89b2881..5e79744 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -2,6 +2,7 @@
 #define _LINUX_NFS_XDR_H
 
 #include <linux/nfsacl.h>
+#include <linux/nfs_xattr.h>
 #include <linux/nfs3.h>
 
 /*
@@ -514,6 +515,27 @@ struct nfs3_setaclargs {
 	struct page **		pages;
 };
 
+struct nfs3_getxattrargs {
+	struct nfs_fh *		fh;
+	const char *		xattr_namespace;
+	const char *		xattr_name;
+	unsigned int		xattr_size_max;
+};
+
+struct nfs3_setxattrargs {
+	struct nfs_fh *		fh;
+	unsigned int		xattr_flags;
+	const char *		xattr_namespace;
+	const char *		xattr_name;
+	const char *		xattr_val;
+	int			xattr_val_len;
+};
+
+struct nfs3_listxattrargs {
+	struct nfs_fh *		fh;
+	unsigned int		xattr_list_max;
+};
+
 struct nfs_diropok {
 	struct nfs_fh *		fh;
 	struct nfs_fattr *	fattr;
@@ -646,6 +668,26 @@ struct nfs3_getaclres {
 	struct posix_acl *	acl_default;
 };
 
+struct nfs3_getxattrres {
+	struct nfs_fattr *	fattr;
+	char *			xattr_val;
+	int			xattr_val_len;
+};
+
+/*
+ * Note: if we don't add any more fields, we can get rid of this struct and
+ * just use fattr in the calling code.
+ */
+struct nfs3_setxattrres {
+	struct nfs_fattr *	fattr;
+};
+
+struct nfs3_listxattrres {
+	struct nfs_fattr *	fattr;
+	char *			xattr_list;
+	int			xattr_list_len;
+};
+
 #ifdef CONFIG_NFS_V4
 
 typedef u64 clientid4;
@@ -1074,4 +1116,7 @@ extern struct rpc_version	nfs_version4;
 extern struct rpc_version	nfsacl_version3;
 extern struct rpc_program	nfsacl_program;
 
+extern struct rpc_version	nfs_xattr_version3;
+extern struct rpc_program	nfs_xattr_program;
+
 #endif
-- 
1.6.3.3


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 4/6] NFSv3: add server implementation of XATTR protocol
  2010-03-08 10:42 ` [PATCH 0/6][v4][RFC] NFSv3: implement extended attribute protocol (XATTR) James Morris
  2010-03-08 10:43   ` [PATCH 1/6] NFSv3: convert client to generic xattr API James Morris
  2010-03-08 10:44   ` [PATCH 3/6] NFSv3: add client implementation of XATTR protocol James Morris
@ 2010-03-08 10:45   ` James Morris
  2010-03-08 10:46   ` [PATCH 5/6] xattr: add new top level nfsd namespace and implement ext3 support James Morris
                     ` (2 subsequent siblings)
  5 siblings, 0 replies; 39+ messages in thread
From: James Morris @ 2010-03-08 10:45 UTC (permalink / raw)
  To: linux-nfs
  Cc: linux-security-module, Trond Myklebust, J. Bruce Fields,
	Neil Brown, linux-fsdevel

Add server support for the Linux NFSv3 extended attribute
side protocol (XATTR).

Signed-off-by: James Morris <jmorris@namei.org>
---
 fs/nfs/nfs3xattr_user.c    |   19 ++-
 fs/nfsd/Kconfig            |    8 +
 fs/nfsd/Makefile           |    1 +
 fs/nfsd/nfs3xattr.c        |  354 ++++++++++++++++++++++++++++++++++++++++++++
 fs/nfsd/nfsctl.c           |    3 +
 fs/nfsd/nfssvc.c           |   60 +++++++-
 fs/nfsd/vfs.c              |    5 +-
 fs/nfsd/vfs.h              |   13 ++
 fs/nfsd/xdr3.h             |   46 ++++++
 include/linux/sunrpc/svc.h |    2 +-
 10 files changed, 496 insertions(+), 15 deletions(-)
 create mode 100644 fs/nfsd/nfs3xattr.c

diff --git a/fs/nfs/nfs3xattr_user.c b/fs/nfs/nfs3xattr_user.c
index 61ae019..c544fcb 100644
--- a/fs/nfs/nfs3xattr_user.c
+++ b/fs/nfs/nfs3xattr_user.c
@@ -23,24 +23,25 @@
  * now, because we only support this single namespace.  If support is
  * expanded to more namespaces, we we'll need a custom listxattr operation.
  */
-static size_t nfs3_user_xattr_list(struct inode *inode, char *list,
+static size_t nfs3_user_xattr_list(struct dentry *dentry, char *list,
 				   size_t list_len, const char *name,
-				   size_t name_len)
+				   size_t name_len, int hflags)
 {
-	return nfs3_proc_listxattr(inode, list, list_len);
+	return nfs3_proc_listxattr(dentry->d_inode, list, list_len);
 }
 
-static int nfs3_user_xattr_get(struct inode *inode, const char *name,
-			       void *buffer, size_t size)
+static int nfs3_user_xattr_get(struct dentry *dentry, const char *name,
+			       void *buffer, size_t size, int hflags)
 {
-	return nfs3_proc_getxattr(inode, XATTR_USER_PREFIX,
+	return nfs3_proc_getxattr(dentry->d_inode, XATTR_USER_PREFIX,
 				  name, buffer, size);
 }
 
-static int nfs3_user_xattr_set(struct inode *inode, const char *name,
-			       const void *value, size_t size, int flags)
+static int nfs3_user_xattr_set(struct dentry *dentry, const char *name,
+			       const void *value, size_t size,
+			       int flags, int hflags)
 {
-	return nfs3_proc_setxattr(inode, XATTR_USER_PREFIX,
+	return nfs3_proc_setxattr(dentry->d_inode, XATTR_USER_PREFIX,
 				  name, value, size, flags);
 }
 
diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig
index 503b9da..4252d16 100644
--- a/fs/nfsd/Kconfig
+++ b/fs/nfsd/Kconfig
@@ -64,6 +64,14 @@ config NFSD_V3_ACL
 
 	  If unsure, say N.
 
+config NFSD_V3_XATTR
+	bool "NFS server support for the NFSv3 XATTR protocol extension (EXPERIMENTAL)"
+	depends on NFSD_V3 && EXPERIMENTAL
+	help
+	  NFS server support for the NFSv3 XATTR protocol.
+
+	  If unsure, say N.
+
 config NFSD_V4
 	bool "NFS server support for NFS version 4 (EXPERIMENTAL)"
 	depends on NFSD && PROC_FS && EXPERIMENTAL
diff --git a/fs/nfsd/Makefile b/fs/nfsd/Makefile
index 9b118ee..e206b52 100644
--- a/fs/nfsd/Makefile
+++ b/fs/nfsd/Makefile
@@ -9,5 +9,6 @@ nfsd-y 			:= nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \
 nfsd-$(CONFIG_NFSD_V2_ACL) += nfs2acl.o
 nfsd-$(CONFIG_NFSD_V3)	+= nfs3proc.o nfs3xdr.o
 nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o
+nfsd-$(CONFIG_NFSD_V3_XATTR) += nfs3xattr.o
 nfsd-$(CONFIG_NFSD_V4)	+= nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \
 			   nfs4acl.o nfs4callback.o nfs4recover.o
diff --git a/fs/nfsd/nfs3xattr.c b/fs/nfsd/nfs3xattr.c
new file mode 100644
index 0000000..b5a5faa
--- /dev/null
+++ b/fs/nfsd/nfs3xattr.c
@@ -0,0 +1,354 @@
+/*
+ * Process version 3 NFSXATTR requests.
+ *
+ * Based on the NFSACL code by:
+ * Copyright (C) 2002-2003 Andreas Gruenbacher <agruen@suse.de>
+ *
+ * Copyright (C) 2009 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ */
+#include <linux/sunrpc/svc.h>
+#include <linux/nfs3.h>
+#include <linux/xattr.h>
+#include <linux/nfs_xattr.h>
+
+#include "nfsd.h"
+#include "xdr3.h"
+#include "vfs.h"
+#include "cache.h"
+
+#define NFSDDBG_FACILITY	NFSDDBG_PROC
+#define RETURN_STATUS(st)	{ resp->status = (st); return (st); }
+
+/* NULL call */
+static __be32 nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
+{
+	return nfs_ok;
+}
+
+/*
+ * GETXATTR
+ *
+ * FIXME:
+ *  - Implement shared xattr cache
+ *  - Audit nfs error returns
+ */
+static __be32 nfsd3_proc_getxattr(struct svc_rqst * rqstp,
+				  struct nfsd3_getxattrargs *argp,
+				  struct nfsd3_getxattrres *resp)
+{
+	__be32 nfserr = nfserrno(-EINVAL);
+	svc_fh *fh;
+	void *value;
+	int ret;
+	char *name, *xattr_name = argp->xattr_name;
+	unsigned int size_max = argp->xattr_size_max;
+	unsigned int name_len = argp->xattr_name_len;
+
+	dprintk("nfsd: GETXATTR(3)  %s %.*s %u\n", SVCFH_fmt(&argp->fh),
+	        name_len, xattr_name, size_max);
+
+	if (name_len > XATTR_NAME_MAX)
+		RETURN_STATUS(nfserr);
+
+	if (size_max > XATTR_SIZE_MAX)
+		RETURN_STATUS(nfserr);
+
+	/* Probes must be handled by the client */
+	if (size_max == 0)
+		RETURN_STATUS(nfserr);
+
+	fh = fh_copy(&resp->fh, &argp->fh);
+	nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_READ);
+	if (nfserr)
+		RETURN_STATUS(nfserr);
+
+	/* Convert xdr string to real string */
+	name = kmalloc(name_len + 1, GFP_KERNEL);
+	if (name == NULL)
+		RETURN_STATUS(nfserrno(-ENOMEM));
+
+	ret = snprintf(name, name_len + 1, "%.*s", name_len, xattr_name);
+	if (ret > name_len) {
+		nfserr = nfserrno(-EINVAL);
+		goto cleanup;
+	}
+
+	/* Only the user namespace is currently supported by the server */
+	if (strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) {
+		nfserr = nfserrno(-EINVAL);
+		goto cleanup;
+	}
+
+	ret = nfsd_getxattr(fh->fh_dentry, name, &value);
+	if (ret <= 0) {
+		if (ret == 0)
+			ret = -ENODATA;
+		nfserr = nfserrno(ret);
+		goto cleanup;
+	}
+
+	nfserr = 0;
+	resp->xattr_val = value;
+	resp->xattr_val_len = ret;
+
+cleanup:
+	kfree(name);
+	RETURN_STATUS(nfserr);
+}
+
+/* cribbed from decode pathname */
+static __be32 *decode_xattrname(__be32 *p, char **namp, unsigned int *lenp)
+{
+	char *name;
+	unsigned int i;
+
+	p = xdr_decode_string_inplace(p, namp, lenp, XATTR_NAME_MAX);
+	if (p != NULL)
+		for (i = 0, name = *namp; i < *lenp; i++, name++)
+			if (*name == '\0')
+				return NULL;
+	return p;
+}
+
+static int nfs3svc_decode_getxattrargs(struct svc_rqst *rqstp, __be32 *p,
+				       struct nfsd3_getxattrargs *argp)
+{
+	if (!(p = nfs3svc_decode_fh(p, &argp->fh)))
+		return 0;
+	if (!(p = decode_xattrname(p, &argp->xattr_name, &argp->xattr_name_len)))
+		return 0;
+	argp->xattr_size_max = ntohl(*p++);
+	return xdr_argsize_check(rqstp, p);
+}
+
+static int nfs3svc_encode_getxattrres(struct svc_rqst *rqstp, __be32 *p,
+				      struct nfsd3_getxattrres *resp)
+{
+	p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh);
+	if (resp->status == 0)
+		p = xdr_encode_array(p, resp->xattr_val, resp->xattr_val_len);
+	return xdr_ressize_check(rqstp, p);
+}
+
+static int nfs3svc_release_getxattr(struct svc_rqst *rqstp, __be32 *p,
+				    struct nfsd3_getxattrres *resp)
+{
+	fh_put(&resp->fh);
+	kfree(resp->xattr_val);
+	return 1;
+}
+
+/*
+ * SETXATTR and RMXATTR
+ *
+ * RMXATTR is detected with zero buffer len and XATTR_REPLACE.
+ *
+ */
+static __be32 nfsd3_proc_setxattr(struct svc_rqst * rqstp,
+				  struct nfsd3_setxattrargs *argp,
+				  struct nfsd3_setxattrres *resp)
+{
+	__be32 nfserr = nfserrno(-EINVAL);
+	svc_fh *fh;
+	int ret;
+	char *name, *xattr_name = argp->xattr_name;
+	unsigned int name_len = argp->xattr_name_len;
+	unsigned int val_len = argp->xattr_val_len;
+	unsigned int flags = argp->xattr_flags;
+
+	dprintk("nfsd: SETXATTR(3)  %s %.*s %u %#x\n", SVCFH_fmt(&argp->fh),
+		name_len, xattr_name, val_len, flags);
+
+	if (name_len > XATTR_NAME_MAX)
+		RETURN_STATUS(nfserr);
+
+	if (val_len > XATTR_SIZE_MAX)
+		RETURN_STATUS(nfserr);
+
+	if (flags & ~(XATTR_CREATE|XATTR_REPLACE))
+		RETURN_STATUS(nfserr);
+
+	fh = fh_copy(&resp->fh, &argp->fh);
+	nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR);
+	if (nfserr)
+		RETURN_STATUS(nfserr);
+
+	/* Convert xdr string to real string */
+	name = kmalloc(name_len + 1, GFP_KERNEL);
+	if (name == NULL)
+		RETURN_STATUS(nfserrno(-ENOMEM));
+
+	ret = snprintf(name, name_len + 1, "%.*s", name_len, xattr_name);
+	if (ret > name_len) {
+		nfserr = nfserrno(-EINVAL);
+		goto cleanup;
+	}
+
+	/* Only the user namespace is currently supported by the server */
+	if (strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) {
+		nfserr = nfserrno(-EINVAL);
+		goto cleanup;
+	}
+
+	if (!val_len) {
+		if (flags & ~XATTR_REPLACE) {
+			nfserr = nfserrno(-EINVAL);
+			goto cleanup;
+		}
+		ret = vfs_removexattr(fh->fh_dentry, name);
+	} else
+		ret = vfs_setxattr(fh->fh_dentry, name,
+				   argp->xattr_val, val_len, flags);
+
+	nfserr = nfserrno(ret);
+
+cleanup:
+	kfree(name);
+	RETURN_STATUS(nfserr);
+}
+
+static int nfs3svc_decode_setxattrargs(struct svc_rqst *rqstp, __be32 *p,
+				       struct nfsd3_setxattrargs *argp)
+{
+	if (!(p = nfs3svc_decode_fh(p, &argp->fh)))
+		return 0;
+	if (!(p = decode_xattrname(p, &argp->xattr_name, &argp->xattr_name_len)))
+		return 0;
+	if (!(p = xdr_decode_string_inplace(p, &argp->xattr_val,
+					&argp->xattr_val_len, XATTR_SIZE_MAX)))
+		return 0;
+	argp->xattr_flags = ntohl(*p++);
+	return xdr_argsize_check(rqstp, p);
+}
+
+static int nfs3svc_encode_setxattrres(struct svc_rqst *rqstp, __be32 *p,
+				      struct nfsd3_setxattrres *resp)
+{
+	p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh);
+	return xdr_ressize_check(rqstp, p);
+}
+
+static int nfs3svc_release_setxattr(struct svc_rqst *rqstp, __be32 *p,
+				    struct nfsd3_setxattrres *resp)
+{
+	fh_put(&resp->fh);
+	return 1;
+}
+
+/*
+ * LISTXATTR
+ *
+ * TODO: namespace filtering?
+ */
+static __be32 nfsd3_proc_listxattr(struct svc_rqst * rqstp,
+				   struct nfsd3_listxattrargs *argp,
+				   struct nfsd3_listxattrres *resp)
+{
+	__be32 nfserr = nfserrno(-EINVAL);
+	svc_fh *fh;
+	char *list;
+	int ret;
+	unsigned int list_max = argp->xattr_list_max;
+
+	dprintk("nfsd: LISTXATTR(3)  %s %u\n", SVCFH_fmt(&argp->fh), list_max);
+
+	if (list_max > XATTR_LIST_MAX)
+		RETURN_STATUS(nfserr);
+
+	/* Probes must be handled by the client */
+	if (list_max == 0)
+		RETURN_STATUS(nfserr);
+
+	fh = fh_copy(&resp->fh, &argp->fh);
+	nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_READ);
+	if (nfserr)
+		RETURN_STATUS(nfserr);
+
+	list = kmalloc(list_max, GFP_ATOMIC);
+	if (list == NULL)
+		RETURN_STATUS(nfserrno(-ENOMEM));
+
+	ret = vfs_listxattr(fh->fh_dentry, list, list_max);
+	if (ret <= 0) {
+		if (ret == 0)
+			ret = -ENODATA;
+		RETURN_STATUS(nfserrno(ret));
+	}
+
+	nfserr = 0;
+	resp->xattr_list = list;
+	resp->xattr_list_len = ret;
+
+	RETURN_STATUS(nfserr);
+}
+
+static int nfs3svc_decode_listxattrargs(struct svc_rqst *rqstp, __be32 *p,
+				        struct nfsd3_listxattrargs *argp)
+{
+	if (!(p = nfs3svc_decode_fh(p, &argp->fh)))
+		return 0;
+	argp->xattr_list_max = ntohl(*p++);
+	return xdr_argsize_check(rqstp, p);
+}
+
+static int nfs3svc_encode_listxattrres(struct svc_rqst *rqstp, __be32 *p,
+				       struct nfsd3_listxattrres *resp)
+{
+	p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh);
+	if (resp->status == 0)
+		p = xdr_encode_array(p, resp->xattr_list, resp->xattr_list_len);
+	return xdr_ressize_check(rqstp, p);
+}
+
+static int nfs3svc_release_listxattr(struct svc_rqst *rqstp, __be32 *p,
+				     struct nfsd3_listxattrres *resp)
+{
+	fh_put(&resp->fh);
+	kfree(resp->xattr_list);
+	return 1;
+}
+
+#define ST 1		/* status */
+#define AT 21           /* attributes */
+#define pAT (1+AT)      /* post attributes - conditional */
+
+#define nfs3svc_decode_voidargs		NULL
+#define nfs3svc_release_void		NULL
+#define nfsd3_voidres			nfsd3_voidargs
+struct nfsd3_voidargs { int dummy; };
+
+#define PROC(name, argt, rest, relt, cache, respsize)	\
+ { (svc_procfunc) nfsd3_proc_##name,		\
+   (kxdrproc_t) nfs3svc_decode_##argt##args,	\
+   (kxdrproc_t) nfs3svc_encode_##rest##res,	\
+   (kxdrproc_t) nfs3svc_release_##relt,		\
+   sizeof(struct nfsd3_##argt##args),		\
+   sizeof(struct nfsd3_##rest##res),		\
+   0,						\
+   cache,					\
+   respsize,					\
+ }
+
+#define G_RSZ	(ST+pAT+1+(XATTR_SIZE_MAX>>2))
+#define S_RSZ	(ST+pAT)
+#define L_RSZ	(ST+pAT+1+(XATTR_LIST_MAX>>2))
+
+static struct svc_procedure nfsd_xattr_procedures3[] = {
+  PROC(null,       void,       void,       void,       RC_NOCACHE, ST),
+  PROC(getxattr,   getxattr,   getxattr,   getxattr,   RC_NOCACHE, G_RSZ),
+  PROC(setxattr,   setxattr,   setxattr,   setxattr,   RC_NOCACHE, S_RSZ),
+  PROC(listxattr,  listxattr,  listxattr,  listxattr,  RC_NOCACHE, L_RSZ),
+};
+
+struct svc_version	nfsd_xattr_version3 = {
+	.vs_vers	= 3,
+	.vs_nproc	= 4,
+	.vs_proc	= nfsd_xattr_procedures3,
+	.vs_dispatch	= nfsd_dispatch,
+	.vs_xdrsize	= NFS3_SVC_XDRSIZE,
+	.vs_hidden	= 1,
+};
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 2604c3e..0fc6608 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -1378,6 +1378,8 @@ static int create_proc_exports_entry(void)
 }
 #endif
 
+extern void __init nfsd_prog_init(void);
+
 static int __init init_nfsd(void)
 {
 	int retval;
@@ -1386,6 +1388,7 @@ static int __init init_nfsd(void)
 	retval = nfs4_state_init(); /* nfs4 locking state */
 	if (retval)
 		return retval;
+	nfsd_prog_init();
 	nfsd_stat_init();	/* Statistics */
 	retval = nfsd_reply_cache_init();
 	if (retval)
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 171699e..6f0f472 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -15,6 +15,7 @@
 #include <linux/sunrpc/svcsock.h>
 #include <linux/lockd/bind.h>
 #include <linux/nfsacl.h>
+#include <linux/nfs_xattr.h>
 #include <linux/seq_file.h>
 #include "nfsd.h"
 #include "cache.h"
@@ -87,6 +88,27 @@ static struct svc_stat	nfsd_acl_svcstats = {
 };
 #endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */
 
+#ifdef CONFIG_NFSD_V3_XATTR
+static struct svc_stat	nfsd_xattr_svcstats;
+static struct svc_version *	nfsd_xattr_version[] = {
+	[3] = &nfsd_xattr_version3,
+};
+
+#define NFSD_XATTR_MINVERS	3
+#define NFSD_XATTR_NRVERS	ARRAY_SIZE(nfsd_xattr_version)
+static struct svc_version *nfsd_xattr_versions[NFSD_XATTR_NRVERS];
+
+static struct svc_program	nfsd_xattr_program = {
+	.pg_prog		= NFS_XATTR_PROGRAM,
+	.pg_nvers		= NFSD_XATTR_NRVERS,
+	.pg_vers		= nfsd_xattr_versions,
+	.pg_name		= "nfsxattr",
+	.pg_class		= "nfsd",		/* share nfsd auth */
+	.pg_stats		= &nfsd_xattr_svcstats,
+	.pg_authenticate	= &svc_set_client,
+};
+#endif	/* CONFIG_NFSD_V3_XATTR */
+
 static struct svc_version *	nfsd_version[] = {
 	[2] = &nfsd_version2,
 #if defined(CONFIG_NFSD_V3)
@@ -102,9 +124,6 @@ static struct svc_version *	nfsd_version[] = {
 static struct svc_version *nfsd_versions[NFSD_NRVERS];
 
 struct svc_program		nfsd_program = {
-#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
-	.pg_next		= &nfsd_acl_program,
-#endif
 	.pg_prog		= NFS_PROGRAM,		/* program number */
 	.pg_nvers		= NFSD_NRVERS,		/* nr of entries in nfsd_version */
 	.pg_vers		= nfsd_versions,	/* version table */
@@ -115,6 +134,28 @@ struct svc_program		nfsd_program = {
 
 };
 
+static void __init nfsd_prog_add(struct svc_program *new)
+{
+	struct svc_program *p = &nfsd_program;
+
+	while (p->pg_next)
+		p = p->pg_next;
+
+	p->pg_next = new;
+}
+
+/* Dynamically initialize list of service programs */
+void __init nfsd_prog_init(void)
+{
+#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
+	nfsd_prog_add(&nfsd_acl_program);
+#endif
+
+#ifdef CONFIG_NFSD_V3_XATTR
+	nfsd_prog_add(&nfsd_xattr_program);
+#endif
+}
+
 u32 nfsd_supported_minorversion;
 
 int nfsd_vers(int vers, enum vers_op change)
@@ -128,6 +169,10 @@ int nfsd_vers(int vers, enum vers_op change)
 		if (vers < NFSD_ACL_NRVERS)
 			nfsd_acl_versions[vers] = nfsd_acl_version[vers];
 #endif
+#ifdef CONFIG_NFSD_V3_XATTR
+		if (vers < NFSD_XATTR_NRVERS)
+			nfsd_xattr_versions[vers] = nfsd_xattr_version[vers];
+#endif
 		break;
 	case NFSD_CLEAR:
 		nfsd_versions[vers] = NULL;
@@ -135,6 +180,10 @@ int nfsd_vers(int vers, enum vers_op change)
 		if (vers < NFSD_ACL_NRVERS)
 			nfsd_acl_versions[vers] = NULL;
 #endif
+#ifdef CONFIG_NFSD_V3_XATTR
+		if (vers < NFSD_XATTR_NRVERS)
+			nfsd_xattr_versions[vers] = NULL;
+#endif
 		break;
 	case NFSD_TEST:
 		return nfsd_versions[vers] != NULL;
@@ -213,6 +262,11 @@ void nfsd_reset_versions(void)
 			nfsd_acl_program.pg_vers[i] =
 				nfsd_acl_version[i];
 #endif
+#ifdef CONFIG_NFSD_V3_XATTR
+		for (i = NFSD_XATTR_MINVERS; i < NFSD_XATTR_NRVERS; i++)
+			nfsd_xattr_program.pg_vers[i] =
+				nfsd_xattr_version[i];
+#endif
 	}
 }
 
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 8715d19..72f24ad 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -428,8 +428,9 @@ out_nfserr:
 
 #if defined(CONFIG_NFSD_V2_ACL) || \
     defined(CONFIG_NFSD_V3_ACL) || \
-    defined(CONFIG_NFSD_V4)
-static ssize_t nfsd_getxattr(struct dentry *dentry, char *key, void **buf)
+    defined(CONFIG_NFSD_V4) || \
+    defined(CONFIG_NFSD_V3_XATTR)
+ssize_t nfsd_getxattr(struct dentry *dentry, char *key, void **buf)
 {
 	ssize_t buflen;
 	ssize_t ret;
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
index 4b1de0a..f8132f3 100644
--- a/fs/nfsd/vfs.h
+++ b/fs/nfsd/vfs.h
@@ -98,4 +98,17 @@ struct posix_acl *nfsd_get_posix_acl(struct svc_fh *, int);
 int nfsd_set_posix_acl(struct svc_fh *, int, struct posix_acl *);
 #endif
 
+#if defined(CONFIG_NFSD_V2_ACL) || \
+    defined(CONFIG_NFSD_V3_ACL) || \
+    defined(CONFIG_NFSD_V4) || \
+    defined(CONFIG_NFSD_V3_XATTR)
+ssize_t nfsd_getxattr(struct dentry *dentry, char *key, void **buf);
+#endif
+
+#ifdef CONFIG_NFSD_V3_XATTR
+extern struct svc_version nfsd_xattr_version3;
+#else
+#define nfsd_xattr_version3 NULL
+#endif
+
 #endif /* LINUX_NFSD_VFS_H */
diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h
index 7df980e..e6ccc60 100644
--- a/fs/nfsd/xdr3.h
+++ b/fs/nfsd/xdr3.h
@@ -119,6 +119,27 @@ struct nfsd3_setaclargs {
 	struct posix_acl	*acl_default;
 };
 
+struct nfsd3_getxattrargs {
+	struct svc_fh           fh;
+	char *                  xattr_name;
+	unsigned int            xattr_name_len;
+	unsigned int            xattr_size_max;
+};
+
+struct nfsd3_setxattrargs {
+	struct svc_fh           fh;
+	unsigned int            xattr_flags;
+	char *                  xattr_name;
+	unsigned int            xattr_name_len;
+	char *                  xattr_val;
+	int                     xattr_val_len;
+};
+
+struct nfsd3_listxattrargs {
+	struct svc_fh           fh;
+	unsigned int            xattr_list_max;
+};
+
 struct nfsd3_attrstat {
 	__be32			status;
 	struct svc_fh		fh;
@@ -227,6 +248,25 @@ struct nfsd3_getaclres {
 	struct posix_acl	*acl_default;
 };
 
+struct nfsd3_getxattrres {
+	__be32                  status;
+	struct svc_fh           fh;
+	char *                  xattr_val;
+	unsigned int            xattr_val_len;
+};
+
+struct nfsd3_setxattrres {
+	__be32                  status;
+	struct svc_fh           fh;
+};
+
+struct nfsd3_listxattrres {
+	__be32                  status;
+	struct svc_fh           fh;
+	char *                  xattr_list;
+	unsigned int            xattr_list_len;
+};
+
 /* dummy type for release */
 struct nfsd3_fhandle_pair {
 	__u32			dummy;
@@ -247,6 +287,9 @@ union nfsd3_xdrstore {
 	struct nfsd3_linkargs		linkargs;
 	struct nfsd3_symlinkargs	symlinkargs;
 	struct nfsd3_readdirargs	readdirargs;
+	struct nfsd3_getxattrargs	getxattrargs;
+	struct nfsd3_setxattrargs	setxattrargs;
+	struct nfsd3_listxattrargs	listxattrargs;
 	struct nfsd3_diropres 		diropres;
 	struct nfsd3_accessres		accessres;
 	struct nfsd3_readlinkres	readlinkres;
@@ -260,6 +303,9 @@ union nfsd3_xdrstore {
 	struct nfsd3_pathconfres	pathconfres;
 	struct nfsd3_commitres		commitres;
 	struct nfsd3_getaclres		getaclres;
+	struct nfsd3_getxattrres	getxattrres;
+	struct nfsd3_setxattrres	setxattrres;
+	struct nfsd3_listxattrres	listxattrres;
 };
 
 #define NFS3_SVC_XDRSIZE		sizeof(union nfsd3_xdrstore)
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index 5a3085b..8bde5c1 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -371,7 +371,7 @@ struct svc_version {
 	u32			vs_xdrsize;	/* xdrsize needed for this version */
 
 	unsigned int		vs_hidden : 1;	/* Don't register with portmapper.
-						 * Only used for nfsacl so far. */
+						 * Used for nfsacl and nfsxattr. */
 
 	/* Override dispatch function (e.g. when caching replies).
 	 * A return value of 0 means drop the request. 
-- 
1.6.3.3


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 5/6] xattr: add new top level nfsd namespace and implement ext3 support
  2010-03-08 10:42 ` [PATCH 0/6][v4][RFC] NFSv3: implement extended attribute protocol (XATTR) James Morris
                     ` (2 preceding siblings ...)
  2010-03-08 10:45   ` [PATCH 4/6] NFSv3: add server " James Morris
@ 2010-03-08 10:46   ` James Morris
       [not found]   ` <alpine.LRH.2.00.1003082122340.6314-CK9fWmtY32x9JUWOpEiw7w@public.gmane.org>
  2010-03-09  3:59   ` [PATCH 0/6][v4][RFC] NFSv3: implement extended attribute protocol (XATTR) Brad Boyer
  5 siblings, 0 replies; 39+ messages in thread
From: James Morris @ 2010-03-08 10:46 UTC (permalink / raw)
  To: linux-nfs
  Cc: linux-security-module, Trond Myklebust, J. Bruce Fields,
	Neil Brown, linux-fsdevel

Add a new top-level 'nfsd' xattr namespace for use by the NFSv3 server
when storing xattrs provided by clients using the XATTR
protocol.

Also implement filesystem-level support for the new namespace for the
ext3 filesystem for testing.

Signed-off-by: James Morris <jmorris@namei.org>
---
 fs/ext3/Makefile      |    2 +-
 fs/ext3/xattr.c       |    2 +
 fs/ext3/xattr.h       |    2 +
 fs/ext3/xattr_nfsd.c  |   58 +++++++++++++++++++++++++++++++++++++++++++++++++
 fs/xattr.c            |    6 +++-
 include/linux/xattr.h |    3 ++
 6 files changed, 70 insertions(+), 3 deletions(-)
 create mode 100644 fs/ext3/xattr_nfsd.c

diff --git a/fs/ext3/Makefile b/fs/ext3/Makefile
index e77766a..216ca8a 100644
--- a/fs/ext3/Makefile
+++ b/fs/ext3/Makefile
@@ -7,6 +7,6 @@ obj-$(CONFIG_EXT3_FS) += ext3.o
 ext3-y	:= balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
 	   ioctl.o namei.o super.o symlink.o hash.o resize.o ext3_jbd.o
 
-ext3-$(CONFIG_EXT3_FS_XATTR)	 += xattr.o xattr_user.o xattr_trusted.o
+ext3-$(CONFIG_EXT3_FS_XATTR)	 += xattr.o xattr_user.o xattr_trusted.o xattr_nfsd.o
 ext3-$(CONFIG_EXT3_FS_POSIX_ACL) += acl.o
 ext3-$(CONFIG_EXT3_FS_SECURITY)	 += xattr_security.o
diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c
index 66895cc..e05ae22 100644
--- a/fs/ext3/xattr.c
+++ b/fs/ext3/xattr.c
@@ -114,6 +114,7 @@ static struct xattr_handler *ext3_xattr_handler_map[] = {
 #ifdef CONFIG_EXT3_FS_SECURITY
 	[EXT3_XATTR_INDEX_SECURITY]	     = &ext3_xattr_security_handler,
 #endif
+	[EXT3_XATTR_INDEX_NFSD]		     = &ext3_xattr_nfsd_handler,
 };
 
 struct xattr_handler *ext3_xattr_handlers[] = {
@@ -126,6 +127,7 @@ struct xattr_handler *ext3_xattr_handlers[] = {
 #ifdef CONFIG_EXT3_FS_SECURITY
 	&ext3_xattr_security_handler,
 #endif
+	&ext3_xattr_nfsd_handler,
 	NULL
 };
 
diff --git a/fs/ext3/xattr.h b/fs/ext3/xattr.h
index 148a4df..e06e90f 100644
--- a/fs/ext3/xattr.h
+++ b/fs/ext3/xattr.h
@@ -21,6 +21,7 @@
 #define EXT3_XATTR_INDEX_TRUSTED		4
 #define	EXT3_XATTR_INDEX_LUSTRE			5
 #define EXT3_XATTR_INDEX_SECURITY	        6
+#define EXT3_XATTR_INDEX_NFSD			7
 
 struct ext3_xattr_header {
 	__le32	h_magic;	/* magic number for identification */
@@ -63,6 +64,7 @@ extern struct xattr_handler ext3_xattr_trusted_handler;
 extern struct xattr_handler ext3_xattr_acl_access_handler;
 extern struct xattr_handler ext3_xattr_acl_default_handler;
 extern struct xattr_handler ext3_xattr_security_handler;
+extern struct xattr_handler ext3_xattr_nfsd_handler;
 
 extern ssize_t ext3_listxattr(struct dentry *, char *, size_t);
 
diff --git a/fs/ext3/xattr_nfsd.c b/fs/ext3/xattr_nfsd.c
new file mode 100644
index 0000000..890ccd9
--- /dev/null
+++ b/fs/ext3/xattr_nfsd.c
@@ -0,0 +1,58 @@
+/*
+ * linux/fs/ext3/xattr_nfsd.c
+ * Handler for nfsd extended attributes.
+ *
+ * Copyright (C) 2003 by Andreas Gruenbacher, <a.gruenbacher@computer.org>
+ * Copyright (C) 2010 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ */
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/capability.h>
+#include <linux/fs.h>
+#include <linux/ext3_jbd.h>
+#include <linux/ext3_fs.h>
+#include "xattr.h"
+
+static size_t ext3_xattr_nfsd_list(struct dentry *dentry, char *list,
+				   size_t list_size, const char *name,
+				   size_t name_len, int type)
+{
+	const size_t prefix_len = XATTR_NFSD_PREFIX_LEN;
+	const size_t total_len = prefix_len + name_len + 1;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return 0;
+
+	if (list && total_len <= list_size) {
+		memcpy(list, XATTR_NFSD_PREFIX, prefix_len);
+		memcpy(list+prefix_len, name, name_len);
+		list[prefix_len + name_len] = '\0';
+	}
+	return total_len;
+}
+
+static int ext3_xattr_nfsd_get(struct dentry *dentry, const char *name,
+			       void *buffer, size_t size, int type)
+{
+	if (strcmp(name, "") == 0)
+		return -EINVAL;
+	return ext3_xattr_get(dentry->d_inode, EXT3_XATTR_INDEX_NFSD,
+			      name, buffer, size);
+}
+
+static int ext3_xattr_nfsd_set(struct dentry *dentry, const char *name,
+			       const void *value, size_t size, int flags,
+			       int type)
+{
+	if (strcmp(name, "") == 0)
+		return -EINVAL;
+	return ext3_xattr_set(dentry->d_inode, EXT3_XATTR_INDEX_NFSD, name,
+			      value, size, flags);
+}
+
+struct xattr_handler ext3_xattr_nfsd_handler = {
+	.prefix	= XATTR_NFSD_PREFIX,
+	.list	= ext3_xattr_nfsd_list,
+	.get	= ext3_xattr_nfsd_get,
+	.set	= ext3_xattr_nfsd_set,
+};
diff --git a/fs/xattr.c b/fs/xattr.c
index 46f87e8..87b8c8c 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -46,9 +46,11 @@ xattr_permission(struct inode *inode, const char *name, int mask)
 		return 0;
 
 	/*
-	 * The trusted.* namespace can only be accessed by a privileged user.
+	 * The trusted.* and nfsd.* namespaces can only be accessed by a
+	 * privileged user.
 	 */
-	if (!strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN))
+	if (!strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) ||
+	    !strncmp(name, XATTR_NFSD_PREFIX, XATTR_NFSD_PREFIX_LEN))
 		return (capable(CAP_SYS_ADMIN) ? 0 : -EPERM);
 
 	/* In user.* namespace, only regular files and directories can have
diff --git a/include/linux/xattr.h b/include/linux/xattr.h
index fb9b7e6..5b954a2 100644
--- a/include/linux/xattr.h
+++ b/include/linux/xattr.h
@@ -33,6 +33,9 @@
 #define XATTR_USER_PREFIX "user."
 #define XATTR_USER_PREFIX_LEN (sizeof (XATTR_USER_PREFIX) - 1)
 
+#define XATTR_NFSD_PREFIX "nfsd."
+#define XATTR_NFSD_PREFIX_LEN (sizeof (XATTR_NFSD_PREFIX) - 1)
+
 struct inode;
 struct dentry;
 
-- 
1.6.3.3


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 6/6] NFSv3: Add server namespace support for XATTR protocol implementation
       [not found]   ` <alpine.LRH.2.00.1003082122340.6314-CK9fWmtY32x9JUWOpEiw7w@public.gmane.org>
@ 2010-03-08 10:47       ` James Morris
  2010-03-08 10:47       ` James Morris
  1 sibling, 0 replies; 39+ messages in thread
From: James Morris @ 2010-03-08 10:47 UTC (permalink / raw)
  To: linux-nfs-u79uwXL29TY76Z2rM5mHXA
  Cc: linux-security-module-u79uwXL29TY76Z2rM5mHXA, Trond Myklebust,
	J. Bruce Fields, Neil Brown,
	linux-fsdevel-u79uwXL29TY76Z2rM5mHXA

Add support for a server namespace for storing and retrieving
client-supplied xattrs.  All xattrs are now stored on the server under
the 'nfsd' namespace, and are not interpreted by the server at all.
This allows clients to utilize arbitrary xattr namespaces and for the
server to act only as a storage mechanism for the xattrs.

Currently, only the user and trusted namespaces are supported by
the client, as system and security namespaces require further analysis,
and some special-case handling will be required (for security.selinux,
at least).

NFS ACLs continue to work as expected, because they implement a
hard-coded system xattr namespace which is invoked before the
NFS layer.  e.g. any access to a system.posix_acl_access xattr
is invokes the NFS_ACL protocol.

Signed-off-by: James Morris <jmorris-gx6/JNMH7DfYtjvyW6yDsg@public.gmane.org>
---
 fs/nfs/Kconfig          |   10 ------
 fs/nfs/Makefile         |    2 +-
 fs/nfs/internal.h       |    3 +-
 fs/nfs/nfs3xattr.c      |    3 +-
 fs/nfs/nfs3xattr_user.c |   53 ------------------------------
 fs/nfsd/nfs3xattr.c     |   83 +++++++++++++++++++++++++++++++---------------
 fs/nfsd/vfs.h           |   10 ++++++
 7 files changed, 71 insertions(+), 93 deletions(-)
 delete mode 100644 fs/nfs/nfs3xattr_user.c

diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig
index e0e2535..317259e 100644
--- a/fs/nfs/Kconfig
+++ b/fs/nfs/Kconfig
@@ -86,16 +86,6 @@ config NFS_V3_XATTR
 
 	  If unsure, say N.
 
-config NFS_V3_XATTR_USER
-	bool "Extended attributes in the user namespace (EXPERIMENTAL)"
-	depends on NFS_V3_XATTR
-	help
-	  This option selects extended attributes in the user.* namespace,
-	  which are arbitrarily named and managed by users, and conveyed
-	  via the XATTR protocol extension for NFS version 3.
-
-	  If unsure, say N.
-
 config NFS_V4
 	bool "NFS client support for NFS version 4 (EXPERIMENTAL)"
 	depends on NFS_FS && EXPERIMENTAL
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile
index 54018ee..b289d7e 100644
--- a/fs/nfs/Makefile
+++ b/fs/nfs/Makefile
@@ -12,7 +12,7 @@ nfs-$(CONFIG_ROOT_NFS)	+= nfsroot.o
 nfs-$(CONFIG_NFS_V3)	+= nfs3proc.o nfs3xdr.o
 nfs-$(CONFIG_NFS_V3_ACL)	+= nfs3acl.o
 nfs-$(CONFIG_NFS_V3_XATTR_API)	+= nfs3xattr.o
-nfs-$(CONFIG_NFS_V3_XATTR_USER)	+= nfs3xattr_user.o
+nfs-$(CONFIG_NFS_V3_XATTR)	+= nfs3xattr_handlers.o
 nfs-$(CONFIG_NFS_V4)	+= nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \
 			   delegation.o idmap.o \
 			   callback.o callback_xdr.o callback_proc.o \
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 3661a64..a631daf 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -296,8 +296,9 @@ extern int nfs3_proc_setxattr(struct inode *inode, const char *namespace,
 extern int nfs3_proc_listxattr(struct inode *inode, char *list,
 			       size_t list_len);
 
-/* nfs3xattr_user.c */
+/* nfs3xattr_handers.c */
 extern struct xattr_handler nfs3_xattr_user_handler;
+extern struct xattr_handler nfs3_xattr_trusted_handler;
 
 /* nfs3acl.c */
 extern struct xattr_handler nfs3_xattr_acl_access_handler;
diff --git a/fs/nfs/nfs3xattr.c b/fs/nfs/nfs3xattr.c
index 7ff651b..a1e054f 100644
--- a/fs/nfs/nfs3xattr.c
+++ b/fs/nfs/nfs3xattr.c
@@ -19,8 +19,9 @@
 #define NFSDBG_FACILITY	NFSDBG_PROC
 
 struct xattr_handler *nfs3_xattr_handlers[] = {
-#ifdef CONFIG_NFS_V3_XATTR_USER
+#ifdef CONFIG_NFS_V3_XATTR
 	&nfs3_xattr_user_handler,
+	&nfs3_xattr_trusted_handler,
 #endif
 #ifdef CONFIG_NFS_V3_ACL
 	&nfs3_xattr_acl_access_handler,
diff --git a/fs/nfs/nfs3xattr_user.c b/fs/nfs/nfs3xattr_user.c
deleted file mode 100644
index c544fcb..0000000
--- a/fs/nfs/nfs3xattr_user.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Support for extended attributes in the the user.* namespace, which are
- * arbitrarily named and managed by users and conveyed via the XATTR
- * protocol extension.
- *
- * Copyright (C) 2009 Red Hat, Inc., James Morris <jmorris-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2,
- * as published by the Free Software Foundation.
- */
-#include <linux/fs.h>
-#include <linux/nfs.h>
-#include <linux/nfs3.h>
-#include <linux/nfs_fs.h>
-
-#include "internal.h"
-
-#define NFSDBG_FACILITY	NFSDBG_PROC
-
-/*
- * The generic xattr code will call this for each helper, which is ok for
- * now, because we only support this single namespace.  If support is
- * expanded to more namespaces, we we'll need a custom listxattr operation.
- */
-static size_t nfs3_user_xattr_list(struct dentry *dentry, char *list,
-				   size_t list_len, const char *name,
-				   size_t name_len, int hflags)
-{
-	return nfs3_proc_listxattr(dentry->d_inode, list, list_len);
-}
-
-static int nfs3_user_xattr_get(struct dentry *dentry, const char *name,
-			       void *buffer, size_t size, int hflags)
-{
-	return nfs3_proc_getxattr(dentry->d_inode, XATTR_USER_PREFIX,
-				  name, buffer, size);
-}
-
-static int nfs3_user_xattr_set(struct dentry *dentry, const char *name,
-			       const void *value, size_t size,
-			       int flags, int hflags)
-{
-	return nfs3_proc_setxattr(dentry->d_inode, XATTR_USER_PREFIX,
-				  name, value, size, flags);
-}
-
-struct xattr_handler nfs3_xattr_user_handler = {
-	.prefix = XATTR_USER_PREFIX,
-	.list   = nfs3_user_xattr_list,
-	.get    = nfs3_user_xattr_get,
-	.set    = nfs3_user_xattr_set,
-};
diff --git a/fs/nfsd/nfs3xattr.c b/fs/nfsd/nfs3xattr.c
index b5a5faa..41e0aef 100644
--- a/fs/nfsd/nfs3xattr.c
+++ b/fs/nfsd/nfs3xattr.c
@@ -47,11 +47,12 @@ static __be32 nfsd3_proc_getxattr(struct svc_rqst * rqstp,
 	char *name, *xattr_name = argp->xattr_name;
 	unsigned int size_max = argp->xattr_size_max;
 	unsigned int name_len = argp->xattr_name_len;
+	unsigned int name_tot_len = name_len + NFSD_XATTR_PREFIX_LEN;
 
 	dprintk("nfsd: GETXATTR(3)  %s %.*s %u\n", SVCFH_fmt(&argp->fh),
 	        name_len, xattr_name, size_max);
 
-	if (name_len > XATTR_NAME_MAX)
+	if (name_tot_len > XATTR_NAME_MAX)
 		RETURN_STATUS(nfserr);
 
 	if (size_max > XATTR_SIZE_MAX)
@@ -66,19 +67,14 @@ static __be32 nfsd3_proc_getxattr(struct svc_rqst * rqstp,
 	if (nfserr)
 		RETURN_STATUS(nfserr);
 
-	/* Convert xdr string to real string */
-	name = kmalloc(name_len + 1, GFP_KERNEL);
+	/* Convert xattr name to real string and add local prefix */
+	name = kmalloc(name_tot_len + 1, GFP_KERNEL);
 	if (name == NULL)
 		RETURN_STATUS(nfserrno(-ENOMEM));
 
-	ret = snprintf(name, name_len + 1, "%.*s", name_len, xattr_name);
-	if (ret > name_len) {
-		nfserr = nfserrno(-EINVAL);
-		goto cleanup;
-	}
-
-	/* Only the user namespace is currently supported by the server */
-	if (strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) {
+	ret = snprintf(name, name_tot_len + 1, "%s%.*s",
+		       NFSD_XATTR_PREFIX, name_len, xattr_name);
+	if (ret > name_tot_len) {
 		nfserr = nfserrno(-EINVAL);
 		goto cleanup;
 	}
@@ -159,11 +155,12 @@ static __be32 nfsd3_proc_setxattr(struct svc_rqst * rqstp,
 	unsigned int name_len = argp->xattr_name_len;
 	unsigned int val_len = argp->xattr_val_len;
 	unsigned int flags = argp->xattr_flags;
+	unsigned int name_tot_len = name_len + NFSD_XATTR_PREFIX_LEN;
 
 	dprintk("nfsd: SETXATTR(3)  %s %.*s %u %#x\n", SVCFH_fmt(&argp->fh),
 		name_len, xattr_name, val_len, flags);
 
-	if (name_len > XATTR_NAME_MAX)
+	if (name_tot_len > XATTR_NAME_MAX)
 		RETURN_STATUS(nfserr);
 
 	if (val_len > XATTR_SIZE_MAX)
@@ -177,19 +174,15 @@ static __be32 nfsd3_proc_setxattr(struct svc_rqst * rqstp,
 	if (nfserr)
 		RETURN_STATUS(nfserr);
 
-	/* Convert xdr string to real string */
-	name = kmalloc(name_len + 1, GFP_KERNEL);
+	/* Convert xattr name to real string and add prefix */
+	name = kmalloc(name_tot_len + 1, GFP_KERNEL);
 	if (name == NULL)
 		RETURN_STATUS(nfserrno(-ENOMEM));
 
-	ret = snprintf(name, name_len + 1, "%.*s", name_len, xattr_name);
-	if (ret > name_len) {
-		nfserr = nfserrno(-EINVAL);
-		goto cleanup;
-	}
+	ret = snprintf(name, name_tot_len + 1, "%s%.*s",
+		       NFSD_XATTR_PREFIX, name_len, xattr_name);
 
-	/* Only the user namespace is currently supported by the server */
-	if (strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) {
+	if (ret > name_tot_len) {
 		nfserr = nfserrno(-EINVAL);
 		goto cleanup;
 	}
@@ -240,9 +233,30 @@ static int nfs3svc_release_setxattr(struct svc_rqst *rqstp, __be32 *p,
 }
 
 /*
+ * Search the xattr list for those which match the local NFSD prefix. For
+ * each, strip the prefix and copy out the rest of the xattr.
+ */
+static int nfsd3_filter_xattrs(const char *in, char *out, int i_len)
+{
+	int i_idx = 0, o_idx = 0;
+
+	while (i_idx < i_len) {
+		const char *curr = in + i_idx;
+		int c_len = strlen(curr);
+
+		if (!strncmp(NFSD_XATTR_PREFIX, curr, NFSD_XATTR_PREFIX_LEN)) {
+			strcpy(out + o_idx, curr + NFSD_XATTR_PREFIX_LEN);
+			o_idx += c_len - NFSD_XATTR_PREFIX_LEN + 1;
+		}
+
+		i_idx += c_len + 1;
+	}
+
+	return o_idx;
+}
+
+/*
  * LISTXATTR
- *
- * TODO: namespace filtering?
  */
 static __be32 nfsd3_proc_listxattr(struct svc_rqst * rqstp,
 				   struct nfsd3_listxattrargs *argp,
@@ -250,8 +264,8 @@ static __be32 nfsd3_proc_listxattr(struct svc_rqst * rqstp,
 {
 	__be32 nfserr = nfserrno(-EINVAL);
 	svc_fh *fh;
-	char *list;
-	int ret;
+	char *list, *f_list;
+	int ret, f_len;
 	unsigned int list_max = argp->xattr_list_max;
 
 	dprintk("nfsd: LISTXATTR(3)  %s %u\n", SVCFH_fmt(&argp->fh), list_max);
@@ -276,12 +290,27 @@ static __be32 nfsd3_proc_listxattr(struct svc_rqst * rqstp,
 	if (ret <= 0) {
 		if (ret == 0)
 			ret = -ENODATA;
+		kfree(list);
 		RETURN_STATUS(nfserrno(ret));
 	}
 
+	/*
+	 * Filter the xattr list: translate and return only those stored
+	 * with the correct prefix.  The list is a series of nul-terminated
+	 * strings.
+	 */
+	f_list = kmalloc(ret, GFP_ATOMIC);
+	if (f_list == NULL) {
+		kfree(list);
+		RETURN_STATUS(nfserrno(-ENOMEM));
+	}
+
+	f_len = nfsd3_filter_xattrs(list, f_list, ret);
+	kfree(list);
+
 	nfserr = 0;
-	resp->xattr_list = list;
-	resp->xattr_list_len = ret;
+	resp->xattr_list = f_list;
+	resp->xattr_list_len = f_len;
 
 	RETURN_STATUS(nfserr);
 }
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
index f8132f3..23028ee 100644
--- a/fs/nfsd/vfs.h
+++ b/fs/nfsd/vfs.h
@@ -107,6 +107,16 @@ ssize_t nfsd_getxattr(struct dentry *dentry, char *key, void **buf);
 
 #ifdef CONFIG_NFSD_V3_XATTR
 extern struct svc_version nfsd_xattr_version3;
+
+/*
+ * Translation prefix for local storage of remote xattrs.  This is currently
+ * hard-coded, but could be made a configurable per-export option.  We're
+ * using the user namespace, which is widely supported by filesystems, and
+ * allows arbitrary manipulation.
+ */
+#define NFSD_XATTR_PREFIX "nfsd."
+#define NFSD_XATTR_PREFIX_LEN (strlen(NFSD_XATTR_PREFIX))
+
 #else
 #define nfsd_xattr_version3 NULL
 #endif
-- 
1.6.3.3

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 6/6] NFSv3: Add server namespace support for XATTR protocol implementation
@ 2010-03-08 10:47       ` James Morris
  0 siblings, 0 replies; 39+ messages in thread
From: James Morris @ 2010-03-08 10:47 UTC (permalink / raw)
  To: linux-nfs
  Cc: linux-security-module, Trond Myklebust, J. Bruce Fields,
	Neil Brown, linux-fsdevel

Add support for a server namespace for storing and retrieving
client-supplied xattrs.  All xattrs are now stored on the server under
the 'nfsd' namespace, and are not interpreted by the server at all.
This allows clients to utilize arbitrary xattr namespaces and for the
server to act only as a storage mechanism for the xattrs.

Currently, only the user and trusted namespaces are supported by
the client, as system and security namespaces require further analysis,
and some special-case handling will be required (for security.selinux,
at least).

NFS ACLs continue to work as expected, because they implement a
hard-coded system xattr namespace which is invoked before the
NFS layer.  e.g. any access to a system.posix_acl_access xattr
is invokes the NFS_ACL protocol.

Signed-off-by: James Morris <jmorris@namei.org>
---
 fs/nfs/Kconfig          |   10 ------
 fs/nfs/Makefile         |    2 +-
 fs/nfs/internal.h       |    3 +-
 fs/nfs/nfs3xattr.c      |    3 +-
 fs/nfs/nfs3xattr_user.c |   53 ------------------------------
 fs/nfsd/nfs3xattr.c     |   83 +++++++++++++++++++++++++++++++---------------
 fs/nfsd/vfs.h           |   10 ++++++
 7 files changed, 71 insertions(+), 93 deletions(-)
 delete mode 100644 fs/nfs/nfs3xattr_user.c

diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig
index e0e2535..317259e 100644
--- a/fs/nfs/Kconfig
+++ b/fs/nfs/Kconfig
@@ -86,16 +86,6 @@ config NFS_V3_XATTR
 
 	  If unsure, say N.
 
-config NFS_V3_XATTR_USER
-	bool "Extended attributes in the user namespace (EXPERIMENTAL)"
-	depends on NFS_V3_XATTR
-	help
-	  This option selects extended attributes in the user.* namespace,
-	  which are arbitrarily named and managed by users, and conveyed
-	  via the XATTR protocol extension for NFS version 3.
-
-	  If unsure, say N.
-
 config NFS_V4
 	bool "NFS client support for NFS version 4 (EXPERIMENTAL)"
 	depends on NFS_FS && EXPERIMENTAL
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile
index 54018ee..b289d7e 100644
--- a/fs/nfs/Makefile
+++ b/fs/nfs/Makefile
@@ -12,7 +12,7 @@ nfs-$(CONFIG_ROOT_NFS)	+= nfsroot.o
 nfs-$(CONFIG_NFS_V3)	+= nfs3proc.o nfs3xdr.o
 nfs-$(CONFIG_NFS_V3_ACL)	+= nfs3acl.o
 nfs-$(CONFIG_NFS_V3_XATTR_API)	+= nfs3xattr.o
-nfs-$(CONFIG_NFS_V3_XATTR_USER)	+= nfs3xattr_user.o
+nfs-$(CONFIG_NFS_V3_XATTR)	+= nfs3xattr_handlers.o
 nfs-$(CONFIG_NFS_V4)	+= nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \
 			   delegation.o idmap.o \
 			   callback.o callback_xdr.o callback_proc.o \
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 3661a64..a631daf 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -296,8 +296,9 @@ extern int nfs3_proc_setxattr(struct inode *inode, const char *namespace,
 extern int nfs3_proc_listxattr(struct inode *inode, char *list,
 			       size_t list_len);
 
-/* nfs3xattr_user.c */
+/* nfs3xattr_handers.c */
 extern struct xattr_handler nfs3_xattr_user_handler;
+extern struct xattr_handler nfs3_xattr_trusted_handler;
 
 /* nfs3acl.c */
 extern struct xattr_handler nfs3_xattr_acl_access_handler;
diff --git a/fs/nfs/nfs3xattr.c b/fs/nfs/nfs3xattr.c
index 7ff651b..a1e054f 100644
--- a/fs/nfs/nfs3xattr.c
+++ b/fs/nfs/nfs3xattr.c
@@ -19,8 +19,9 @@
 #define NFSDBG_FACILITY	NFSDBG_PROC
 
 struct xattr_handler *nfs3_xattr_handlers[] = {
-#ifdef CONFIG_NFS_V3_XATTR_USER
+#ifdef CONFIG_NFS_V3_XATTR
 	&nfs3_xattr_user_handler,
+	&nfs3_xattr_trusted_handler,
 #endif
 #ifdef CONFIG_NFS_V3_ACL
 	&nfs3_xattr_acl_access_handler,
diff --git a/fs/nfs/nfs3xattr_user.c b/fs/nfs/nfs3xattr_user.c
deleted file mode 100644
index c544fcb..0000000
--- a/fs/nfs/nfs3xattr_user.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Support for extended attributes in the the user.* namespace, which are
- * arbitrarily named and managed by users and conveyed via the XATTR
- * protocol extension.
- *
- * Copyright (C) 2009 Red Hat, Inc., James Morris <jmorris@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2,
- * as published by the Free Software Foundation.
- */
-#include <linux/fs.h>
-#include <linux/nfs.h>
-#include <linux/nfs3.h>
-#include <linux/nfs_fs.h>
-
-#include "internal.h"
-
-#define NFSDBG_FACILITY	NFSDBG_PROC
-
-/*
- * The generic xattr code will call this for each helper, which is ok for
- * now, because we only support this single namespace.  If support is
- * expanded to more namespaces, we we'll need a custom listxattr operation.
- */
-static size_t nfs3_user_xattr_list(struct dentry *dentry, char *list,
-				   size_t list_len, const char *name,
-				   size_t name_len, int hflags)
-{
-	return nfs3_proc_listxattr(dentry->d_inode, list, list_len);
-}
-
-static int nfs3_user_xattr_get(struct dentry *dentry, const char *name,
-			       void *buffer, size_t size, int hflags)
-{
-	return nfs3_proc_getxattr(dentry->d_inode, XATTR_USER_PREFIX,
-				  name, buffer, size);
-}
-
-static int nfs3_user_xattr_set(struct dentry *dentry, const char *name,
-			       const void *value, size_t size,
-			       int flags, int hflags)
-{
-	return nfs3_proc_setxattr(dentry->d_inode, XATTR_USER_PREFIX,
-				  name, value, size, flags);
-}
-
-struct xattr_handler nfs3_xattr_user_handler = {
-	.prefix = XATTR_USER_PREFIX,
-	.list   = nfs3_user_xattr_list,
-	.get    = nfs3_user_xattr_get,
-	.set    = nfs3_user_xattr_set,
-};
diff --git a/fs/nfsd/nfs3xattr.c b/fs/nfsd/nfs3xattr.c
index b5a5faa..41e0aef 100644
--- a/fs/nfsd/nfs3xattr.c
+++ b/fs/nfsd/nfs3xattr.c
@@ -47,11 +47,12 @@ static __be32 nfsd3_proc_getxattr(struct svc_rqst * rqstp,
 	char *name, *xattr_name = argp->xattr_name;
 	unsigned int size_max = argp->xattr_size_max;
 	unsigned int name_len = argp->xattr_name_len;
+	unsigned int name_tot_len = name_len + NFSD_XATTR_PREFIX_LEN;
 
 	dprintk("nfsd: GETXATTR(3)  %s %.*s %u\n", SVCFH_fmt(&argp->fh),
 	        name_len, xattr_name, size_max);
 
-	if (name_len > XATTR_NAME_MAX)
+	if (name_tot_len > XATTR_NAME_MAX)
 		RETURN_STATUS(nfserr);
 
 	if (size_max > XATTR_SIZE_MAX)
@@ -66,19 +67,14 @@ static __be32 nfsd3_proc_getxattr(struct svc_rqst * rqstp,
 	if (nfserr)
 		RETURN_STATUS(nfserr);
 
-	/* Convert xdr string to real string */
-	name = kmalloc(name_len + 1, GFP_KERNEL);
+	/* Convert xattr name to real string and add local prefix */
+	name = kmalloc(name_tot_len + 1, GFP_KERNEL);
 	if (name == NULL)
 		RETURN_STATUS(nfserrno(-ENOMEM));
 
-	ret = snprintf(name, name_len + 1, "%.*s", name_len, xattr_name);
-	if (ret > name_len) {
-		nfserr = nfserrno(-EINVAL);
-		goto cleanup;
-	}
-
-	/* Only the user namespace is currently supported by the server */
-	if (strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) {
+	ret = snprintf(name, name_tot_len + 1, "%s%.*s",
+		       NFSD_XATTR_PREFIX, name_len, xattr_name);
+	if (ret > name_tot_len) {
 		nfserr = nfserrno(-EINVAL);
 		goto cleanup;
 	}
@@ -159,11 +155,12 @@ static __be32 nfsd3_proc_setxattr(struct svc_rqst * rqstp,
 	unsigned int name_len = argp->xattr_name_len;
 	unsigned int val_len = argp->xattr_val_len;
 	unsigned int flags = argp->xattr_flags;
+	unsigned int name_tot_len = name_len + NFSD_XATTR_PREFIX_LEN;
 
 	dprintk("nfsd: SETXATTR(3)  %s %.*s %u %#x\n", SVCFH_fmt(&argp->fh),
 		name_len, xattr_name, val_len, flags);
 
-	if (name_len > XATTR_NAME_MAX)
+	if (name_tot_len > XATTR_NAME_MAX)
 		RETURN_STATUS(nfserr);
 
 	if (val_len > XATTR_SIZE_MAX)
@@ -177,19 +174,15 @@ static __be32 nfsd3_proc_setxattr(struct svc_rqst * rqstp,
 	if (nfserr)
 		RETURN_STATUS(nfserr);
 
-	/* Convert xdr string to real string */
-	name = kmalloc(name_len + 1, GFP_KERNEL);
+	/* Convert xattr name to real string and add prefix */
+	name = kmalloc(name_tot_len + 1, GFP_KERNEL);
 	if (name == NULL)
 		RETURN_STATUS(nfserrno(-ENOMEM));
 
-	ret = snprintf(name, name_len + 1, "%.*s", name_len, xattr_name);
-	if (ret > name_len) {
-		nfserr = nfserrno(-EINVAL);
-		goto cleanup;
-	}
+	ret = snprintf(name, name_tot_len + 1, "%s%.*s",
+		       NFSD_XATTR_PREFIX, name_len, xattr_name);
 
-	/* Only the user namespace is currently supported by the server */
-	if (strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) {
+	if (ret > name_tot_len) {
 		nfserr = nfserrno(-EINVAL);
 		goto cleanup;
 	}
@@ -240,9 +233,30 @@ static int nfs3svc_release_setxattr(struct svc_rqst *rqstp, __be32 *p,
 }
 
 /*
+ * Search the xattr list for those which match the local NFSD prefix. For
+ * each, strip the prefix and copy out the rest of the xattr.
+ */
+static int nfsd3_filter_xattrs(const char *in, char *out, int i_len)
+{
+	int i_idx = 0, o_idx = 0;
+
+	while (i_idx < i_len) {
+		const char *curr = in + i_idx;
+		int c_len = strlen(curr);
+
+		if (!strncmp(NFSD_XATTR_PREFIX, curr, NFSD_XATTR_PREFIX_LEN)) {
+			strcpy(out + o_idx, curr + NFSD_XATTR_PREFIX_LEN);
+			o_idx += c_len - NFSD_XATTR_PREFIX_LEN + 1;
+		}
+
+		i_idx += c_len + 1;
+	}
+
+	return o_idx;
+}
+
+/*
  * LISTXATTR
- *
- * TODO: namespace filtering?
  */
 static __be32 nfsd3_proc_listxattr(struct svc_rqst * rqstp,
 				   struct nfsd3_listxattrargs *argp,
@@ -250,8 +264,8 @@ static __be32 nfsd3_proc_listxattr(struct svc_rqst * rqstp,
 {
 	__be32 nfserr = nfserrno(-EINVAL);
 	svc_fh *fh;
-	char *list;
-	int ret;
+	char *list, *f_list;
+	int ret, f_len;
 	unsigned int list_max = argp->xattr_list_max;
 
 	dprintk("nfsd: LISTXATTR(3)  %s %u\n", SVCFH_fmt(&argp->fh), list_max);
@@ -276,12 +290,27 @@ static __be32 nfsd3_proc_listxattr(struct svc_rqst * rqstp,
 	if (ret <= 0) {
 		if (ret == 0)
 			ret = -ENODATA;
+		kfree(list);
 		RETURN_STATUS(nfserrno(ret));
 	}
 
+	/*
+	 * Filter the xattr list: translate and return only those stored
+	 * with the correct prefix.  The list is a series of nul-terminated
+	 * strings.
+	 */
+	f_list = kmalloc(ret, GFP_ATOMIC);
+	if (f_list == NULL) {
+		kfree(list);
+		RETURN_STATUS(nfserrno(-ENOMEM));
+	}
+
+	f_len = nfsd3_filter_xattrs(list, f_list, ret);
+	kfree(list);
+
 	nfserr = 0;
-	resp->xattr_list = list;
-	resp->xattr_list_len = ret;
+	resp->xattr_list = f_list;
+	resp->xattr_list_len = f_len;
 
 	RETURN_STATUS(nfserr);
 }
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
index f8132f3..23028ee 100644
--- a/fs/nfsd/vfs.h
+++ b/fs/nfsd/vfs.h
@@ -107,6 +107,16 @@ ssize_t nfsd_getxattr(struct dentry *dentry, char *key, void **buf);
 
 #ifdef CONFIG_NFSD_V3_XATTR
 extern struct svc_version nfsd_xattr_version3;
+
+/*
+ * Translation prefix for local storage of remote xattrs.  This is currently
+ * hard-coded, but could be made a configurable per-export option.  We're
+ * using the user namespace, which is widely supported by filesystems, and
+ * allows arbitrary manipulation.
+ */
+#define NFSD_XATTR_PREFIX "nfsd."
+#define NFSD_XATTR_PREFIX_LEN (strlen(NFSD_XATTR_PREFIX))
+
 #else
 #define nfsd_xattr_version3 NULL
 #endif
-- 
1.6.3.3


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* Re: [PATCH 0/6][v4][RFC] NFSv3: implement extended attribute protocol (XATTR)
  2010-03-08 10:42 ` [PATCH 0/6][v4][RFC] NFSv3: implement extended attribute protocol (XATTR) James Morris
                     ` (4 preceding siblings ...)
       [not found]   ` <alpine.LRH.2.00.1003082122340.6314-CK9fWmtY32x9JUWOpEiw7w@public.gmane.org>
@ 2010-03-09  3:59   ` Brad Boyer
  2010-03-09  5:49     ` Casey Schaufler
  2010-03-09  8:13     ` James Morris
  5 siblings, 2 replies; 39+ messages in thread
From: Brad Boyer @ 2010-03-09  3:59 UTC (permalink / raw)
  To: James Morris
  Cc: linux-nfs, linux-security-module, Trond Myklebust,
	J. Bruce Fields, Neil Brown, linux-fsdevel

On Mon, Mar 08, 2010 at 09:42:06PM +1100, James Morris wrote:
> Since the last version, I've incorporated feedback to add a new top-level 
> xattr namespace "nfsd", for storing client-origin xattrs on the server.  
> Support for the new namespace has been implemented on ext3 for testing 
> purposes.
> 
> Access to this namespace locally requires CAP_SYS_ADMIN, and it is not 
> accessible over the wire.  Note that there is still potential for 
> confusion between local and remote users, e.g.
> 
> $ setfattr -n user.foo -v bar file.txt
> 
> on an NFS mounted fs will create an xattr on the server called 
> nfsd.user.foo, and then if the user logs in locally, they will not see the 
> xattr at all.  Similarly, if they create xattrs locally, they will not be 
> exported via XATTR.
> 
> Comments welcome.

I personally think it's a bad idea to not map regular user xattr values
directly to what is local to the server. One common thing I've seen in
many places is to have local disks on various servers exported over
NFS to other servers, but the intent is that the user shouldn't care
which server physically hosts the storage. In this case, you want the
data to appear the same regardless of the use or non-use of NFS. In
this sort of situation, one system will see different data than the
others for the same files with the same access level. One possible
option would be to make it configurable, kind of like root_squash.

	Brad Boyer
	flar@allandria.com


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 0/6][v4][RFC] NFSv3: implement extended attribute protocol (XATTR)
  2010-03-09  3:59   ` [PATCH 0/6][v4][RFC] NFSv3: implement extended attribute protocol (XATTR) Brad Boyer
@ 2010-03-09  5:49     ` Casey Schaufler
       [not found]       ` <4B95E167.40306-iSGtlc1asvQWG2LlvL+J4A@public.gmane.org>
  2010-03-09  8:13     ` James Morris
  1 sibling, 1 reply; 39+ messages in thread
From: Casey Schaufler @ 2010-03-09  5:49 UTC (permalink / raw)
  To: Brad Boyer
  Cc: James Morris, linux-nfs, linux-security-module, Trond Myklebust,
	J. Bruce Fields, Neil Brown, linux-fsdevel, Casey Schaufler

Brad Boyer wrote:
> On Mon, Mar 08, 2010 at 09:42:06PM +1100, James Morris wrote:
>   
>> Since the last version, I've incorporated feedback to add a new top-level 
>> xattr namespace "nfsd", for storing client-origin xattrs on the server.  
>> Support for the new namespace has been implemented on ext3 for testing 
>> purposes.
>>
>> Access to this namespace locally requires CAP_SYS_ADMIN, and it is not 
>> accessible over the wire.  Note that there is still potential for 
>> confusion between local and remote users, e.g.
>>
>> $ setfattr -n user.foo -v bar file.txt
>>
>> on an NFS mounted fs will create an xattr on the server called 
>> nfsd.user.foo, and then if the user logs in locally, they will not see the 
>> xattr at all.  Similarly, if they create xattrs locally, they will not be 
>> exported via XATTR.
>>
>> Comments welcome.
>>     
>
> I personally think it's a bad idea to not map regular user xattr values
> directly to what is local to the server. One common thing I've seen in
> many places is to have local disks on various servers exported over
> NFS to other servers, but the intent is that the user shouldn't care
> which server physically hosts the storage. In this case, you want the
> data to appear the same regardless of the use or non-use of NFS. In
> this sort of situation, one system will see different data than the
> others for the same files with the same access level. One possible
> option would be to make it configurable, kind of like root_squash.
>   

Another is to NFS mount the filesystem back on to the server,
in which case James' scheme works just dandy. It's a trick that
I've used more than once in the Unix world for this exact purpose.
Of course you have to arrange your mount points in advance with
malice aforethought, but that's likely something you're used to
by now.

> 	Brad Boyer
> 	flar@allandria.com
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
>
>   


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 0/6][v4][RFC] NFSv3: implement extended attribute protocol (XATTR)
  2010-03-09  5:49     ` Casey Schaufler
@ 2010-03-09  7:04           ` Brad Boyer
  0 siblings, 0 replies; 39+ messages in thread
From: Brad Boyer @ 2010-03-09  7:04 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: James Morris, linux-nfs-u79uwXL29TY76Z2rM5mHXA,
	linux-security-module-u79uwXL29TY76Z2rM5mHXA, Trond Myklebust,
	J. Bruce Fields, Neil Brown,
	linux-fsdevel-u79uwXL29TY76Z2rM5mHXA

On Mon, Mar 08, 2010 at 09:49:27PM -0800, Casey Schaufler wrote:
> Another is to NFS mount the filesystem back on to the server,
> in which case James' scheme works just dandy. It's a trick that
> I've used more than once in the Unix world for this exact purpose.
> Of course you have to arrange your mount points in advance with
> malice aforethought, but that's likely something you're used to
> by now.

That would definitely work, but it's not ideal. Obviously if it's
being accessed over NFS in one place it probably good enough
everywhere, but it's overhead that could be eliminated.

	Brad Boyer
	flar-POGeQm5F+FGB+jHODAdFcQ@public.gmane.org

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 0/6][v4][RFC] NFSv3: implement extended attribute protocol (XATTR)
@ 2010-03-09  7:04           ` Brad Boyer
  0 siblings, 0 replies; 39+ messages in thread
From: Brad Boyer @ 2010-03-09  7:04 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: James Morris, linux-nfs, linux-security-module, Trond Myklebust,
	J. Bruce Fields, Neil Brown, linux-fsdevel

On Mon, Mar 08, 2010 at 09:49:27PM -0800, Casey Schaufler wrote:
> Another is to NFS mount the filesystem back on to the server,
> in which case James' scheme works just dandy. It's a trick that
> I've used more than once in the Unix world for this exact purpose.
> Of course you have to arrange your mount points in advance with
> malice aforethought, but that's likely something you're used to
> by now.

That would definitely work, but it's not ideal. Obviously if it's
being accessed over NFS in one place it probably good enough
everywhere, but it's overhead that could be eliminated.

	Brad Boyer
	flar@allandria.com


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 0/6][v4][RFC] NFSv3: implement extended attribute protocol (XATTR)
  2010-03-09  3:59   ` [PATCH 0/6][v4][RFC] NFSv3: implement extended attribute protocol (XATTR) Brad Boyer
  2010-03-09  5:49     ` Casey Schaufler
@ 2010-03-09  8:13     ` James Morris
  2010-03-13  7:28       ` Brad Boyer
  1 sibling, 1 reply; 39+ messages in thread
From: James Morris @ 2010-03-09  8:13 UTC (permalink / raw)
  To: Brad Boyer
  Cc: linux-nfs, linux-security-module, Trond Myklebust,
	J. Bruce Fields, Neil Brown, linux-fsdevel

On Mon, 8 Mar 2010, Brad Boyer wrote:

> I personally think it's a bad idea to not map regular user xattr values
> directly to what is local to the server. One common thing I've seen in
> many places is to have local disks on various servers exported over
> NFS to other servers, but the intent is that the user shouldn't care
> which server physically hosts the storage. In this case, you want the
> data to appear the same regardless of the use or non-use of NFS. In
> this sort of situation, one system will see different data than the
> others for the same files with the same access level. One possible
> option would be to make it configurable, kind of like root_squash.

It should be straightforward to make it configurable, although I wonder if 
this might end up leading to more confusion for admins.  They'll always 
have to remember how they exported each filesystem.  If they ever mount a 
filesystem with the wrong option, and users start accessing it, they could 
end up with an unfixable mess.

The core issue is that we don't want system-level xattrs being stored on 
the server.

As you suggest, perhaps we always leave 'user' xattrs untranslated on the 
server, with an expectation that they're always opaque to the server and 
managed entirely by user applications.

I don't think we can meaningfully do this for 'trusted' xattrs, as we 
don't know how to extend CAP_SYS_ADMIN over NFS.  So, this, and all other 
non-user namespaces (e.g. 'system', 'security') are mapped on the server 
to the 'nfsd' namespace, on the basis that they would otherwise require 
interpretation by the server, which we want to avoid.  (Note that there's 
an exception here for POSIX ACLs, which already use a well-defined 
protocol over NFS).

Here's a summary of the mappings:

Client                    Server

user.a                    user.a
trusted.a                 nfsd.trusted.a
system.a                  nfsd.system.a
security.a                nfsd.security.a

Special cases:

  if ACL protocol enabled on server:

system.posix_acl_access   system.posix_acl_access
system.posix_acl_default  system.posix_acl_default
  
  if ACL protocol not enabled on server:

system.posix_acl_access   [error]
system.posix_acl_default  [error]

This also ensures that nothing about the existing NFS ACL support changes.

'user' xattrs simply work as expected, whether accessed locally or 
remotely.  

How does this sound?



- James
-- 
James Morris
<jmorris@namei.org>

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 0/6][v4][RFC] NFSv3: implement extended attribute protocol (XATTR)
  2010-03-09  7:04           ` Brad Boyer
  (?)
@ 2010-03-09 19:35           ` Jamie Lokier
       [not found]             ` <20100309193545.GE11042-yetKDKU6eevNLxjTenLetw@public.gmane.org>
  -1 siblings, 1 reply; 39+ messages in thread
From: Jamie Lokier @ 2010-03-09 19:35 UTC (permalink / raw)
  To: Brad Boyer
  Cc: Casey Schaufler, James Morris, linux-nfs, linux-security-module,
	Trond Myklebust, J. Bruce Fields, Neil Brown, linux-fsdevel

Brad Boyer wrote:
> On Mon, Mar 08, 2010 at 09:49:27PM -0800, Casey Schaufler wrote:
> > Another is to NFS mount the filesystem back on to the server,
> > in which case James' scheme works just dandy. It's a trick that
> > I've used more than once in the Unix world for this exact purpose.
> > Of course you have to arrange your mount points in advance with
> > malice aforethought, but that's likely something you're used to
> > by now.
> 
> That would definitely work, but it's not ideal. Obviously if it's
> being accessed over NFS in one place it probably good enough
> everywhere, but it's overhead that could be eliminated.

As a real example:

Each user has a PC with their own home directory being local, fast
storage, but /home is filled with NFS auto-mounts to everyone else's
home directories, on their individual PCs.  The auto-mount map has an
exception, so the local user's home directory is a symlink to the
local storage, instead of an NFS mount.

A scheme like that works very well for occasional access to other
peoples files, and for logging to each other's machines transparently,
yet having fast performance for their own files when using their local
machine.

In an environment where I've used that, forcing local access to go
over local NFS would have destroyed performance for things like big
compiles, running find, git, grep etc. that people do on their own
directories.

-- Jamie

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 0/6][v4][RFC] NFSv3: implement extended attribute protocol (XATTR)
  2010-03-09 19:35           ` Jamie Lokier
@ 2010-03-10  3:46                 ` Casey Schaufler
  0 siblings, 0 replies; 39+ messages in thread
From: Casey Schaufler @ 2010-03-10  3:46 UTC (permalink / raw)
  To: Jamie Lokier
  Cc: Brad Boyer, James Morris, linux-nfs-u79uwXL29TY76Z2rM5mHXA,
	linux-security-module-u79uwXL29TY76Z2rM5mHXA, Trond Myklebust,
	J. Bruce Fields, Neil Brown,
	linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Casey Schaufler

Jamie Lokier wrote:
> Brad Boyer wrote:
>   
>> On Mon, Mar 08, 2010 at 09:49:27PM -0800, Casey Schaufler wrote:
>>     
>>> Another is to NFS mount the filesystem back on to the server,
>>> in which case James' scheme works just dandy. It's a trick that
>>> I've used more than once in the Unix world for this exact purpose.
>>> Of course you have to arrange your mount points in advance with
>>> malice aforethought, but that's likely something you're used to
>>> by now.
>>>       
>> That would definitely work, but it's not ideal. Obviously if it's
>> being accessed over NFS in one place it probably good enough
>> everywhere, but it's overhead that could be eliminated.
>>     
>
> As a real example:
>
> Each user has a PC with their own home directory being local, fast
> storage, but /home is filled with NFS auto-mounts to everyone else's
> home directories, on their individual PCs.  The auto-mount map has an
> exception, so the local user's home directory is a symlink to the
> local storage, instead of an NFS mount.
>
> A scheme like that works very well for occasional access to other
> peoples files, and for logging to each other's machines transparently,
> yet having fast performance for their own files when using their local
> machine.
>
> In an environment where I've used that, forcing local access to go
> over local NFS would have destroyed performance for things like big
> compiles, running find, git, grep etc. that people do on their own
> directories.
>
>   


Sure. The original objection can be readily addressed. There are
performance implications. Just like you'd have if the home directories
resided on a storage appliance. Some people pick security for the
masses over performance for the few. Some the other way round.
It's not an issue for people who want labeled NFS3 badly enough
to install it.


> -- Jamie
>
>   

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 0/6][v4][RFC] NFSv3: implement extended attribute protocol (XATTR)
@ 2010-03-10  3:46                 ` Casey Schaufler
  0 siblings, 0 replies; 39+ messages in thread
From: Casey Schaufler @ 2010-03-10  3:46 UTC (permalink / raw)
  To: Jamie Lokier
  Cc: Brad Boyer, James Morris, linux-nfs, linux-security-module,
	Trond Myklebust, J. Bruce Fields, Neil Brown, linux-fsdevel,
	Casey Schaufler

Jamie Lokier wrote:
> Brad Boyer wrote:
>   
>> On Mon, Mar 08, 2010 at 09:49:27PM -0800, Casey Schaufler wrote:
>>     
>>> Another is to NFS mount the filesystem back on to the server,
>>> in which case James' scheme works just dandy. It's a trick that
>>> I've used more than once in the Unix world for this exact purpose.
>>> Of course you have to arrange your mount points in advance with
>>> malice aforethought, but that's likely something you're used to
>>> by now.
>>>       
>> That would definitely work, but it's not ideal. Obviously if it's
>> being accessed over NFS in one place it probably good enough
>> everywhere, but it's overhead that could be eliminated.
>>     
>
> As a real example:
>
> Each user has a PC with their own home directory being local, fast
> storage, but /home is filled with NFS auto-mounts to everyone else's
> home directories, on their individual PCs.  The auto-mount map has an
> exception, so the local user's home directory is a symlink to the
> local storage, instead of an NFS mount.
>
> A scheme like that works very well for occasional access to other
> peoples files, and for logging to each other's machines transparently,
> yet having fast performance for their own files when using their local
> machine.
>
> In an environment where I've used that, forcing local access to go
> over local NFS would have destroyed performance for things like big
> compiles, running find, git, grep etc. that people do on their own
> directories.
>
>   


Sure. The original objection can be readily addressed. There are
performance implications. Just like you'd have if the home directories
resided on a storage appliance. Some people pick security for the
masses over performance for the few. Some the other way round.
It's not an issue for people who want labeled NFS3 badly enough
to install it.


> -- Jamie
>
>   


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 0/6][v4][RFC] NFSv3: implement extended attribute protocol (XATTR)
  2010-03-09  8:13     ` James Morris
@ 2010-03-13  7:28       ` Brad Boyer
  0 siblings, 0 replies; 39+ messages in thread
From: Brad Boyer @ 2010-03-13  7:28 UTC (permalink / raw)
  To: James Morris
  Cc: linux-nfs, linux-security-module, Trond Myklebust,
	J. Bruce Fields, Neil Brown, linux-fsdevel

On Tue, Mar 09, 2010 at 07:13:45PM +1100, James Morris wrote:
> The core issue is that we don't want system-level xattrs being stored on 
> the server.

I can understand that, but it does seem like only system xattrs should
be treated that way to me.

> As you suggest, perhaps we always leave 'user' xattrs untranslated on the 
> server, with an expectation that they're always opaque to the server and 
> managed entirely by user applications.

This seems reasonable.

> I don't think we can meaningfully do this for 'trusted' xattrs, as we 
> don't know how to extend CAP_SYS_ADMIN over NFS.  So, this, and all other 
> non-user namespaces (e.g. 'system', 'security') are mapped on the server 
> to the 'nfsd' namespace, on the basis that they would otherwise require 
> interpretation by the server, which we want to avoid.  (Note that there's 
> an exception here for POSIX ACLs, which already use a well-defined 
> protocol over NFS).
> 
> Here's a summary of the mappings:
> 
> Client                    Server
> 
> user.a                    user.a
> trusted.a                 nfsd.trusted.a
> system.a                  nfsd.system.a
> security.a                nfsd.security.a
> 
> Special cases:
> 
>   if ACL protocol enabled on server:
> 
> system.posix_acl_access   system.posix_acl_access
> system.posix_acl_default  system.posix_acl_default
>   
>   if ACL protocol not enabled on server:
> 
> system.posix_acl_access   [error]
> system.posix_acl_default  [error]
> 
> This also ensures that nothing about the existing NFS ACL support changes.
> 
> 'user' xattrs simply work as expected, whether accessed locally or 
> remotely.  
> 
> How does this sound?

This mapping sounds great to me. It would be interesting to hear some
opinions from other people on the lists.

	Brad Boyer
	flar@allandria.com


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 0/6][v4][RFC] NFSv3: implement extended attribute protocol (XATTR)
  2010-03-10  3:46                 ` Casey Schaufler
  (?)
@ 2010-03-15  3:19                 ` Jamie Lokier
  2010-03-15  4:42                   ` Casey Schaufler
  -1 siblings, 1 reply; 39+ messages in thread
From: Jamie Lokier @ 2010-03-15  3:19 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: Brad Boyer, James Morris, linux-nfs, linux-security-module,
	Trond Myklebust, J. Bruce Fields, Neil Brown, linux-fsdevel

Casey Schaufler wrote:
> Jamie Lokier wrote:
> > Brad Boyer wrote:
> >   
> >> On Mon, Mar 08, 2010 at 09:49:27PM -0800, Casey Schaufler wrote:
> >>     
> >>> Another is to NFS mount the filesystem back on to the server,
> >>> in which case James' scheme works just dandy. It's a trick that
> >>> I've used more than once in the Unix world for this exact purpose.
> >>> Of course you have to arrange your mount points in advance with
> >>> malice aforethought, but that's likely something you're used to
> >>> by now.
> >>>       
> >> That would definitely work, but it's not ideal. Obviously if it's
> >> being accessed over NFS in one place it probably good enough
> >> everywhere, but it's overhead that could be eliminated.
> >>     
> >
> > As a real example:
> >
> > Each user has a PC with their own home directory being local, fast
> > storage, but /home is filled with NFS auto-mounts to everyone else's
> > home directories, on their individual PCs.  The auto-mount map has an
> > exception, so the local user's home directory is a symlink to the
> > local storage, instead of an NFS mount.
> >
> > A scheme like that works very well for occasional access to other
> > peoples files, and for logging to each other's machines transparently,
> > yet having fast performance for their own files when using their local
> > machine.
> >
> > In an environment where I've used that, forcing local access to go
> > over local NFS would have destroyed performance for things like big
> > compiles, running find, git, grep etc. that people do on their own
> > directories.
> >
> >   
> 
> Sure. The original objection can be readily addressed. There are
> performance implications. Just like you'd have if the home directories
> resided on a storage appliance. Some people pick security for the
> masses over performance for the few. Some the other way round.
> It's not an issue for people who want labeled NFS3 badly enough
> to install it.

It seems in this case, the performance implications are totally unnecassary.

Why not a mount option for the xattr name translation?

-- Jamie

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 0/6][v4][RFC] NFSv3: implement extended attribute protocol (XATTR)
  2010-03-15  3:19                 ` Jamie Lokier
@ 2010-03-15  4:42                   ` Casey Schaufler
       [not found]                     ` <4B9DBAB0.5060500-iSGtlc1asvQWG2LlvL+J4A@public.gmane.org>
  0 siblings, 1 reply; 39+ messages in thread
From: Casey Schaufler @ 2010-03-15  4:42 UTC (permalink / raw)
  To: Jamie Lokier
  Cc: Brad Boyer, James Morris, linux-nfs, linux-security-module,
	Trond Myklebust, J. Bruce Fields, Neil Brown, linux-fsdevel,
	Casey Schaufler

Jamie Lokier wrote:
> Casey Schaufler wrote:
>   
>> Jamie Lokier wrote:
>>     
>>> Brad Boyer wrote:
>>>   
>>>       
>>>> On Mon, Mar 08, 2010 at 09:49:27PM -0800, Casey Schaufler wrote:
>>>>     
>>>>         
>>>>> Another is to NFS mount the filesystem back on to the server,
>>>>> in which case James' scheme works just dandy. It's a trick that
>>>>> I've used more than once in the Unix world for this exact purpose.
>>>>> Of course you have to arrange your mount points in advance with
>>>>> malice aforethought, but that's likely something you're used to
>>>>> by now.
>>>>>       
>>>>>           
>>>> That would definitely work, but it's not ideal. Obviously if it's
>>>> being accessed over NFS in one place it probably good enough
>>>> everywhere, but it's overhead that could be eliminated.
>>>>     
>>>>         
>>> As a real example:
>>>
>>> Each user has a PC with their own home directory being local, fast
>>> storage, but /home is filled with NFS auto-mounts to everyone else's
>>> home directories, on their individual PCs.  The auto-mount map has an
>>> exception, so the local user's home directory is a symlink to the
>>> local storage, instead of an NFS mount.
>>>
>>> A scheme like that works very well for occasional access to other
>>> peoples files, and for logging to each other's machines transparently,
>>> yet having fast performance for their own files when using their local
>>> machine.
>>>
>>> In an environment where I've used that, forcing local access to go
>>> over local NFS would have destroyed performance for things like big
>>> compiles, running find, git, grep etc. that people do on their own
>>> directories.
>>>
>>>   
>>>       
>> Sure. The original objection can be readily addressed. There are
>> performance implications. Just like you'd have if the home directories
>> resided on a storage appliance. Some people pick security for the
>> masses over performance for the few. Some the other way round.
>> It's not an issue for people who want labeled NFS3 badly enough
>> to install it.
>>     
>
> It seems in this case, the performance implications are totally unnecassary.
>
> Why not a mount option for the xattr name translation?
>
>   

As much as we might like it to be otherwise, an NFS mounted
filesystem behaves differently from an ext3 local filesystem.
To get consistent behavior the same mechanism needs to be used
for all of the machines on which the data is accessed. That
means using NFS everywhere because you can't use the local
filesystem in multiple places. Usually the variations can be
ignored, but there are cases where it matters.


> -- Jamie
> --
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
>
>   


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 0/6][v4][RFC] NFSv3: implement extended attribute protocol (XATTR)
  2010-03-15  4:42                   ` Casey Schaufler
@ 2010-03-15 14:28                         ` Jamie Lokier
  0 siblings, 0 replies; 39+ messages in thread
From: Jamie Lokier @ 2010-03-15 14:28 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: Brad Boyer, James Morris, linux-nfs-u79uwXL29TY76Z2rM5mHXA,
	linux-security-module-u79uwXL29TY76Z2rM5mHXA, Trond Myklebust,
	J. Bruce Fields, Neil Brown,
	linux-fsdevel-u79uwXL29TY76Z2rM5mHXA

Casey Schaufler wrote:
> Jamie Lokier wrote:
> > Casey Schaufler wrote:
> >   
> >> Jamie Lokier wrote:
> >>     
> >>> Brad Boyer wrote:
> >>>   
> >>>       
> >>>> On Mon, Mar 08, 2010 at 09:49:27PM -0800, Casey Schaufler wrote:
> >>>>     
> >>>>         
> >>>>> Another is to NFS mount the filesystem back on to the server,
> >>>>> in which case James' scheme works just dandy. It's a trick that
> >>>>> I've used more than once in the Unix world for this exact purpose.
> >>>>> Of course you have to arrange your mount points in advance with
> >>>>> malice aforethought, but that's likely something you're used to
> >>>>> by now.
> >>>>>       
> >>>>>           
> >>>> That would definitely work, but it's not ideal. Obviously if it's
> >>>> being accessed over NFS in one place it probably good enough
> >>>> everywhere, but it's overhead that could be eliminated.
> >>>>     
> >>>>         
> >>> As a real example:
> >>>
> >>> Each user has a PC with their own home directory being local, fast
> >>> storage, but /home is filled with NFS auto-mounts to everyone else's
> >>> home directories, on their individual PCs.  The auto-mount map has an
> >>> exception, so the local user's home directory is a symlink to the
> >>> local storage, instead of an NFS mount.
> >>>
> >>> A scheme like that works very well for occasional access to other
> >>> peoples files, and for logging to each other's machines transparently,
> >>> yet having fast performance for their own files when using their local
> >>> machine.
> >>>
> >>> In an environment where I've used that, forcing local access to go
> >>> over local NFS would have destroyed performance for things like big
> >>> compiles, running find, git, grep etc. that people do on their own
> >>> directories.
> >>>
> >>>   
> >>>       
> >> Sure. The original objection can be readily addressed. There are
> >> performance implications. Just like you'd have if the home directories
> >> resided on a storage appliance. Some people pick security for the
> >> masses over performance for the few. Some the other way round.
> >> It's not an issue for people who want labeled NFS3 badly enough
> >> to install it.
> >>     
> >
> > It seems in this case, the performance implications are totally unnecassary.
> >
> > Why not a mount option for the xattr name translation?
> >
> >   
> 
> As much as we might like it to be otherwise, an NFS mounted
> filesystem behaves differently from an ext3 local filesystem.
> To get consistent behavior the same mechanism needs to be used
> for all of the machines on which the data is accessed. That
> means using NFS everywhere because you can't use the local
> filesystem in multiple places. Usually the variations can be
> ignored, but there are cases where it matters.

Sure - but is this case one of them?  If so, what's the difference?

Sometimes a 10x performance improvement(*) is preferred over rigidly
consistent behaviour, if the differences don't matter.  Besides, if
something is working over NFS, it almost certainly works locally.
Problems only tend to occur the other way around.

I've never yet had a problem running the combination of local mount
locally and NFS mount remotely on the same filesystem.  This change
seems to be creating a problem where there wasn't one before - unless
I'm missing something.

(*) Measured during big "makes".

-- Jamie
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 0/6][v4][RFC] NFSv3: implement extended attribute protocol (XATTR)
@ 2010-03-15 14:28                         ` Jamie Lokier
  0 siblings, 0 replies; 39+ messages in thread
From: Jamie Lokier @ 2010-03-15 14:28 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: Brad Boyer, James Morris, linux-nfs, linux-security-module,
	Trond Myklebust, J. Bruce Fields, Neil Brown, linux-fsdevel

Casey Schaufler wrote:
> Jamie Lokier wrote:
> > Casey Schaufler wrote:
> >   
> >> Jamie Lokier wrote:
> >>     
> >>> Brad Boyer wrote:
> >>>   
> >>>       
> >>>> On Mon, Mar 08, 2010 at 09:49:27PM -0800, Casey Schaufler wrote:
> >>>>     
> >>>>         
> >>>>> Another is to NFS mount the filesystem back on to the server,
> >>>>> in which case James' scheme works just dandy. It's a trick that
> >>>>> I've used more than once in the Unix world for this exact purpose.
> >>>>> Of course you have to arrange your mount points in advance with
> >>>>> malice aforethought, but that's likely something you're used to
> >>>>> by now.
> >>>>>       
> >>>>>           
> >>>> That would definitely work, but it's not ideal. Obviously if it's
> >>>> being accessed over NFS in one place it probably good enough
> >>>> everywhere, but it's overhead that could be eliminated.
> >>>>     
> >>>>         
> >>> As a real example:
> >>>
> >>> Each user has a PC with their own home directory being local, fast
> >>> storage, but /home is filled with NFS auto-mounts to everyone else's
> >>> home directories, on their individual PCs.  The auto-mount map has an
> >>> exception, so the local user's home directory is a symlink to the
> >>> local storage, instead of an NFS mount.
> >>>
> >>> A scheme like that works very well for occasional access to other
> >>> peoples files, and for logging to each other's machines transparently,
> >>> yet having fast performance for their own files when using their local
> >>> machine.
> >>>
> >>> In an environment where I've used that, forcing local access to go
> >>> over local NFS would have destroyed performance for things like big
> >>> compiles, running find, git, grep etc. that people do on their own
> >>> directories.
> >>>
> >>>   
> >>>       
> >> Sure. The original objection can be readily addressed. There are
> >> performance implications. Just like you'd have if the home directories
> >> resided on a storage appliance. Some people pick security for the
> >> masses over performance for the few. Some the other way round.
> >> It's not an issue for people who want labeled NFS3 badly enough
> >> to install it.
> >>     
> >
> > It seems in this case, the performance implications are totally unnecassary.
> >
> > Why not a mount option for the xattr name translation?
> >
> >   
> 
> As much as we might like it to be otherwise, an NFS mounted
> filesystem behaves differently from an ext3 local filesystem.
> To get consistent behavior the same mechanism needs to be used
> for all of the machines on which the data is accessed. That
> means using NFS everywhere because you can't use the local
> filesystem in multiple places. Usually the variations can be
> ignored, but there are cases where it matters.

Sure - but is this case one of them?  If so, what's the difference?

Sometimes a 10x performance improvement(*) is preferred over rigidly
consistent behaviour, if the differences don't matter.  Besides, if
something is working over NFS, it almost certainly works locally.
Problems only tend to occur the other way around.

I've never yet had a problem running the combination of local mount
locally and NFS mount remotely on the same filesystem.  This change
seems to be creating a problem where there wasn't one before - unless
I'm missing something.

(*) Measured during big "makes".

-- Jamie

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 0/6][v4][RFC] NFSv3: implement extended attribute protocol (XATTR)
  2010-03-15 14:28                         ` Jamie Lokier
@ 2010-03-15 23:28                             ` Casey Schaufler
  -1 siblings, 0 replies; 39+ messages in thread
From: Casey Schaufler @ 2010-03-15 23:28 UTC (permalink / raw)
  To: Jamie Lokier
  Cc: Brad Boyer, James Morris, linux-nfs-u79uwXL29TY76Z2rM5mHXA,
	linux-security-module-u79uwXL29TY76Z2rM5mHXA, Trond Myklebust,
	J. Bruce Fields, Neil Brown,
	linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, Casey Schaufler

Jamie Lokier wrote:
> Casey Schaufler wrote:
>   
>> Jamie Lokier wrote:
>>     
>>> Casey Schaufler wrote:
>>>   
>>>       
>>>> Jamie Lokier wrote:
>>>>     
>>>>         
>>>>> Brad Boyer wrote:
>>>>>   
>>>>>       
>>>>>           
>>>>>> On Mon, Mar 08, 2010 at 09:49:27PM -0800, Casey Schaufler wrote:
>>>>>>     
>>>>>>         
>>>>>>             
>>>>>>> Another is to NFS mount the filesystem back on to the server,
>>>>>>> in which case James' scheme works just dandy. It's a trick that
>>>>>>> I've used more than once in the Unix world for this exact purpose.
>>>>>>> Of course you have to arrange your mount points in advance with
>>>>>>> malice aforethought, but that's likely something you're used to
>>>>>>> by now.
>>>>>>>       
>>>>>>>           
>>>>>>>               
>>>>>> That would definitely work, but it's not ideal. Obviously if it's
>>>>>> being accessed over NFS in one place it probably good enough
>>>>>> everywhere, but it's overhead that could be eliminated.
>>>>>>     
>>>>>>         
>>>>>>             
>>>>> As a real example:
>>>>>
>>>>> Each user has a PC with their own home directory being local, fast
>>>>> storage, but /home is filled with NFS auto-mounts to everyone else's
>>>>> home directories, on their individual PCs.  The auto-mount map has an
>>>>> exception, so the local user's home directory is a symlink to the
>>>>> local storage, instead of an NFS mount.
>>>>>
>>>>> A scheme like that works very well for occasional access to other
>>>>> peoples files, and for logging to each other's machines transparently,
>>>>> yet having fast performance for their own files when using their local
>>>>> machine.
>>>>>
>>>>> In an environment where I've used that, forcing local access to go
>>>>> over local NFS would have destroyed performance for things like big
>>>>> compiles, running find, git, grep etc. that people do on their own
>>>>> directories.
>>>>>
>>>>>   
>>>>>       
>>>>>           
>>>> Sure. The original objection can be readily addressed. There are
>>>> performance implications. Just like you'd have if the home directories
>>>> resided on a storage appliance. Some people pick security for the
>>>> masses over performance for the few. Some the other way round.
>>>> It's not an issue for people who want labeled NFS3 badly enough
>>>> to install it.
>>>>     
>>>>         
>>> It seems in this case, the performance implications are totally unnecassary.
>>>
>>> Why not a mount option for the xattr name translation?
>>>
>>>   
>>>       
>> As much as we might like it to be otherwise, an NFS mounted
>> filesystem behaves differently from an ext3 local filesystem.
>> To get consistent behavior the same mechanism needs to be used
>> for all of the machines on which the data is accessed. That
>> means using NFS everywhere because you can't use the local
>> filesystem in multiple places. Usually the variations can be
>> ignored, but there are cases where it matters.
>>     
>
> Sure - but is this case one of them?

Well, that's the debate. If James' NFS3 labeling uses a different
namespace for the label attribute it could very well result in a
difference in behavior. Look at "ls -Z", which reports the value
of a specific attribute.

>   If so, what's the difference?
>
> Sometimes a 10x performance improvement(*) is preferred over rigidly
> consistent behaviour, if the differences don't matter.  Besides, if
> something is working over NFS, it almost certainly works locally.
> Problems only tend to occur the other way around.
>
> I've never yet had a problem running the combination of local mount
> locally and NFS mount remotely on the same filesystem.  This change
> seems to be creating a problem where there wasn't one before - unless
> I'm missing something.
>   

You're missing something. Privilege semantics are different. The
behavior of unlinked files is different. Locking is different. You
are correct that in most cases it does not matter. We're not talking
about the common case, we're talking about using xattrs to store
information that is used to make security decisions. It is quite
difficult to make security claims when an object can be accessed
under two different sets of semantics.


> (*) Measured during big "makes".
>
> -- Jamie
>
>
>   

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 0/6][v4][RFC] NFSv3: implement extended attribute protocol (XATTR)
@ 2010-03-15 23:28                             ` Casey Schaufler
  0 siblings, 0 replies; 39+ messages in thread
From: Casey Schaufler @ 2010-03-15 23:28 UTC (permalink / raw)
  To: Jamie Lokier
  Cc: Brad Boyer, James Morris, linux-nfs, linux-security-module,
	Trond Myklebust, J. Bruce Fields, Neil Brown, linux-fsdevel,
	Casey Schaufler

Jamie Lokier wrote:
> Casey Schaufler wrote:
>   
>> Jamie Lokier wrote:
>>     
>>> Casey Schaufler wrote:
>>>   
>>>       
>>>> Jamie Lokier wrote:
>>>>     
>>>>         
>>>>> Brad Boyer wrote:
>>>>>   
>>>>>       
>>>>>           
>>>>>> On Mon, Mar 08, 2010 at 09:49:27PM -0800, Casey Schaufler wrote:
>>>>>>     
>>>>>>         
>>>>>>             
>>>>>>> Another is to NFS mount the filesystem back on to the server,
>>>>>>> in which case James' scheme works just dandy. It's a trick that
>>>>>>> I've used more than once in the Unix world for this exact purpose.
>>>>>>> Of course you have to arrange your mount points in advance with
>>>>>>> malice aforethought, but that's likely something you're used to
>>>>>>> by now.
>>>>>>>       
>>>>>>>           
>>>>>>>               
>>>>>> That would definitely work, but it's not ideal. Obviously if it's
>>>>>> being accessed over NFS in one place it probably good enough
>>>>>> everywhere, but it's overhead that could be eliminated.
>>>>>>     
>>>>>>         
>>>>>>             
>>>>> As a real example:
>>>>>
>>>>> Each user has a PC with their own home directory being local, fast
>>>>> storage, but /home is filled with NFS auto-mounts to everyone else's
>>>>> home directories, on their individual PCs.  The auto-mount map has an
>>>>> exception, so the local user's home directory is a symlink to the
>>>>> local storage, instead of an NFS mount.
>>>>>
>>>>> A scheme like that works very well for occasional access to other
>>>>> peoples files, and for logging to each other's machines transparently,
>>>>> yet having fast performance for their own files when using their local
>>>>> machine.
>>>>>
>>>>> In an environment where I've used that, forcing local access to go
>>>>> over local NFS would have destroyed performance for things like big
>>>>> compiles, running find, git, grep etc. that people do on their own
>>>>> directories.
>>>>>
>>>>>   
>>>>>       
>>>>>           
>>>> Sure. The original objection can be readily addressed. There are
>>>> performance implications. Just like you'd have if the home directories
>>>> resided on a storage appliance. Some people pick security for the
>>>> masses over performance for the few. Some the other way round.
>>>> It's not an issue for people who want labeled NFS3 badly enough
>>>> to install it.
>>>>     
>>>>         
>>> It seems in this case, the performance implications are totally unnecassary.
>>>
>>> Why not a mount option for the xattr name translation?
>>>
>>>   
>>>       
>> As much as we might like it to be otherwise, an NFS mounted
>> filesystem behaves differently from an ext3 local filesystem.
>> To get consistent behavior the same mechanism needs to be used
>> for all of the machines on which the data is accessed. That
>> means using NFS everywhere because you can't use the local
>> filesystem in multiple places. Usually the variations can be
>> ignored, but there are cases where it matters.
>>     
>
> Sure - but is this case one of them?

Well, that's the debate. If James' NFS3 labeling uses a different
namespace for the label attribute it could very well result in a
difference in behavior. Look at "ls -Z", which reports the value
of a specific attribute.

>   If so, what's the difference?
>
> Sometimes a 10x performance improvement(*) is preferred over rigidly
> consistent behaviour, if the differences don't matter.  Besides, if
> something is working over NFS, it almost certainly works locally.
> Problems only tend to occur the other way around.
>
> I've never yet had a problem running the combination of local mount
> locally and NFS mount remotely on the same filesystem.  This change
> seems to be creating a problem where there wasn't one before - unless
> I'm missing something.
>   

You're missing something. Privilege semantics are different. The
behavior of unlinked files is different. Locking is different. You
are correct that in most cases it does not matter. We're not talking
about the common case, we're talking about using xattrs to store
information that is used to make security decisions. It is quite
difficult to make security claims when an object can be accessed
under two different sets of semantics.


> (*) Measured during big "makes".
>
> -- Jamie
>
>
>   


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 0/6][v4][RFC] NFSv3: implement extended attribute protocol (XATTR)
  2010-03-15 23:28                             ` Casey Schaufler
  (?)
@ 2010-03-15 23:49                             ` Trond Myklebust
  2010-03-16  2:31                               ` Casey Schaufler
  -1 siblings, 1 reply; 39+ messages in thread
From: Trond Myklebust @ 2010-03-15 23:49 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: Jamie Lokier, Brad Boyer, James Morris, linux-nfs,
	linux-security-module, J. Bruce Fields, Neil Brown,
	linux-fsdevel

On Mon, 2010-03-15 at 16:28 -0700, Casey Schaufler wrote:

> You're missing something. Privilege semantics are different. The
> behavior of unlinked files is different. Locking is different. You
> are correct that in most cases it does not matter. We're not talking
> about the common case, we're talking about using xattrs to store
> information that is used to make security decisions. It is quite
> difficult to make security claims when an object can be accessed
> under two different sets of semantics.

I'm sorry. Exactly _how_ are you going to prevent files from being
accessed under more than one set of semantics under NFS? You have _no_
idea what kind of security mechanisms are implemented on the client.

All you can do is export a given set of security labels and hope...

Trond

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 0/6][v4][RFC] NFSv3: implement extended attribute protocol (XATTR)
  2010-03-15 23:49                             ` Trond Myklebust
@ 2010-03-16  2:31                               ` Casey Schaufler
  0 siblings, 0 replies; 39+ messages in thread
From: Casey Schaufler @ 2010-03-16  2:31 UTC (permalink / raw)
  To: Trond Myklebust
  Cc: Jamie Lokier, Brad Boyer, James Morris, linux-nfs,
	linux-security-module, J. Bruce Fields, Neil Brown,
	linux-fsdevel, Casey Schaufler

Trond Myklebust wrote:
> On Mon, 2010-03-15 at 16:28 -0700, Casey Schaufler wrote:
>
>   
>> You're missing something. Privilege semantics are different. The
>> behavior of unlinked files is different. Locking is different. You
>> are correct that in most cases it does not matter. We're not talking
>> about the common case, we're talking about using xattrs to store
>> information that is used to make security decisions. It is quite
>> difficult to make security claims when an object can be accessed
>> under two different sets of semantics.
>>     
>
> I'm sorry. Exactly _how_ are you going to prevent files from being
> accessed under more than one set of semantics under NFS? You have _no_
> idea what kind of security mechanisms are implemented on the client.
>
> All you can do is export a given set of security labels and hope...
>
>   

Not going to. That's not the point of the discussion, even though
you have a very valid point. The question was about how you might
deal with the differences between access on the NFS server and the
NFS client. I made a proposal that has performance implications,
and I acknowledge those implications. The proposal that I made
also assumes that the policy being enforced on the clients (one
of which is the server, NFS mounting the file system locally) is
sufficiently uniform to meet the needs of the site. I realize that
the probability that your average deployment could achieve this
state is painfully small. Security at the level where this is
useful remains quite rare but is taken very seriously in the cases
where it is useful. Without James' implementation the capability
to deploy something correctly does not exist. With the implementation
it only requires heroic and draconian effort. It's not convenient,
but it is possible.

And before someone starts arguing that no one would ever use
this, I will point out that this mechanism has been deployed
on Unix systems for many years. I realize that by itself the
fact that other systems do it is not a compelling argument.
I will point out the those who deploy such systems do so with
a level of discipline that would shock most software developers.
Generally there lives at stake. Sometimes it's just large
amounts of money. In any case these people can deal with a
performance issue and can ensure that all the systems they are
dealing with treat data the same way.

> Trond
>
>
>   


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 0/6][v4][RFC] NFSv3: implement extended attribute protocol (XATTR)
  2010-03-09  5:49     ` Casey Schaufler
@ 2010-03-17 20:13           ` Eric Paris
  0 siblings, 0 replies; 39+ messages in thread
From: Eric Paris @ 2010-03-17 20:13 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: Brad Boyer, James Morris, linux-nfs-u79uwXL29TY76Z2rM5mHXA,
	linux-security-module-u79uwXL29TY76Z2rM5mHXA, Trond Myklebust,
	J. Bruce Fields, Neil Brown,
	linux-fsdevel-u79uwXL29TY76Z2rM5mHXA

On Tue, Mar 9, 2010 at 1:49 AM, Casey Schaufler <casey-iSGtlc1asvQWG2LlvL+J4A@public.gmane.org> wrote:

> Another is to NFS mount the filesystem back on to the server,
> in which case James' scheme works just dandy. It's a trick that
> I've used more than once in the Unix world for this exact purpose.
> Of course you have to arrange your mount points in advance with
> malice aforethought, but that's likely something you're used to
> by now.

Is this safe with NFS on Linux?  I know in the past (RHEL5) mounting
NFS over loopback can cause deadlocks under even slight memory
pressure.  I complained about it and was told 'don't do that, just
bind mount.'

-Eric
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 0/6][v4][RFC] NFSv3: implement extended attribute protocol (XATTR)
@ 2010-03-17 20:13           ` Eric Paris
  0 siblings, 0 replies; 39+ messages in thread
From: Eric Paris @ 2010-03-17 20:13 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: Brad Boyer, James Morris, linux-nfs, linux-security-module,
	Trond Myklebust, J. Bruce Fields, Neil Brown, linux-fsdevel

On Tue, Mar 9, 2010 at 1:49 AM, Casey Schaufler <casey@schaufler-ca.com> wrote:

> Another is to NFS mount the filesystem back on to the server,
> in which case James' scheme works just dandy. It's a trick that
> I've used more than once in the Unix world for this exact purpose.
> Of course you have to arrange your mount points in advance with
> malice aforethought, but that's likely something you're used to
> by now.

Is this safe with NFS on Linux?  I know in the past (RHEL5) mounting
NFS over loopback can cause deadlocks under even slight memory
pressure.  I complained about it and was told 'don't do that, just
bind mount.'

-Eric

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 0/6][v4][RFC] NFSv3: implement extended attribute protocol (XATTR)
  2010-03-17 20:13           ` Eric Paris
  (?)
@ 2010-03-17 21:23           ` Casey Schaufler
  -1 siblings, 0 replies; 39+ messages in thread
From: Casey Schaufler @ 2010-03-17 21:23 UTC (permalink / raw)
  To: Eric Paris
  Cc: Brad Boyer, James Morris, linux-nfs, linux-security-module,
	Trond Myklebust, J. Bruce Fields, Neil Brown, linux-fsdevel,
	Casey Schaufler

Eric Paris wrote:
> On Tue, Mar 9, 2010 at 1:49 AM, Casey Schaufler <casey@schaufler-ca.com> wrote:
>
>   
>> Another is to NFS mount the filesystem back on to the server,
>> in which case James' scheme works just dandy. It's a trick that
>> I've used more than once in the Unix world for this exact purpose.
>> Of course you have to arrange your mount points in advance with
>> malice aforethought, but that's likely something you're used to
>> by now.
>>     
>
> Is this safe with NFS on Linux?  I know in the past (RHEL5) mounting
> NFS over loopback can cause deadlocks under even slight memory
> pressure.  I complained about it and was told 'don't do that, just
> bind mount.'
>
>   

Sigh. Dedicate your NFS server as an NFS server and never let
anyone long onto it then. The point is well past made, I think.


> -Eric
> --
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
>
>   


^ permalink raw reply	[flat|nested] 39+ messages in thread

end of thread, other threads:[~2010-03-17 21:23 UTC | newest]

Thread overview: 39+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-02-26  4:33 [PATCH 0/5][v3][RFC] NFSv3: implement extended attribute protocol (XATTR) James Morris
2010-02-26  4:34 ` [PATCH 1/5] NFSv3: convert client to generic xattr API James Morris
2010-02-26  4:35 ` [PATCH 2/5] NFSv3: add xattr API config option for client James Morris
     [not found] ` <alpine.LRH.2.00.1002261457420.25193-CK9fWmtY32x9JUWOpEiw7w@public.gmane.org>
2010-02-26  4:36   ` Subject: [PATCH 3/5] NFSv3: add client implementation of XATTR protocol James Morris
2010-02-26  4:36 ` [PATCH 4/5] NFSv3: add server " James Morris
2010-02-26  4:37 ` [PATCH 5/5] NFSv3: Add server namespace support for XATTR protocol implementation James Morris
2010-02-26 13:46   ` Stephen Smalley
2010-03-01  0:49     ` Casey Schaufler
2010-03-01  1:17       ` Trond Myklebust
2010-03-01  8:09         ` James Morris
2010-03-08 10:42 ` [PATCH 0/6][v4][RFC] NFSv3: implement extended attribute protocol (XATTR) James Morris
2010-03-08 10:43   ` [PATCH 1/6] NFSv3: convert client to generic xattr API James Morris
2010-03-08 10:44   ` [PATCH 3/6] NFSv3: add client implementation of XATTR protocol James Morris
2010-03-08 10:45   ` [PATCH 4/6] NFSv3: add server " James Morris
2010-03-08 10:46   ` [PATCH 5/6] xattr: add new top level nfsd namespace and implement ext3 support James Morris
     [not found]   ` <alpine.LRH.2.00.1003082122340.6314-CK9fWmtY32x9JUWOpEiw7w@public.gmane.org>
2010-03-08 10:43     ` [PATCH 2/6] NFSv3: add xattr API config option for client James Morris
2010-03-08 10:43       ` James Morris
2010-03-08 10:47     ` [PATCH 6/6] NFSv3: Add server namespace support for XATTR protocol implementation James Morris
2010-03-08 10:47       ` James Morris
2010-03-09  3:59   ` [PATCH 0/6][v4][RFC] NFSv3: implement extended attribute protocol (XATTR) Brad Boyer
2010-03-09  5:49     ` Casey Schaufler
     [not found]       ` <4B95E167.40306-iSGtlc1asvQWG2LlvL+J4A@public.gmane.org>
2010-03-09  7:04         ` Brad Boyer
2010-03-09  7:04           ` Brad Boyer
2010-03-09 19:35           ` Jamie Lokier
     [not found]             ` <20100309193545.GE11042-yetKDKU6eevNLxjTenLetw@public.gmane.org>
2010-03-10  3:46               ` Casey Schaufler
2010-03-10  3:46                 ` Casey Schaufler
2010-03-15  3:19                 ` Jamie Lokier
2010-03-15  4:42                   ` Casey Schaufler
     [not found]                     ` <4B9DBAB0.5060500-iSGtlc1asvQWG2LlvL+J4A@public.gmane.org>
2010-03-15 14:28                       ` Jamie Lokier
2010-03-15 14:28                         ` Jamie Lokier
     [not found]                         ` <20100315142803.GC15133-yetKDKU6eevNLxjTenLetw@public.gmane.org>
2010-03-15 23:28                           ` Casey Schaufler
2010-03-15 23:28                             ` Casey Schaufler
2010-03-15 23:49                             ` Trond Myklebust
2010-03-16  2:31                               ` Casey Schaufler
2010-03-17 20:13         ` Eric Paris
2010-03-17 20:13           ` Eric Paris
2010-03-17 21:23           ` Casey Schaufler
2010-03-09  8:13     ` James Morris
2010-03-13  7:28       ` Brad Boyer

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.