This patchset is the initial posting of an implementation of extended
attribute support for the Linux NFSv3 code, and intended as an RFC.
This code is based initially on the GPL'd NFSv3 xattr code from IRIX
(thanks, Casey!), as well as the existing Linux NFSv3 ACL code. It is
implemented as a side-protocol and should not affect any existing protocol
operation. These patches are against the devel branch of the linux-nfs
tree.
Currently, the code is implemented only to support Linux namespace.name
xattrs in the "user" namespace. It could be extended to support other
similar name/value pair xattr implementations (and not far from IRIX wire
compat), although that's not an aim of this version. There may also be
some scope for limited support of system xattrs (e.g. 'dumb' security
label transport), although I've not looked beyond user.* so far.
Three operations are implemented by the new XATTR protocol and map to
syscalls:
- GETXATTR getxattr(2)
- LISTXTTR listxattr(2)
- SETXATTR setxattr(2) and removexattr(2)
This code passes basic testing of the above syscalls, although there are
some areas which still need work:
- Dynamic allocation of RPC buffers/pages (currently, the max size of
e.g. the getxattr(2) value buffer is allocated at the RPC layer for
each call -- suggestions on the best approach for this welcome)
- Determine appropriate NFS error codes for each operation
- Formal documentation of the XATTR protocol
- Interoperability with other OSs (we probably should at least
discuss with BSD folk)
- Handle size probing for getxattr(2) and listxattr(2) in the client
(currently faked). I think we should handle this at the client and not
support it over the wire, as probes are almost always followed
immediately by full calls, and the protocol can be kept simpler by
expecting the client to perform a full call over the wire in response
to a userland probe and caching the result.
- Caching of xattrs at the client
Please review and comment!
Note that I'll be giving a talk on this at LinuxCon on Thursday:
http://linuxcon.linuxfoundation.org/meetings/1589 So, in addition to
discussion here, please come along to the talk if you're at the conf, and
we may also be able to discuss it at Plumbers in one of the BoFs.
Full diffstat:
fs/nfs/Kconfig | 36 ++++
fs/nfs/Makefile | 2
fs/nfs/client.c | 51 ++++++
fs/nfs/dir.c | 8 -
fs/nfs/file.c | 8 -
fs/nfs/internal.h | 19 ++
fs/nfs/nfs3acl.c | 155 +++++++++++--------
fs/nfs/nfs3xattr.c | 264 +++++++++++++++++++++++++++++++++
fs/nfs/nfs3xattr_user.c | 52 ++++++
fs/nfs/nfs3xdr.c | 187 +++++++++++++++++++++++
fs/nfs/super.c | 3
fs/nfsd/Kconfig | 8 +
fs/nfsd/Makefile | 1
fs/nfsd/nfs3xattr.c | 352 +++++++++++++++++++++++++++++++++++++++++++++
fs/nfsd/nfsctl.c | 3
fs/nfsd/nfssvc.c | 60 +++++++
fs/nfsd/vfs.c | 5
include/linux/nfs_fs.h | 16 --
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 +++++
include/linux/nfsd/nfsd.h | 13 +
include/linux/nfsd/xdr3.h | 46 +++++
include/linux/sunrpc/svc.h | 2
25 files changed, 1265 insertions(+), 98 deletions(-)
- James
--
James Morris
<[email protected]>
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 <[email protected]>
---
fs/nfs/dir.c | 8 +-
fs/nfs/file.c | 8 +-
fs/nfs/internal.h | 4 +
fs/nfs/nfs3acl.c | 161 ++++++++++++++++++++++++++++--------------------
fs/nfs/super.c | 3 +
include/linux/nfs_fs.h | 16 -----
6 files changed, 110 insertions(+), 90 deletions(-)
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 32062c3..104fae5 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 5021b75..22c4ce1 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 e21b1bb..964170d 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)
@@ -287,6 +288,9 @@ static inline void nfs4_sequence_free_slot(const struct nfs_client *clp,
#endif /* CONFIG_NFS_V4_1 */
}
+/* nfs3acl.c */
+extern struct xattr_handler *nfs3_xattr_handlers[];
+
/*
* Determine the device name as a string
*/
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c
index bac6051..4e15d1a 100644
--- a/fs/nfs/nfs3acl.c
+++ b/fs/nfs/nfs3acl.c
@@ -9,64 +9,57 @@
#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 inode *inode,
+ char *list, size_t list_len,
+ const char *name, size_t name_len,
+ int acl_type, const char *acl_name)
{
- struct inode *inode = dentry->d_inode;
struct posix_acl *acl;
- int pos=0, len=0;
+ 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(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);
- }
- }
+ if (list && size <= list_len)
+ memcpy(list, acl_name, size);
-# undef output
+ posix_acl_release(acl);
+ return size;
+}
- if (!buffer || len <= size)
- return len;
- return -ERANGE;
+static size_t nfs3_acl_access_xattr_list(struct inode *inode, char *list,
+ size_t list_len, const char *name,
+ size_t name_len)
+{
+ return nfs3_acl_xattr_list(inode, list, list_len,
+ name, name_len, ACL_TYPE_ACCESS,
+ POSIX_ACL_XATTR_ACCESS);
}
-ssize_t nfs3_getxattr(struct dentry *dentry, const char *name,
- void *buffer, size_t size)
+static size_t nfs3_acl_default_xattr_list(struct inode *inode, char *list,
+ size_t list_len, const char *name,
+ size_t name_len)
{
- struct inode *inode = dentry->d_inode;
- struct posix_acl *acl;
- int type, error = 0;
+ return nfs3_acl_xattr_list(inode, list, list_len,
+ name, name_len, ACL_TYPE_DEFAULT,
+ POSIX_ACL_XATTR_DEFAULT);
+}
- 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;
+static ssize_t nfs3_acl_xattr_get(struct inode *inode, void *buffer,
+ size_t size, int acl_type)
+{
+ struct posix_acl *acl;
+ int error = 0;
- acl = nfs3_proc_getacl(inode, type);
+ acl = nfs3_proc_getacl(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,44 +70,80 @@ 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_access_xattr_get(struct inode *inode, const char *name,
+ void *buffer, size_t size)
+{
+ if (strcmp(name, "") != 0)
+ return -EINVAL;
+
+ return nfs3_acl_xattr_get(inode, buffer, size, ACL_TYPE_ACCESS);
+}
+
+static int nfs3_acl_default_xattr_get(struct inode *inode, const char *name,
+ void *buffer, size_t size)
+{
+ if (strcmp(name, "") != 0)
+ return -EINVAL;
+
+ return nfs3_acl_xattr_get(inode, buffer, size, ACL_TYPE_DEFAULT);
+}
+
+static int nfs3_acl_xattr_set(struct inode *inode, 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(inode, acl_type, acl);
posix_acl_release(acl);
return error;
}
-int nfs3_removexattr(struct dentry *dentry, const char *name)
+static int nfs3_acl_access_xattr_set(struct inode *inode, const char *name,
+ const void *value, size_t size, int flags)
{
- 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;
+ if (strcmp(name, "") != 0)
+ return -EINVAL;
+ return nfs3_acl_xattr_set(inode, value, size, flags, ACL_TYPE_ACCESS);
+}
- return nfs3_proc_setacl(inode, type, NULL);
+static int nfs3_acl_default_xattr_set(struct inode *inode, const char *name,
+ const void *value, size_t size, int flags)
+{
+ if (strcmp(name, "") != 0)
+ return -EINVAL;
+ return nfs3_acl_xattr_set(inode, value, size, flags, ACL_TYPE_DEFAULT);
}
+static struct xattr_handler nfs3_xattr_acl_access_handler = {
+ .prefix = POSIX_ACL_XATTR_ACCESS,
+ .list = nfs3_acl_access_xattr_list,
+ .get = nfs3_acl_access_xattr_get,
+ .set = nfs3_acl_access_xattr_set,
+};
+
+static struct xattr_handler nfs3_xattr_acl_default_handler = {
+ .prefix = POSIX_ACL_XATTR_DEFAULT,
+ .list = nfs3_acl_default_xattr_list,
+ .get = nfs3_acl_default_xattr_get,
+ .set = nfs3_acl_default_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/super.c b/fs/nfs/super.c
index 867f705..c94fa3f 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -1940,6 +1940,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 f6b9024..04c4f80 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -390,22 +390,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.2.5
--
James Morris
<[email protected]>
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 <[email protected]>
---
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 2a77bc2..ff75902 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 964170d..370f61c 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -288,9 +288,13 @@ static inline void nfs4_sequence_free_slot(const struct nfs_client *clp,
#endif /* CONFIG_NFS_V4_1 */
}
-/* 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 device name as a string
*/
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c
index 4e15d1a..4d59f44 100644
--- a/fs/nfs/nfs3acl.c
+++ b/fs/nfs/nfs3acl.c
@@ -124,26 +124,20 @@ static int nfs3_acl_default_xattr_set(struct inode *inode, const char *name,
return nfs3_acl_xattr_set(inode, value, size, flags, ACL_TYPE_DEFAULT);
}
-static struct xattr_handler nfs3_xattr_acl_access_handler = {
+struct xattr_handler nfs3_xattr_acl_access_handler = {
.prefix = POSIX_ACL_XATTR_ACCESS,
.list = nfs3_acl_access_xattr_list,
.get = nfs3_acl_access_xattr_get,
.set = nfs3_acl_access_xattr_set,
};
-static struct xattr_handler nfs3_xattr_acl_default_handler = {
+struct xattr_handler nfs3_xattr_acl_default_handler = {
.prefix = POSIX_ACL_XATTR_DEFAULT,
.list = nfs3_acl_default_xattr_list,
.get = nfs3_acl_default_xattr_get,
.set = nfs3_acl_default_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 <[email protected]>
+ *
+ * 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.2.5
--
James Morris
<[email protected]>
Add server support for the Linux NFSv3 extended attribute
side protocol (XATTR).
Signed-off-by: James Morris <[email protected]>
---
fs/nfsd/Kconfig | 8 +
fs/nfsd/Makefile | 1 +
fs/nfsd/nfs3xattr.c | 352 ++++++++++++++++++++++++++++++++++++++++++++
fs/nfsd/nfsctl.c | 3 +
fs/nfsd/nfssvc.c | 60 +++++++-
fs/nfsd/vfs.c | 5 +-
include/linux/nfsd/nfsd.h | 13 ++
include/linux/nfsd/xdr3.h | 46 ++++++
include/linux/sunrpc/svc.h | 2 +-
9 files changed, 484 insertions(+), 6 deletions(-)
create mode 100644 fs/nfsd/nfs3xattr.c
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..3b0ae49
--- /dev/null
+++ b/fs/nfsd/nfs3xattr.c
@@ -0,0 +1,352 @@
+/*
+ * Process version 3 NFSXATTR requests.
+ *
+ * Based on the NFSACL code by:
+ * Copyright (C) 2002-2003 Andreas Gruenbacher <[email protected]>
+ *
+ * Copyright (C) 2009 Red Hat, Inc., James Morris <[email protected]>
+ *
+ * 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/nfsd/nfsd.h>
+#include <linux/nfsd/cache.h>
+#include <linux/nfsd/xdr3.h>
+#include <linux/xattr.h>
+#include <linux/nfs_xattr.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 7e906c5..57b51a2 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -1385,6 +1385,8 @@ static int create_proc_exports_entry(void)
}
#endif
+extern void __init nfsd_prog_init(void);
+
static int __init init_nfsd(void)
{
int retval;
@@ -1393,6 +1395,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 492c79b..bd028fd 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -34,6 +34,7 @@
#include <linux/nfsd/syscall.h>
#include <linux/lockd/bind.h>
#include <linux/nfsacl.h>
+#include <linux/nfs_xattr.h>
#define NFSDDBG_FACILITY NFSDDBG_SVC
@@ -92,6 +93,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)
@@ -107,9 +129,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 */
@@ -120,6 +139,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)
@@ -133,6 +174,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;
@@ -140,6 +185,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;
@@ -218,6 +267,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 23341c1..88c8c48 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -413,8 +413,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/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
index 2b49d67..447692a 100644
--- a/include/linux/nfsd/nfsd.h
+++ b/include/linux/nfsd/nfsd.h
@@ -133,6 +133,13 @@ __be32 nfsd_permission(struct svc_rqst *, struct svc_export *,
struct dentry *, int);
int nfsd_sync_dir(struct dentry *dp);
+#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
+
#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
#ifdef CONFIG_NFSD_V2_ACL
extern struct svc_version nfsd_acl_version2;
@@ -148,6 +155,12 @@ struct posix_acl *nfsd_get_posix_acl(struct svc_fh *, int);
int nfsd_set_posix_acl(struct svc_fh *, int, struct posix_acl *);
#endif
+#ifdef CONFIG_NFSD_V3_XATTR
+extern struct svc_version nfsd_xattr_version3;
+#else
+#define nfsd_xattr_version3 NULL
+#endif
+
enum vers_op {NFSD_SET, NFSD_CLEAR, NFSD_TEST, NFSD_AVAIL };
int nfsd_vers(int vers, enum vers_op change);
int nfsd_minorversion(u32 minorversion, enum vers_op change);
diff --git a/include/linux/nfsd/xdr3.h b/include/linux/nfsd/xdr3.h
index 421eddd..a79b84e 100644
--- a/include/linux/nfsd/xdr3.h
+++ b/include/linux/nfsd/xdr3.h
@@ -121,6 +121,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;
@@ -229,6 +250,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;
@@ -249,6 +289,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;
@@ -262,6 +305,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 ea80096..4987fc6 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -380,7 +380,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.2.5
--
James Morris
<[email protected]>
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 <[email protected]>
---
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 ff75902..0b328b1 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 d36925f..2d1b066 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;
@@ -700,6 +715,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,
@@ -845,8 +890,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 370f61c..376bff1 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -291,6 +291,17 @@ static inline void nfs4_sequence_free_slot(const struct nfs_client *clp,
/* 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 <[email protected]>
*
* 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 <[email protected]>
+ *
+ * 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 35869a4..e2d5400 100644
--- a/fs/nfs/nfs3xdr.c
+++ b/fs/nfs/nfs3xdr.c
@@ -89,6 +89,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[] = {
@@ -728,6 +748,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
*/
@@ -1137,6 +1223,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, \
@@ -1208,3 +1357,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 320569e..9d34769 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 <[email protected]>
+ *
+ */
+#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 62f63fb..35a4ddf 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>
/*
* To change the maximum rsize and wsize supported by the NFS client, adjust
@@ -512,6 +513,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;
@@ -644,6 +666,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;
@@ -1062,4 +1104,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.2.5
--
James Morris
<[email protected]>
James Morris wrote:
> This patchset is the initial posting of an implementation of extended
> attribute support for the Linux NFSv3 code, and intended as an RFC.
>
> This code is based initially on the GPL'd NFSv3 xattr code from IRIX
> (thanks, Casey!),
You are welcome.
> as well as the existing Linux NFSv3 ACL code. It is
> implemented as a side-protocol and should not affect any existing protocol
> operation. These patches are against the devel branch of the linux-nfs
> tree.
>
> Currently, the code is implemented only to support Linux namespace.name
> xattrs in the "user" namespace.
Why the limitation? It's been a while since I looked at that code,
but it seems that it would require extra effort to impose that
restriction. It has also proven that while Irix xattrs (which are
the basis for Linux xattrs) were intended for end user purposes
initially, they were only ever actually used for system attributes,
and almost exclusively security attributes at that.
> It could be extended to support other
> similar name/value pair xattr implementations (and not far from IRIX wire
> compat), although that's not an aim of this version. There may also be
> some scope for limited support of system xattrs (e.g. 'dumb' security
> label transport), although I've not looked beyond user.* so far.
>
I suggest that support for "dumb" security attributes will dramatically
increase the value and frequency of use of this facility. If you can
set/get SELinux security contexts and Smack labels you win. That will
be true (based on the Irix experience) even if the clients are SELinux
and the server not. I am familiar with the debates involving client-side
checks, server-side checks, policy mingling, and I do not need to be
reminded of them (by anyone (smiley here)). In real world deployments
there are meaningful situations for each permutation.
> Three operations are implemented by the new XATTR protocol and map to
> syscalls:
>
> - GETXATTR getxattr(2)
> - LISTXTTR listxattr(2)
> - SETXATTR setxattr(2) and removexattr(2)
>
> This code passes basic testing of the above syscalls, although there are
> some areas which still need work:
>
> - Dynamic allocation of RPC buffers/pages (currently, the max size of
> e.g. the getxattr(2) value buffer is allocated at the RPC layer for
> each call -- suggestions on the best approach for this welcome)
>
> - Determine appropriate NFS error codes for each operation
>
> - Formal documentation of the XATTR protocol
>
> - Interoperability with other OSs (we probably should at least
> discuss with BSD folk)
>
> - Handle size probing for getxattr(2) and listxattr(2) in the client
> (currently faked). I think we should handle this at the client and not
> support it over the wire, as probes are almost always followed
> immediately by full calls, and the protocol can be kept simpler by
> expecting the client to perform a full call over the wire in response
> to a userland probe and caching the result.
>
> - Caching of xattrs at the client
>
> Please review and comment!
>
I endorse this approach, and have advocated it in the past. I am
delighted that someone has picked up the ball. This scheme works
very well in the real world.
> Note that I'll be giving a talk on this at LinuxCon on Thursday:
> http://linuxcon.linuxfoundation.org/meetings/1589 So, in addition to
> discussion here, please come along to the talk if you're at the conf, and
> we may also be able to discuss it at Plumbers in one of the BoFs.
>
> Full diffstat:
>
> fs/nfs/Kconfig | 36 ++++
> fs/nfs/Makefile | 2
> fs/nfs/client.c | 51 ++++++
> fs/nfs/dir.c | 8 -
> fs/nfs/file.c | 8 -
> fs/nfs/internal.h | 19 ++
> fs/nfs/nfs3acl.c | 155 +++++++++++--------
> fs/nfs/nfs3xattr.c | 264 +++++++++++++++++++++++++++++++++
> fs/nfs/nfs3xattr_user.c | 52 ++++++
> fs/nfs/nfs3xdr.c | 187 +++++++++++++++++++++++
> fs/nfs/super.c | 3
> fs/nfsd/Kconfig | 8 +
> fs/nfsd/Makefile | 1
> fs/nfsd/nfs3xattr.c | 352 +++++++++++++++++++++++++++++++++++++++++++++
> fs/nfsd/nfsctl.c | 3
> fs/nfsd/nfssvc.c | 60 +++++++
> fs/nfsd/vfs.c | 5
> include/linux/nfs_fs.h | 16 --
> 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 +++++
> include/linux/nfsd/nfsd.h | 13 +
> include/linux/nfsd/xdr3.h | 46 +++++
> include/linux/sunrpc/svc.h | 2
> 25 files changed, 1265 insertions(+), 98 deletions(-)
>
>
> - James
>
On Sat, 19 Sep 2009, Casey Schaufler wrote:
> > Currently, the code is implemented only to support Linux namespace.name
> > xattrs in the "user" namespace.
>
> Why the limitation? It's been a while since I looked at that code,
> but it seems that it would require extra effort to impose that
> restriction. It has also proven that while Irix xattrs (which are
> the basis for Linux xattrs) were intended for end user purposes
> initially, they were only ever actually used for system attributes,
> and almost exclusively security attributes at that.
As a first step, it keeps the semantics simple, and provides a direct
mapping between the userland API and the NFS protocol. System level
xattrs may have semantics which extend beyond the simple NFS xattr
protocol (e.g. full security labeling as we've previously discussed &
documented needs to convey more than just object labels).
Some xattr uses are internal local interfaces, such as with Linux ACLs,
where xattrs are used internally for storing the ACL data, but the exposed
API is quite different (as is the NFS protocol).
We can go beyond user.*, but I think each system-level xattr exposed via
NFS will need to be considered on a case-by-case basis.
> > It could be extended to support other
> > similar name/value pair xattr implementations (and not far from IRIX wire
> > compat), although that's not an aim of this version. There may also be
> > some scope for limited support of system xattrs (e.g. 'dumb' security
> > label transport), although I've not looked beyond user.* so far.
> >
>
> I suggest that support for "dumb" security attributes will dramatically
> increase the value and frequency of use of this facility.
Indeed, there is significant demand for this. e.g. NFS root, remote
access
to VM images. It's not a complete solution, of course.
- James
--
James Morris
<[email protected]>
On Sun, Sep 20, 2009 at 03:13:28PM +1000, James Morris wrote:
> As a first step, it keeps the semantics simple, and provides a direct
> mapping between the userland API and the NFS protocol. System level
> xattrs may have semantics which extend beyond the simple NFS xattr
> protocol (e.g. full security labeling as we've previously discussed &
> documented needs to convey more than just object labels).
>
> Some xattr uses are internal local interfaces, such as with Linux ACLs,
> where xattrs are used internally for storing the ACL data, but the exposed
> API is quite different (as is the NFS protocol).
>
> We can go beyond user.*, but I think each system-level xattr exposed via
> NFS will need to be considered on a case-by-case basis.
Note that the mapping should be really simple. Both the NFS protocol
and XFS implement the same IRIX-xattr format that has a numerical
namespace instead of the string prefix Linux has. If you just use the
same mapping as XFS it should not have interoperability problems.
On Tue, 22 Sep 2009, Christoph Hellwig wrote:
> Note that the mapping should be really simple. Both the NFS protocol
> and XFS implement the same IRIX-xattr format that has a numerical
> namespace instead of the string prefix Linux has. If you just use the
> same mapping as XFS it should not have interoperability problems.
One issue may be that the IRIX protcol for listxattr includes a
"attrlist_cursor_kern_t cursor" -- presumably to allow the client to index
into large lists of xattrs. I'm going to guess that this doesn't happen
much in practice, although to have interop with IRIX, we'd need to handle
this in some useful way.
Otherwise, yes, mapping to the IRIX protocol should be straightforward.
We can use the side-protocol number+version to detect that we're talking
to an IRIX box.
- James
--
James Morris
<[email protected]>
On Tue, Sep 22, 2009 at 11:03:25PM +1000, James Morris wrote:
> On Tue, 22 Sep 2009, Christoph Hellwig wrote:
>
> > Note that the mapping should be really simple. Both the NFS protocol
> > and XFS implement the same IRIX-xattr format that has a numerical
> > namespace instead of the string prefix Linux has. If you just use the
> > same mapping as XFS it should not have interoperability problems.
>
> One issue may be that the IRIX protcol for listxattr includes a
> "attrlist_cursor_kern_t cursor" -- presumably to allow the client to index
> into large lists of xattrs. I'm going to guess that this doesn't happen
> much in practice, although to have interop with IRIX, we'd need to handle
> this in some useful way.
Yeah, unfortunately XFS experts those semantics via the horrible list
attrs by handle ioctls and carries a lot of cruft around to allow using
the cursor and validating the btree tate stored in it. It's a real
mess.
Personally I'd just kill it and do a similar indexing scheme that
libattr uses to emulate the IRIX API (libattr/libattr.c:attr_list() in
the libattr repository)
On Tue, 2009-10-13 at 18:02 +1100, James Morris wrote:
> This xattr approach would only cover the "dumb server" scenario, where the
> server simply stores and retrieves security labels on behalf of the
> client. It's intended primarily to enable things like nfsroot, backups,
> serving virtualized file systems etc., and not for fully trusted sharing
> like Labeled NFS.
>
> It is essentially just security label transport.
>
> Support for this feature would be configured at the server, possibly an
> option in /etc/exports which enables specific security namespaces, e.g:
>
> /opt/share 10.0.0.0/8(rw,insecure,xattr="user.*,security.SMACK64")
>
> This says that the XATTR side protocol is enabled and clients can read and
> write user and security.smack xattrs (local DAC would be applied to both).
>
> The server kernel would likely need to know that these are foreign labels,
> and not necessarily 'trust' them for its own use, so a root_squash -like
> option may be used to remap them to an 'untrusted' local label for local
> enforcement purposes -- if it was running SELinux or Smack at all, which
> it may not be.
Fair enough. That might indeed work.
One simple alternative might be to just store the exported xattrs in
something other than the 'security' extended attribute namespace so that
your server processes don't have to deal with any conflicts.
IOW: maybe add a 'nfs.security' xattr namespace, which would contain
those security labels that are actually exported by this XATTR protocol,
and which the clients could then translate into their local 'security'
labels.
You might even be able to store per-client security labels as something
like 'nfs.$(hostname).security', or perhaps have a namespace like
'nfs.fedora11.security' that applies to all clients running fedora?
> At the top of my todo list is to document the XATTR protocol -- I'll also
> draft a specification for the security namespace along these lines.
Thanks! That would be good.
Trond
On Tue, 13 Oct 2009, Trond Myklebust wrote:
[added the ecryptfs folk]
> On Tue, 2009-10-13 at 18:02 +1100, James Morris wrote:
> > This xattr approach would only cover the "dumb server" scenario, where the
> > server simply stores and retrieves security labels on behalf of the
> > client. It's intended primarily to enable things like nfsroot, backups,
> > serving virtualized file systems etc., and not for fully trusted sharing
> > like Labeled NFS.
> >
> > It is essentially just security label transport.
> >
> > Support for this feature would be configured at the server, possibly an
> > option in /etc/exports which enables specific security namespaces, e.g:
> >
> > /opt/share 10.0.0.0/8(rw,insecure,xattr="user.*,security.SMACK64")
> >
> > This says that the XATTR side protocol is enabled and clients can read and
> > write user and security.smack xattrs (local DAC would be applied to both).
> >
> > The server kernel would likely need to know that these are foreign labels,
> > and not necessarily 'trust' them for its own use, so a root_squash -like
> > option may be used to remap them to an 'untrusted' local label for local
> > enforcement purposes -- if it was running SELinux or Smack at all, which
> > it may not be.
>
> Fair enough. That might indeed work.
>
> One simple alternative might be to just store the exported xattrs in
> something other than the 'security' extended attribute namespace so that
> your server processes don't have to deal with any conflicts.
>
> IOW: maybe add a 'nfs.security' xattr namespace, which would contain
> those security labels that are actually exported by this XATTR protocol,
> and which the clients could then translate into their local 'security'
> labels.
This sounds like a really good idea, and may provide a general solution
for non-user xattrs. i.e. any system, security or trusted xattr is stored
in the 'nfs' namespace on the server, and these are always opaque to the
server -- semantics are managed at the client.
The wire protocol would always carry the client view, for simplicity, and
there's no negotiation -- label mapping is always configured at the server
by the admin.
i.e. the client always sends and receives "security.selinux"; the
server by default maps these locally as "nfs.security.selinux"; and may be
optionally configured to map to "nfs.$(custom).security.selinux"
I wonder how to handle ecryptfs -- it strikes me as a special case where
the semantics are always local i.e. files can always be decrypted locally
because of the crypto metatdata stored with them.
> You might even be able to store per-client security labels as something
> like 'nfs.$(hostname).security', or perhaps have a namespace like
> 'nfs.fedora11.security' that applies to all clients running fedora?
I don't know if there's an established need for this, but some kind of
generalized mapping scheme might be useful, and I suspect it's pretty
simple to implement as long as the xattr values are always opaque to the
server.
- James
--
James Morris
<[email protected]>
James Morris wrote:
> On Tue, 13 Oct 2009, Trond Myklebust wrote:
>
> [added the ecryptfs folk]
>
>
>> On Tue, 2009-10-13 at 18:02 +1100, James Morris wrote:
>>
>>> This xattr approach would only cover the "dumb server" scenario, where the
>>> server simply stores and retrieves security labels on behalf of the
>>> client. It's intended primarily to enable things like nfsroot, backups,
>>> serving virtualized file systems etc., and not for fully trusted sharing
>>> like Labeled NFS.
>>>
>>> It is essentially just security label transport.
>>>
>>> Support for this feature would be configured at the server, possibly an
>>> option in /etc/exports which enables specific security namespaces, e.g:
>>>
>>> /opt/share 10.0.0.0/8(rw,insecure,xattr="user.*,security.SMACK64")
>>>
>>> This says that the XATTR side protocol is enabled and clients can read and
>>> write user and security.smack xattrs (local DAC would be applied to both).
>>>
>>> The server kernel would likely need to know that these are foreign labels,
>>> and not necessarily 'trust' them for its own use, so a root_squash -like
>>> option may be used to remap them to an 'untrusted' local label for local
>>> enforcement purposes -- if it was running SELinux or Smack at all, which
>>> it may not be.
>>>
>> Fair enough. That might indeed work.
>>
>> One simple alternative might be to just store the exported xattrs in
>> something other than the 'security' extended attribute namespace so that
>> your server processes don't have to deal with any conflicts.
>>
>> IOW: maybe add a 'nfs.security' xattr namespace, which would contain
>> those security labels that are actually exported by this XATTR protocol,
>> and which the clients could then translate into their local 'security'
>> labels.
>>
>
> This sounds like a really good idea, and may provide a general solution
> for non-user xattrs. i.e. any system, security or trusted xattr is stored
> in the 'nfs' namespace on the server, and these are always opaque to the
> server -- semantics are managed at the client.
>
> The wire protocol would always carry the client view, for simplicity, and
> there's no negotiation -- label mapping is always configured at the server
> by the admin.
>
If you wanted to you could implement a mapping scheme of your choice
on the server. A Smack server might be happy with mapping
nfs.security.SMACK64 to security.SMACK64, while an HP/UX server might
have a function to map nfs.security.selinux into security.BellAndLaPadula
for its own nefarious purposes. Because you could do this strictly
on the server you don't have to implement a negotiation protocol,
although you could.
> i.e. the client always sends and receives "security.selinux"; the
> server by default maps these locally as "nfs.security.selinux"; and may be
> optionally configured to map to "nfs.$(custom).security.selinux"
>
> I wonder how to handle ecryptfs -- it strikes me as a special case where
> the semantics are always local i.e. files can always be decrypted locally
> because of the crypto metatdata stored with them.
>
>
>> You might even be able to store per-client security labels as something
>> like 'nfs.$(hostname).security', or perhaps have a namespace like
>> 'nfs.fedora11.security' that applies to all clients running fedora?
>>
>
> I don't know if there's an established need for this, but some kind of
> generalized mapping scheme might be useful, and I suspect it's pretty
> simple to implement as long as the xattr values are always opaque to the
> server.
>
>
> - James
>
On Tue, 13 Oct 2009, Casey Schaufler wrote:
> If you wanted to you could implement a mapping scheme of your choice
> on the server.
Just as long as you don't expect any defined semantics from this protocol
-- it's purely xattr transport.
> A Smack server might be happy with mapping
> nfs.security.SMACK64 to security.SMACK64, while an HP/UX server might
> have a function to map nfs.security.selinux into security.BellAndLaPadula
> for its own nefarious purposes. Because you could do this strictly
> on the server you don't have to implement a negotiation protocol,
> although you could.
I think if we start looking at negotiation & interpretation, then we've
moved beyond simple metadata transport and should be looking at extending
NFSv4 instead (e.g. like Labeled NFS).
- James
--
James Morris
<[email protected]>
James Morris wrote:
> On Tue, 13 Oct 2009, Casey Schaufler wrote:
>
>
>> If you wanted to you could implement a mapping scheme of your choice
>> on the server.
>>
>
> Just as long as you don't expect any defined semantics from this protocol
> -- it's purely xattr transport.
>
I agree completely. My point is that you can leave it up to the
server to deal with if it is so inclined. No networking required.
>
>> A Smack server might be happy with mapping
>> nfs.security.SMACK64 to security.SMACK64, while an HP/UX server might
>> have a function to map nfs.security.selinux into security.BellAndLaPadula
>> for its own nefarious purposes. Because you could do this strictly
>> on the server you don't have to implement a negotiation protocol,
>> although you could.
>>
>
> I think if we start looking at negotiation & interpretation, then we've
> moved beyond simple metadata transport and should be looking at extending
> NFSv4 instead (e.g. like Labeled NFS).
>
Again, I agree. The appeal to this xattr approach is that there
is no negotiation. It is just transport and storage. And for those
who question the value of the scheme, it has been in use in Irix
for -I'm not 100% sure- 10 years now.
On Wed, 2009-10-14 at 11:48 +1100, James Morris wrote:
> I wonder how to handle ecryptfs -- it strikes me as a special case
> where the semantics are always local i.e. files can always be
> decrypted locally because of the crypto metatdata stored with them.
Hi James-
Yes, ecryptfs-on-NFS has long been a holy grail for the eCryptfs
project. More generally, getting ecryptfs working on top of *any*
network filesystem (NFS, Samba, sshfs) would be brilliant.
As you say, the beauty is that the decryption happens locally, on your
CPU, and the storage server would just dutifully and agnosticly write
your encrypted bits, and would never see any keys.
We've hit a number of roadblocks, though, most of them of the
filesystems-don't-layer-on-top-of-NFS-well variety.
I don't suppose your present discussion gets us any closer to solving
those?
Regarding metadata, ecryptfs typically stores the metadata in the file
headers, rather than XATTRs.
Cheers,
--
:-Dustin
Dustin Kirkland
Canonical, LTD
[email protected]
GPG: 1024D/83A61194
On Tue, 13 Oct 2009, Dustin Kirkland wrote:
> We've hit a number of roadblocks, though, most of them of the
> filesystems-don't-layer-on-top-of-NFS-well variety.
>
> I don't suppose your present discussion gets us any closer to solving
> those?
Probably not.
- James
--
James Morris
<[email protected]>
Casey Schaufler wrote:
> James Morris wrote:
>> On Tue, 13 Oct 2009, Casey Schaufler wrote:
>>
>>
>>> If you wanted to you could implement a mapping scheme of your choice
>>> on the server.
>>>
>> Just as long as you don't expect any defined semantics from this protocol
>> -- it's purely xattr transport.
>>
>
> I agree completely. My point is that you can leave it up to the
> server to deal with if it is so inclined. No networking required.
>
>>
>>> A Smack server might be happy with mapping
>>> nfs.security.SMACK64 to security.SMACK64, while an HP/UX server might
>>> have a function to map nfs.security.selinux into security.BellAndLaPadula
>>> for its own nefarious purposes. Because you could do this strictly
>>> on the server you don't have to implement a negotiation protocol,
>>> although you could.
>>>
>> I think if we start looking at negotiation & interpretation, then we've
>> moved beyond simple metadata transport and should be looking at extending
>> NFSv4 instead (e.g. like Labeled NFS).
>>
>
> Again, I agree. The appeal to this xattr approach is that there
> is no negotiation. It is just transport and storage. And for those
> who question the value of the scheme, it has been in use in Irix
> for -I'm not 100% sure- 10 years now.
>
We need something like this support and this design is sufficient
to meet the current set of needs. Let's not go too far, trying to
solve problems which do not need to be solved.
Thanx...
ps
On 10/13/2009 07:48 PM, James Morris wrote:
> On Tue, 13 Oct 2009, Trond Myklebust wrote:
>
> [added the ecryptfs folk]
>
>> On Tue, 2009-10-13 at 18:02 +1100, James Morris wrote:
>>> This xattr approach would only cover the "dumb server" scenario, where the
>>> server simply stores and retrieves security labels on behalf of the
>>> client. It's intended primarily to enable things like nfsroot, backups,
>>> serving virtualized file systems etc., and not for fully trusted sharing
>>> like Labeled NFS.
>>>
>>> It is essentially just security label transport.
>>>
>>> Support for this feature would be configured at the server, possibly an
>>> option in /etc/exports which enables specific security namespaces, e.g:
>>>
>>> /opt/share 10.0.0.0/8(rw,insecure,xattr="user.*,security.SMACK64")
>>>
>>> This says that the XATTR side protocol is enabled and clients can read and
>>> write user and security.smack xattrs (local DAC would be applied to both).
>>>
>>> The server kernel would likely need to know that these are foreign labels,
>>> and not necessarily 'trust' them for its own use, so a root_squash -like
>>> option may be used to remap them to an 'untrusted' local label for local
>>> enforcement purposes -- if it was running SELinux or Smack at all, which
>>> it may not be.
>>
>> Fair enough. That might indeed work.
>>
>> One simple alternative might be to just store the exported xattrs in
>> something other than the 'security' extended attribute namespace so that
>> your server processes don't have to deal with any conflicts.
>>
>> IOW: maybe add a 'nfs.security' xattr namespace, which would contain
>> those security labels that are actually exported by this XATTR protocol,
>> and which the clients could then translate into their local 'security'
>> labels.
>
> This sounds like a really good idea, and may provide a general solution
> for non-user xattrs. i.e. any system, security or trusted xattr is stored
> in the 'nfs' namespace on the server, and these are always opaque to the
> server -- semantics are managed at the client.
>
> The wire protocol would always carry the client view, for simplicity, and
> there's no negotiation -- label mapping is always configured at the server
> by the admin.
>
> i.e. the client always sends and receives "security.selinux"; the
> server by default maps these locally as "nfs.security.selinux"; and may be
> optionally configured to map to "nfs.$(custom).security.selinux"
>
> I wonder how to handle ecryptfs -- it strikes me as a special case where
> the semantics are always local i.e. files can always be decrypted locally
> because of the crypto metatdata stored with them.
After skimming back through the thread, I'm not quite understanding the
special case that you're getting at here. Are you assuming that
eCryptfs uses the security namespace?
#define ECRYPTFS_XATTR_NAME "user.ecryptfs"
In my opinion, the option to store the eCryptfs metadata in an xattr is
a bad idea and I haven't heard of anyone actually using the feature.
I've considered removing it for a while now. Don't let this bad
eCryptfs feature get in the way of a good design decision. :)
Tyler
James Morris wrote:
> This patchset is the initial posting of an implementation of extended
> attribute support for the Linux NFSv3 code, and intended as an RFC.
>
> This code is based initially on the GPL'd NFSv3 xattr code from IRIX
> (thanks, Casey!), as well as the existing Linux NFSv3 ACL code. It is
> implemented as a side-protocol and should not affect any existing protocol
> operation. These patches are against the devel branch of the linux-nfs
> tree.
>
> Currently, the code is implemented only to support Linux namespace.name
> xattrs in the "user" namespace. It could be extended to support other
> similar name/value pair xattr implementations (and not far from IRIX wire
> compat), although that's not an aim of this version. There may also be
> some scope for limited support of system xattrs (e.g. 'dumb' security
> label transport), although I've not looked beyond user.* so far.
>
> Three operations are implemented by the new XATTR protocol and map to
> syscalls:
>
> - GETXATTR getxattr(2)
> - LISTXTTR listxattr(2)
> - SETXATTR setxattr(2) and removexattr(2)
>
> This code passes basic testing of the above syscalls, although there are
> some areas which still need work:
>
Is there a set of tests which are used to test this functionality?
> - Dynamic allocation of RPC buffers/pages (currently, the max size of
> e.g. the getxattr(2) value buffer is allocated at the RPC layer for
> each call -- suggestions on the best approach for this welcome)
>
> - Determine appropriate NFS error codes for each operation
>
> - Formal documentation of the XATTR protocol
>
These two would be a good thing. It would be good to at least have
a .x description, although having some of the semantics described
as well would be a good thing.
> - Interoperability with other OSs (we probably should at least
> discuss with BSD folk)
>
It would be good to include the BSD folks, but I think that more
valuable targets would be those with volume servers that might be
encountered at customer sites. I think that we need NetApp, EMC,
perhaps Sun, providing some feedback on the protocol and semantics.
> - Handle size probing for getxattr(2) and listxattr(2) in the client
> (currently faked). I think we should handle this at the client and not
> support it over the wire, as probes are almost always followed
> immediately by full calls, and the protocol can be kept simpler by
> expecting the client to perform a full call over the wire in response
> to a userland probe and caching the result.
>
> - Caching of xattrs at the client
>
This will need a closer specification for the semantics associated
with these xattrs. The need will be how to determine when to
invalidate cached xattrs.
On more bullet that I might suggest is ensuring that the protocol
is compliant with the RPC and XDR standards.
Thanx...
ps
> Please review and comment!
>
> Note that I'll be giving a talk on this at LinuxCon on Thursday:
> http://linuxcon.linuxfoundation.org/meetings/1589 So, in addition to
> discussion here, please come along to the talk if you're at the conf, and
> we may also be able to discuss it at Plumbers in one of the BoFs.
>
> Full diffstat:
>
> fs/nfs/Kconfig | 36 ++++
> fs/nfs/Makefile | 2
> fs/nfs/client.c | 51 ++++++
> fs/nfs/dir.c | 8 -
> fs/nfs/file.c | 8 -
> fs/nfs/internal.h | 19 ++
> fs/nfs/nfs3acl.c | 155 +++++++++++--------
> fs/nfs/nfs3xattr.c | 264 +++++++++++++++++++++++++++++++++
> fs/nfs/nfs3xattr_user.c | 52 ++++++
> fs/nfs/nfs3xdr.c | 187 +++++++++++++++++++++++
> fs/nfs/super.c | 3
> fs/nfsd/Kconfig | 8 +
> fs/nfsd/Makefile | 1
> fs/nfsd/nfs3xattr.c | 352 +++++++++++++++++++++++++++++++++++++++++++++
> fs/nfsd/nfsctl.c | 3
> fs/nfsd/nfssvc.c | 60 +++++++
> fs/nfsd/vfs.c | 5
> include/linux/nfs_fs.h | 16 --
> 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 +++++
> include/linux/nfsd/nfsd.h | 13 +
> include/linux/nfsd/xdr3.h | 46 +++++
> include/linux/sunrpc/svc.h | 2
> 25 files changed, 1265 insertions(+), 98 deletions(-)
>
>
> - James
On Thu, Oct 08, 2009 at 09:19:13AM -0700, Sriram Ramkrishna wrote:
> On Sat, Sep 19, 2009 at 8:09 AM, James Morris <[email protected]> wrote:
>
> >
> > Currently, the code is implemented only to support Linux namespace.name
> > xattrs in the "user" namespace. It could be extended to support other
> > similar name/value pair xattr implementations (and not far from IRIX wire
> > compat), although that's not an aim of this version. There may also be
> > some scope for limited support of system xattrs (e.g. 'dumb' security
> > label transport), although I've not looked beyond user.* so far.
> >
> >
> James this is great news. I personally am interested (as a consumer) in
> setting up better ACL list (ala AFS) than the POSIX model we have now and
> trying to implement it using xattr might be the right way. But my
> frustration of course was that everybody did xattr in different ways and no
> filesystem implementer wanted to go on a limb and implemented such things
> without a RFC.
Yes, we could allow applications on the client to access essentially
arbitrary filesystem-specific functionality. However, this also would
allow applications to become dependent on particular features of the
exported filesystem. There's some question whether we'd really want to
do that.
I assume that it was in order to avoid that question that this initial
implementation only exports the user.* namespace, since xattr's in that
name space are by design not given any special interpretation by the
filesystem--they just store and return opaque data.
--b.
>
>
> >
> > Note that I'll be giving a talk on this at LinuxCon on Thursday:
> > http://linuxcon.linuxfoundation.org/meetings/1589 So, in addition to
> > discussion here, please come along to the talk if you're at the conf, and
> > we may also be able to discuss it at Plumbers in one of the BoFs.
> >
>
>
> Ah, I was there, and I was asking around wanting to talk about the issue!
> Ah well.
>
> sri
On Thu, Oct 08, 2009 at 09:19:13AM -0700, Sriram Ramkrishna wrote:
> On Sat, Sep 19, 2009 at 8:09 AM, James Morris <[email protected]> wrote:
>
> >
> > Currently, the code is implemented only to support Linux namespace.name
> > xattrs in the "user" namespace. It could be extended to support other
> > similar name/value pair xattr implementations (and not far from IRIX wire
> > compat), although that's not an aim of this version. There may also be
> > some scope for limited support of system xattrs (e.g. 'dumb' security
> > label transport), although I've not looked beyond user.* so far.
> >
> >
> James this is great news. I personally am interested (as a consumer) in
> setting up better ACL list (ala AFS) than the POSIX model we have now and
> trying to implement it using xattr might be the right way.
By the way, I'd be curious if you could summarize why POSIX ACLs (and
NFSv4 ACLs?) don't meet your requirements.
--b.
> But my
> frustration of course was that everybody did xattr in different ways and no
> filesystem implementer wanted to go on a limb and implemented such things
> without a RFC.
>
>
> >
> > Note that I'll be giving a talk on this at LinuxCon on Thursday:
> > http://linuxcon.linuxfoundation.org/meetings/1589 So, in addition to
> > discussion here, please come along to the talk if you're at the conf, and
> > we may also be able to discuss it at Plumbers in one of the BoFs.
> >
>
>
> Ah, I was there, and I was asking around wanting to talk about the issue!
> Ah well.
>
> sri
On Thu, 8 Oct 2009, J. Bruce Fields wrote:
> I assume that it was in order to avoid that question that this initial
> implementation only exports the user.* namespace, since xattr's in that
> name space are by design not given any special interpretation by the
> filesystem--they just store and return opaque data.
Correct -- there are no system semantics (beyond existing DACsecurity
checks), so it's straightforward.
Other namespaces would need to have semantics defined on a case by case
basis.
>
> --b.
>
> >
> >
> > >
> > > Note that I'll be giving a talk on this at LinuxCon on Thursday:
> > > http://linuxcon.linuxfoundation.org/meetings/1589 So, in addition to
> > > discussion here, please come along to the talk if you're at the conf, and
> > > we may also be able to discuss it at Plumbers in one of the BoFs.
> > >
> >
> >
> > Ah, I was there, and I was asking around wanting to talk about the issue!
> > Ah well.
> >
> > sri
>
--
James Morris
<[email protected]>
On Tue, 6 Oct 2009, Peter Staubach wrote:
> > Three operations are implemented by the new XATTR protocol and map to
> > syscalls:
> >
> > - GETXATTR getxattr(2)
> > - LISTXTTR listxattr(2)
> > - SETXATTR setxattr(2) and removexattr(2)
> >
> > This code passes basic testing of the above syscalls, although there are
> > some areas which still need work:
> >
>
> Is there a set of tests which are used to test this functionality?
No, I just manually run a set of commands to verify basic behavior.
I gather LTP would be the best place to add tests for this?
> > - Interoperability with other OSs (we probably should at least
> > discuss with BSD folk)
> >
>
> It would be good to include the BSD folks, but I think that more
> valuable targets would be those with volume servers that might be
> encountered at customer sites. I think that we need NetApp, EMC,
> perhaps Sun, providing some feedback on the protocol and semantics.
Given that IETF activity is closed for v3, I wonder what the best forum
would be to reach all these folk?
> > - Caching of xattrs at the client
> >
>
> This will need a closer specification for the semantics associated
> with these xattrs. The need will be how to determine when to
> invalidate cached xattrs.
I suspect user namespace xattrs should be treated like file data wrt
caching (i.e. they're fully under the control of the user).
> On more bullet that I might suggest is ensuring that the protocol
> is compliant with the RPC and XDR standards.
Thanks, I'll check that.
- James
--
James Morris
<[email protected]>
On Fri, Oct 09, 2009 at 11:39:21AM +1100, James Morris wrote:
> No, I just manually run a set of commands to verify basic behavior.
>
> I gather LTP would be the best place to add tests for this?
xfstests has various patches for the xattr system calls, and it also
supports testing NFS in addition to various local filesystems.
James Morris wrote:
> On Tue, 6 Oct 2009, Peter Staubach wrote:
>
>>> Three operations are implemented by the new XATTR protocol and map to
>>> syscalls:
>>>
>>> - GETXATTR getxattr(2)
>>> - LISTXTTR listxattr(2)
>>> - SETXATTR setxattr(2) and removexattr(2)
>>>
>>> This code passes basic testing of the above syscalls, although there are
>>> some areas which still need work:
>>>
>> Is there a set of tests which are used to test this functionality?
>
> No, I just manually run a set of commands to verify basic behavior.
>
> I gather LTP would be the best place to add tests for this?
>
>>> - Interoperability with other OSs (we probably should at least
>>> discuss with BSD folk)
>>>
>> It would be good to include the BSD folks, but I think that more
>> valuable targets would be those with volume servers that might be
>> encountered at customer sites. I think that we need NetApp, EMC,
>> perhaps Sun, providing some feedback on the protocol and semantics.
>
> Given that IETF activity is closed for v3, I wonder what the best forum
> would be to reach all these folk?
>
With some sort of protocol description, it should be possible to
publish some sort of document. Off hand, I don't know what it
might be called, but we can find out.
Otherwise, we might be able to get by with a .x description of
the over the wire protocol and some short words describing the
expected semantics of anything that non-Linux implementators
might need to be aware of.
I know that (at least) a few non-Linux folks lurk here. Might
any of them have any opinions regarding the viability of
implementing this support on their own implementations? TomH?
MichaelE?
>>> - Caching of xattrs at the client
>>>
>> This will need a closer specification for the semantics associated
>> with these xattrs. The need will be how to determine when to
>> invalidate cached xattrs.
>
> I suspect user namespace xattrs should be treated like file data wrt
> caching (i.e. they're fully under the control of the user).
>
Umm, I think that some more detail might be required. For
example, when the file contents are modified, the mtime on
the file is supposed to change. I am wondering what in the
metadata for the file itself changes when an extended attribute
is added, modified, or deleted. It is this information that we
can use to then do correct cache validation and invalidation.
I am assuming that the ctime changes, but we need to explicitly
ensure that this is true or discover what else is.
I believe that without caching, the performance of any resulting
implementations will not be acceptable.
>> On more bullet that I might suggest is ensuring that the protocol
>> is compliant with the RPC and XDR standards.
>
I believe that http://tools.ietf.org/html/rfc5531#appendix-B
describes the portion of this that pertains to obtaining a
registered RPC program number. Otherwise, ensuring that all
of the data structures are encoded according to the XDR
specifications and that all byte orders are encoded according
to the same specification should suffice.
Thanx...
ps
Tom Haynes wrote:
>
>
> Sent from my iPhone
>
> On Oct 12, 2009, at 10:50 AM, Peter Staubach <[email protected]> wrote:
>
>> James Morris wrote:
>>> On Tue, 6 Oct 2009, Peter Staubach wrote:
>>>
>>>>> Three operations are implemented by the new XATTR protocol and map to
>>>>> syscalls:
>>>>>
>>>>> - GETXATTR getxattr(2)
>>>>> - LISTXTTR listxattr(2)
>>>>> - SETXATTR setxattr(2) and removexattr(2)
>>>>>
>>>>> This code passes basic testing of the above syscalls, although
>>>>> there are
>>>>> some areas which still need work:
>>>>>
>>>> Is there a set of tests which are used to test this functionality?
>>>
>>> No, I just manually run a set of commands to verify basic behavior.
>>>
>>> I gather LTP would be the best place to add tests for this?
>>>
>>>>> - Interoperability with other OSs (we probably should at least
>>>>> discuss with BSD folk)
>>>>>
>>>> It would be good to include the BSD folks, but I think that more
>>>> valuable targets would be those with volume servers that might be
>>>> encountered at customer sites. I think that we need NetApp, EMC,
>>>> perhaps Sun, providing some feedback on the protocol and semantics.
>>>
>>> Given that IETF activity is closed for v3, I wonder what the best forum
>>> would be to reach all these folk?
>>>
>>
>> With some sort of protocol description, it should be possible to
>> publish some sort of document. Off hand, I don't know what it
>> might be called, but we can find out.
>>
>> Otherwise, we might be able to get by with a .x description of
>> the over the wire protocol and some short words describing the
>> expected semantics of anything that non-Linux implementators
>> might need to be aware of.
>>
>> I know that (at least) a few non-Linux folks lurk here. Might
>> any of them have any opinions regarding the viability of
>> implementing this support on their own implementations? TomH?
>> MichaelE?
>>
>
> Amazing to find my name in the middle of a thread.
>
Or at least part of it... :-)
> I've just got what is in this email...
>
Hmmm. I wonder why this and not the others. Oh well.
> So, is this a new side band protocol or an extension to NFSv3?
>
This is a side band protocol designed to allow the setting
and getting of Linux style extended attributes. They don't
quite match the Solaris style sub-files approach, but I
think could be implemented on top of the sub-files approach.
> Is there some document describing the problem being solved?
>
Not exactly, or at least, not that I've seen. There is a need
to support general Linux style extended attributes over NFSv3
and NFSv4 prior to 4.2. This will be used in the short term
to solve some of the base issues that are being addressed by
the Labeled NFS work currently underway in the IETF WG. That
work is much more extensive and designed to be a better
solution, but we need something before that work will complete.
I am seeking to discover whether this will be a Linux to
Linux only solution always or whether other vendors might be
amenable to considering implementing this support.
Thanx, Tom.
ps
>
>
>
>
>
>>>>> - Caching of xattrs at the client
>>>>>
>>>> This will need a closer specification for the semantics associated
>>>> with these xattrs. The need will be how to determine when to
>>>> invalidate cached xattrs.
>>>
>>> I suspect user namespace xattrs should be treated like file data wrt
>>> caching (i.e. they're fully under the control of the user).
>>>
>>
>> Umm, I think that some more detail might be required. For
>> example, when the file contents are modified, the mtime on
>> the file is supposed to change. I am wondering what in the
>> metadata for the file itself changes when an extended attribute
>> is added, modified, or deleted. It is this information that we
>> can use to then do correct cache validation and invalidation.
>>
>> I am assuming that the ctime changes, but we need to explicitly
>> ensure that this is true or discover what else is.
>>
>> I believe that without caching, the performance of any resulting
>> implementations will not be acceptable.
>>
>>>> On more bullet that I might suggest is ensuring that the protocol
>>>> is compliant with the RPC and XDR standards.
>>>
>>
>> I believe that http://tools.ietf.org/html/rfc5531#appendix-B
>> describes the portion of this that pertains to obtaining a
>> registered RPC program number. Otherwise, ensuring that all
>> of the data structures are encoded according to the XDR
>> specifications and that all byte orders are encoded according
>> to the same specification should suffice.
>>
>> Thanx...
>>
>> ps
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
>> the body of a message to [email protected]
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
Sent from my iPhone
On Oct 12, 2009, at 10:50 AM, Peter Staubach <[email protected]>
wrote:
> James Morris wrote:
>> On Tue, 6 Oct 2009, Peter Staubach wrote:
>>
>>>> Three operations are implemented by the new XATTR protocol and
>>>> map to
>>>> syscalls:
>>>>
>>>> - GETXATTR getxattr(2)
>>>> - LISTXTTR listxattr(2)
>>>> - SETXATTR setxattr(2) and removexattr(2)
>>>>
>>>> This code passes basic testing of the above syscalls, although
>>>> there are
>>>> some areas which still need work:
>>>>
>>> Is there a set of tests which are used to test this functionality?
>>
>> No, I just manually run a set of commands to verify basic behavior.
>>
>> I gather LTP would be the best place to add tests for this?
>>
>>>> - Interoperability with other OSs (we probably should at least
>>>> discuss with BSD folk)
>>>>
>>> It would be good to include the BSD folks, but I think that more
>>> valuable targets would be those with volume servers that might be
>>> encountered at customer sites. I think that we need NetApp, EMC,
>>> perhaps Sun, providing some feedback on the protocol and semantics.
>>
>> Given that IETF activity is closed for v3, I wonder what the best
>> forum
>> would be to reach all these folk?
>>
>
> With some sort of protocol description, it should be possible to
> publish some sort of document. Off hand, I don't know what it
> might be called, but we can find out.
>
> Otherwise, we might be able to get by with a .x description of
> the over the wire protocol and some short words describing the
> expected semantics of anything that non-Linux implementators
> might need to be aware of.
>
> I know that (at least) a few non-Linux folks lurk here. Might
> any of them have any opinions regarding the viability of
> implementing this support on their own implementations? TomH?
> MichaelE?
>
Amazing to find my name in the middle of a thread.
I've just got what is in this email...
So, is this a new side band protocol or an extension to NFSv3?
Is there some document describing the problem being solved?
>>>> - Caching of xattrs at the client
>>>>
>>> This will need a closer specification for the semantics associated
>>> with these xattrs. The need will be how to determine when to
>>> invalidate cached xattrs.
>>
>> I suspect user namespace xattrs should be treated like file data wrt
>> caching (i.e. they're fully under the control of the user).
>>
>
> Umm, I think that some more detail might be required. For
> example, when the file contents are modified, the mtime on
> the file is supposed to change. I am wondering what in the
> metadata for the file itself changes when an extended attribute
> is added, modified, or deleted. It is this information that we
> can use to then do correct cache validation and invalidation.
>
> I am assuming that the ctime changes, but we need to explicitly
> ensure that this is true or discover what else is.
>
> I believe that without caching, the performance of any resulting
> implementations will not be acceptable.
>
>>> On more bullet that I might suggest is ensuring that the protocol
>>> is compliant with the RPC and XDR standards.
>>
>
> I believe that http://tools.ietf.org/html/rfc5531#appendix-B
> describes the portion of this that pertains to obtaining a
> registered RPC program number. Otherwise, ensuring that all
> of the data structures are encoded according to the XDR
> specifications and that all byte orders are encoded according
> to the same specification should suffice.
>
> Thanx...
>
> ps
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs"
> in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
On Mon, 2009-10-12 at 15:34 -0400, Peter Staubach wrote:
> > So, is this a new side band protocol or an extension to NFSv3?
> >
>
> This is a side band protocol designed to allow the setting
> and getting of Linux style extended attributes. They don't
> quite match the Solaris style sub-files approach, but I
> think could be implemented on top of the sub-files approach.
Sub-files are really a different kettle of fish, since they don't have
any side-effects on the main file itself.
xattrs are basically three different sets of objects bundled into one
set of syscall interfaces.
1. There is a set of 'user' extended attributes, which are
basically arbitrary length named strings. Anyone with read
access to the file can read them, and anyone with write access
can set them. Setting or clearing a user attribute has no
side-effects on the parent file. The most common usage for these
strings appears to be to annotate the file with search metadata
(c.f. beagle)...
2. There are a set of 'trusted' extended attributes. These are
similar to user attributes, in that they have no side-effects,
however you need to use a privileged process in order to set or
read them.
3. The 'system' and 'security' extended attributes are where all
hell breaks loose. These provide storage for things like posix
acls, and selinux security contexts. Setting or clearing these
attributes will almost certainly have side-effects on the parent
file itself, so you really want to be very careful with what you
stuff into them.
> > Is there some document describing the problem being solved?
> >
>
> Not exactly, or at least, not that I've seen. There is a need
> to support general Linux style extended attributes over NFSv3
> and NFSv4 prior to 4.2. This will be used in the short term
> to solve some of the base issues that are being addressed by
> the Labeled NFS work currently underway in the IETF WG. That
> work is much more extensive and designed to be a better
> solution, but we need something before that work will complete.
>
> I am seeking to discover whether this will be a Linux to
> Linux only solution always or whether other vendors might be
> amenable to considering implementing this support.
I don't see how it can be anything but a Linux to Linux, single
distribution only solution if you support setting and clearing 'system'
and 'security' extended attributes, since there appears to be no method
outlined here for negotiating which features the client and server
support.
Without such negotiation (or the requirement that the client and server
be completely homogeneous), how do I, for instance, stop the
'restorecon' utility running on my client from breaking my mail server
process running on a completely different machine when it decides to
reset the 'security.selinux' label on my ~/mail folder?
Cheers,
Trond
On Mon, Oct 12, 2009 at 06:55:58PM -0400, Trond Myklebust wrote:
> On Mon, 2009-10-12 at 15:34 -0400, Peter Staubach wrote:
> > > So, is this a new side band protocol or an extension to NFSv3?
> > >
> >
> > This is a side band protocol designed to allow the setting
> > and getting of Linux style extended attributes. They don't
> > quite match the Solaris style sub-files approach, but I
> > think could be implemented on top of the sub-files approach.
>
> Sub-files are really a different kettle of fish, since they don't have
> any side-effects on the main file itself.
>
> xattrs are basically three different sets of objects bundled into one
> set of syscall interfaces.
>
> 1. There is a set of 'user' extended attributes, which are
> basically arbitrary length named strings. Anyone with read
> access to the file can read them, and anyone with write access
> can set them. Setting or clearing a user attribute has no
> side-effects on the parent file.
It does update the parent file's ctime, though.
--b.
> The most common usage for these
> strings appears to be to annotate the file with search metadata
> (c.f. beagle)...
> 2. There are a set of 'trusted' extended attributes. These are
> similar to user attributes, in that they have no side-effects,
> however you need to use a privileged process in order to set or
> read them.
> 3. The 'system' and 'security' extended attributes are where all
> hell breaks loose. These provide storage for things like posix
> acls, and selinux security contexts. Setting or clearing these
> attributes will almost certainly have side-effects on the parent
> file itself, so you really want to be very careful with what you
> stuff into them.
>
> > > Is there some document describing the problem being solved?
> > >
> >
> > Not exactly, or at least, not that I've seen. There is a need
> > to support general Linux style extended attributes over NFSv3
> > and NFSv4 prior to 4.2. This will be used in the short term
> > to solve some of the base issues that are being addressed by
> > the Labeled NFS work currently underway in the IETF WG. That
> > work is much more extensive and designed to be a better
> > solution, but we need something before that work will complete.
> >
> > I am seeking to discover whether this will be a Linux to
> > Linux only solution always or whether other vendors might be
> > amenable to considering implementing this support.
>
> I don't see how it can be anything but a Linux to Linux, single
> distribution only solution if you support setting and clearing 'system'
> and 'security' extended attributes, since there appears to be no method
> outlined here for negotiating which features the client and server
> support.
> Without such negotiation (or the requirement that the client and server
> be completely homogeneous), how do I, for instance, stop the
> 'restorecon' utility running on my client from breaking my mail server
> process running on a completely different machine when it decides to
> reset the 'security.selinux' label on my ~/mail folder?
>
> Cheers,
> Trond
>
On Mon, 12 Oct 2009, Trond Myklebust wrote:
> I don't see how it can be anything but a Linux to Linux, single
> distribution only solution if you support setting and clearing 'system'
> and 'security' extended attributes, since there appears to be no method
> outlined here for negotiating which features the client and server
> support.
I've been focused on the basic protocol implementation for the user
namespace thus far, to see if the general approach is acceptable before
getting too deep into support for other namespaces.
Interop for other namespaces will vary depending on their semantics -- see
below for my ideas on the security namespace.
> Without such negotiation (or the requirement that the client and server
> be completely homogeneous), how do I, for instance, stop the
> 'restorecon' utility running on my client from breaking my mail server
> process running on a completely different machine when it decides to
> reset the 'security.selinux' label on my ~/mail folder?
This xattr approach would only cover the "dumb server" scenario, where the
server simply stores and retrieves security labels on behalf of the
client. It's intended primarily to enable things like nfsroot, backups,
serving virtualized file systems etc., and not for fully trusted sharing
like Labeled NFS.
It is essentially just security label transport.
Support for this feature would be configured at the server, possibly an
option in /etc/exports which enables specific security namespaces, e.g:
/opt/share 10.0.0.0/8(rw,insecure,xattr="user.*,security.SMACK64")
This says that the XATTR side protocol is enabled and clients can read and
write user and security.smack xattrs (local DAC would be applied to both).
The server kernel would likely need to know that these are foreign labels,
and not necessarily 'trust' them for its own use, so a root_squash -like
option may be used to remap them to an 'untrusted' local label for local
enforcement purposes -- if it was running SELinux or Smack at all, which
it may not be.
At the top of my todo list is to document the XATTR protocol -- I'll also
draft a specification for the security namespace along these lines.
- James
--
James Morris
<[email protected]>
On Wed, 27 Jan 2010, Chuck Lever wrote:
> I haven't followed this closely, but two questions come to mind when reading
> this:
>
> a) why would a distro (or admin building their own kernels) want to disable
> this? iow why not leave the capability always built in?
Some people may want to save memory, and it's in keeping with config
options for similar features such as ACLs.
>
> b) why is the side protocol not compatible with IRIX? wouldn't the IRIX
> protocol be a de facto standard? did you mention before whether there were
> other implementations we _should_ be wire compatible with?
I started out hoping to make it compatible with IRIX, but there are a
couple of issues:
- They use a cursor-based scheme for listxattr, which we don't support at
the xattr API level. If we want wire-compatibility, we could ignore
the cursor field, or try and detect that the client is using it and
return an error.
- We use arbitrary text namespaces, whereas they indicate xattr types
via flags. Technically, we could try and use only the IRIX format:
e.g. only use their flags when talking to an IRIX box, and otherwise
concatenate our xattr namespace and names on the wire.
In both cases, we need to detect that we're talking to an IRIX system
and then alter the way we handle the protocol. It also makes our
implementation more complicated than necessary, and it's not clear to me
what level of demand there is for IRIX and Linux interop for NFSv3.
So, my suggestion would be to implement the protocol in a way which is
optimized for Linux, and then look at adding a separate IRIX compatibility
option which:
- uses a distinct protocol number (the existing IRIX one);
- is wire-compatible;
- handles the cursor field somehow; and
- only supports actual IRIX xattr types.
i.e. an option to support legacy IRIX clients. I don't think there's any
point in trying to support IRIX servers. It keeps the overall code
cleaner, and avoids optimizing for what might be a marginal use case.
I don't know of any other open implementations of xattrs for NFSv3.
- James
--
James Morris
<[email protected]>
On Jan 26, 2010, at 6:09 PM, James Morris wrote:
> 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 <[email protected]>
> ---
> 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).
I haven't followed this closely, but two questions come to mind when
reading this:
a) why would a distro (or admin building their own kernels) want to
disable this? iow why not leave the capability always built in?
b) why is the side protocol not compatible with IRIX? wouldn't the
IRIX protocol be a de facto standard? did you mention before whether
there were other implementations we _should_ be wire compatible with?
> +
> + 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.
Why are these separate config options? It's not exactly obvious to
me, but if there's a good reason, perhaps it should be spelled out in
the help text.
> +
> + 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 <[email protected]>
> *
> * 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
> <[email protected]>
> + *
> + * 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
> <[email protected]>
> + *
> + */
> +#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
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs"
> in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Chuck Lever
chuck[dot]lever[at]oracle[dot]com