* [PATCH v3 00/10] server side user xattr support (RFC 8276) @ 2020-06-23 22:39 Frank van der Linden 2020-06-23 22:39 ` [PATCH v3 01/10] xattr: break delegations in {set,remove}xattr Frank van der Linden ` (12 more replies) 0 siblings, 13 replies; 17+ messages in thread From: Frank van der Linden @ 2020-06-23 22:39 UTC (permalink / raw) To: bfields, chuck.lever, linux-nfs; +Cc: Frank van der Linden v3: * Rebase to v5.8-rc2 * Use length probe + allocate + query for the listxattr and setxattr operations to avoid allocating unneeded space. * Because of the above, drop the 'use kvmalloc for svcxdr_tmpalloc' patch, as it's no longer needed. v2: * As per the discussion, user extended attributes are enabled if the client and server support them (e.g. they support 4.2 and advertise the user extended attribute FATTR). There are no longer options to switch them off. * The code is no longer conditioned on a config option. * The number of patches has been reduced somewhat by merging smaller, related ones. * Renamed some functions and added parameter comments as requested. v1: * Split in to client and server (changed from the original RFC patch). Original RFC combined set is here: https://www.spinics.net/lists/linux-nfs/msg74843.html In general, these patches were, both server and client, tested as follows: * stress-ng-xattr with 1000 workers * Test all corner cases (XATTR_SIZE_*) * Test all failure cases (no xattr, setxattr with different or invalid flags, etc). * Verify the content of xattrs across several operations. * Use KASAN and KMEMLEAK for a longer mix of testruns to verify that there were no leaks (after unmounting the filesystem). * Interop run against FreeBSD server/client implementation. * Ran xfstests-dev, with no unexpected/new failures as compared to an unpatched kernel. To fully use xfstests-dev, it needed some modifications, as it expects to either use all xattr namespaces, or none. Whereas NFS only suppors the "user." namespace (+ optional ACLs). I will send the changes in seperately. Frank van der Linden (10): xattr: break delegations in {set,remove}xattr xattr: add a function to check if a namespace is supported nfs,nfsd: NFSv4.2 extended attribute protocol definitions nfsd: split off the write decode code in to a separate function nfsd: add defines for NFSv4.2 extended attribute support nfsd: define xattr functions to call in to their vfs counterparts nfsd: take xattr bits in to account for permission checks nfsd: add structure definitions for xattr requests / responses nfsd: implement the xattr functions and en/decode logic nfsd: add fattr support for user extended attributes fs/nfsd/nfs4proc.c | 128 ++++++++- fs/nfsd/nfs4xdr.c | 531 +++++++++++++++++++++++++++++++++++--- fs/nfsd/nfsd.h | 5 +- fs/nfsd/vfs.c | 239 +++++++++++++++++ fs/nfsd/vfs.h | 10 + fs/nfsd/xdr4.h | 31 +++ fs/xattr.c | 111 +++++++- include/linux/nfs4.h | 22 +- include/linux/xattr.h | 4 + include/uapi/linux/nfs4.h | 3 + 10 files changed, 1044 insertions(+), 40 deletions(-) -- 2.17.2 ^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v3 01/10] xattr: break delegations in {set,remove}xattr 2020-06-23 22:39 [PATCH v3 00/10] server side user xattr support (RFC 8276) Frank van der Linden @ 2020-06-23 22:39 ` Frank van der Linden 2020-06-23 22:39 ` [PATCH v3 02/10] xattr: add a function to check if a namespace is supported Frank van der Linden ` (11 subsequent siblings) 12 siblings, 0 replies; 17+ messages in thread From: Frank van der Linden @ 2020-06-23 22:39 UTC (permalink / raw) To: bfields, chuck.lever, linux-nfs Cc: Frank van der Linden, linux-fsdevel, Al Viro set/removexattr on an exported filesystem should break NFS delegations. This is true in general, but also for the upcoming support for RFC 8726 (NFSv4 extended attribute support). Make sure that they do. Additonally, they need to grow a _locked variant, since callers might call this with i_rwsem held (like the NFS server code). Cc: stable@vger.kernel.org Cc: linux-fsdevel@vger.kernel.org Cc: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Frank van der Linden <fllinden@amazon.com> --- fs/xattr.c | 84 +++++++++++++++++++++++++++++++++++++++---- include/linux/xattr.h | 2 ++ 2 files changed, 79 insertions(+), 7 deletions(-) diff --git a/fs/xattr.c b/fs/xattr.c index 91608d9bfc6a..95f38f57347f 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -204,10 +204,22 @@ int __vfs_setxattr_noperm(struct dentry *dentry, const char *name, return error; } - +/** + * __vfs_setxattr_locked: set an extended attribute while holding the inode + * lock + * + * @dentry - object to perform setxattr on + * @name - xattr name to set + * @value - value to set @name to + * @size - size of @value + * @flags - flags to pass into filesystem operations + * @delegated_inode - on return, will contain an inode pointer that + * a delegation was broken on, NULL if none. + */ int -vfs_setxattr(struct dentry *dentry, const char *name, const void *value, - size_t size, int flags) +__vfs_setxattr_locked(struct dentry *dentry, const char *name, + const void *value, size_t size, int flags, + struct inode **delegated_inode) { struct inode *inode = dentry->d_inode; int error; @@ -216,15 +228,40 @@ vfs_setxattr(struct dentry *dentry, const char *name, const void *value, if (error) return error; - inode_lock(inode); error = security_inode_setxattr(dentry, name, value, size, flags); if (error) goto out; + error = try_break_deleg(inode, delegated_inode); + if (error) + goto out; + error = __vfs_setxattr_noperm(dentry, name, value, size, flags); out: + return error; +} +EXPORT_SYMBOL_GPL(__vfs_setxattr_locked); + +int +vfs_setxattr(struct dentry *dentry, const char *name, const void *value, + size_t size, int flags) +{ + struct inode *inode = dentry->d_inode; + struct inode *delegated_inode = NULL; + int error; + +retry_deleg: + inode_lock(inode); + error = __vfs_setxattr_locked(dentry, name, value, size, flags, + &delegated_inode); inode_unlock(inode); + + if (delegated_inode) { + error = break_deleg_wait(&delegated_inode); + if (!error) + goto retry_deleg; + } return error; } EXPORT_SYMBOL_GPL(vfs_setxattr); @@ -378,8 +415,18 @@ __vfs_removexattr(struct dentry *dentry, const char *name) } EXPORT_SYMBOL(__vfs_removexattr); +/** + * __vfs_removexattr_locked: set an extended attribute while holding the inode + * lock + * + * @dentry - object to perform setxattr on + * @name - name of xattr to remove + * @delegated_inode - on return, will contain an inode pointer that + * a delegation was broken on, NULL if none. + */ int -vfs_removexattr(struct dentry *dentry, const char *name) +__vfs_removexattr_locked(struct dentry *dentry, const char *name, + struct inode **delegated_inode) { struct inode *inode = dentry->d_inode; int error; @@ -388,11 +435,14 @@ vfs_removexattr(struct dentry *dentry, const char *name) if (error) return error; - inode_lock(inode); error = security_inode_removexattr(dentry, name); if (error) goto out; + error = try_break_deleg(inode, delegated_inode); + if (error) + goto out; + error = __vfs_removexattr(dentry, name); if (!error) { @@ -401,12 +451,32 @@ vfs_removexattr(struct dentry *dentry, const char *name) } out: + return error; +} +EXPORT_SYMBOL_GPL(__vfs_removexattr_locked); + +int +vfs_removexattr(struct dentry *dentry, const char *name) +{ + struct inode *inode = dentry->d_inode; + struct inode *delegated_inode = NULL; + int error; + +retry_deleg: + inode_lock(inode); + error = __vfs_removexattr_locked(dentry, name, &delegated_inode); inode_unlock(inode); + + if (delegated_inode) { + error = break_deleg_wait(&delegated_inode); + if (!error) + goto retry_deleg; + } + return error; } EXPORT_SYMBOL_GPL(vfs_removexattr); - /* * Extended attribute SET operations */ diff --git a/include/linux/xattr.h b/include/linux/xattr.h index 47eaa34f8761..a2f3cd02653c 100644 --- a/include/linux/xattr.h +++ b/include/linux/xattr.h @@ -51,8 +51,10 @@ ssize_t vfs_getxattr(struct dentry *, const char *, void *, size_t); ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size); int __vfs_setxattr(struct dentry *, struct inode *, const char *, const void *, size_t, int); int __vfs_setxattr_noperm(struct dentry *, const char *, const void *, size_t, int); +int __vfs_setxattr_locked(struct dentry *, const char *, const void *, size_t, int, struct inode **); int vfs_setxattr(struct dentry *, const char *, const void *, size_t, int); int __vfs_removexattr(struct dentry *, const char *); +int __vfs_removexattr_locked(struct dentry *, const char *, struct inode **); int vfs_removexattr(struct dentry *, const char *); ssize_t generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size); -- 2.17.2 ^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v3 02/10] xattr: add a function to check if a namespace is supported 2020-06-23 22:39 [PATCH v3 00/10] server side user xattr support (RFC 8276) Frank van der Linden 2020-06-23 22:39 ` [PATCH v3 01/10] xattr: break delegations in {set,remove}xattr Frank van der Linden @ 2020-06-23 22:39 ` Frank van der Linden 2020-06-23 22:39 ` [PATCH v3 03/10] nfs,nfsd: NFSv4.2 extended attribute protocol definitions Frank van der Linden ` (10 subsequent siblings) 12 siblings, 0 replies; 17+ messages in thread From: Frank van der Linden @ 2020-06-23 22:39 UTC (permalink / raw) To: bfields, chuck.lever, linux-nfs Cc: Frank van der Linden, linux-fsdevel, Al Viro Add a function that checks is an extended attribute namespace is supported for an inode, meaning that a handler must be present for either the whole namespace, or at least one synthetic xattr in the namespace. To be used by the nfs server code when being queried for extended attributes support. Cc: linux-fsdevel@vger.kernel.org Cc: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Frank van der Linden <fllinden@amazon.com> --- fs/xattr.c | 27 +++++++++++++++++++++++++++ include/linux/xattr.h | 2 ++ 2 files changed, 29 insertions(+) diff --git a/fs/xattr.c b/fs/xattr.c index 95f38f57347f..386b45676d7e 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -134,6 +134,33 @@ xattr_permission(struct inode *inode, const char *name, int mask) return inode_permission(inode, mask); } +/* + * Look for any handler that deals with the specified namespace. + */ +int +xattr_supported_namespace(struct inode *inode, const char *prefix) +{ + const struct xattr_handler **handlers = inode->i_sb->s_xattr; + const struct xattr_handler *handler; + size_t preflen; + + if (!(inode->i_opflags & IOP_XATTR)) { + if (unlikely(is_bad_inode(inode))) + return -EIO; + return -EOPNOTSUPP; + } + + preflen = strlen(prefix); + + for_each_xattr_handler(handlers, handler) { + if (!strncmp(xattr_prefix(handler), prefix, preflen)) + return 0; + } + + return -EOPNOTSUPP; +} +EXPORT_SYMBOL(xattr_supported_namespace); + int __vfs_setxattr(struct dentry *dentry, struct inode *inode, const char *name, const void *value, size_t size, int flags) diff --git a/include/linux/xattr.h b/include/linux/xattr.h index a2f3cd02653c..fac75810d9d3 100644 --- a/include/linux/xattr.h +++ b/include/linux/xattr.h @@ -61,6 +61,8 @@ ssize_t generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_siz ssize_t vfs_getxattr_alloc(struct dentry *dentry, const char *name, char **xattr_value, size_t size, gfp_t flags); +int xattr_supported_namespace(struct inode *inode, const char *prefix); + static inline const char *xattr_prefix(const struct xattr_handler *handler) { return handler->prefix ?: handler->name; -- 2.17.2 ^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v3 03/10] nfs,nfsd: NFSv4.2 extended attribute protocol definitions 2020-06-23 22:39 [PATCH v3 00/10] server side user xattr support (RFC 8276) Frank van der Linden 2020-06-23 22:39 ` [PATCH v3 01/10] xattr: break delegations in {set,remove}xattr Frank van der Linden 2020-06-23 22:39 ` [PATCH v3 02/10] xattr: add a function to check if a namespace is supported Frank van der Linden @ 2020-06-23 22:39 ` Frank van der Linden 2020-06-23 22:39 ` [PATCH v3 04/10] nfsd: split off the write decode code in to a separate function Frank van der Linden ` (9 subsequent siblings) 12 siblings, 0 replies; 17+ messages in thread From: Frank van der Linden @ 2020-06-23 22:39 UTC (permalink / raw) To: bfields, chuck.lever, linux-nfs; +Cc: Frank van der Linden Add definitions for the new operations, errors and flags as defined in RFC 8276 (File System Extended Attributes in NFSv4). Signed-off-by: Frank van der Linden <fllinden@amazon.com> --- include/linux/nfs4.h | 20 ++++++++++++++++++++ include/uapi/linux/nfs4.h | 3 +++ 2 files changed, 23 insertions(+) diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index 4dba3c948932..e6ca9d1d2e76 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -150,6 +150,12 @@ enum nfs_opnum4 { OP_WRITE_SAME = 70, OP_CLONE = 71, + /* xattr support (RFC8726) */ + OP_GETXATTR = 72, + OP_SETXATTR = 73, + OP_LISTXATTRS = 74, + OP_REMOVEXATTR = 75, + OP_ILLEGAL = 10044, }; @@ -280,6 +286,10 @@ enum nfsstat4 { NFS4ERR_WRONG_LFS = 10092, NFS4ERR_BADLABEL = 10093, NFS4ERR_OFFLOAD_NO_REQS = 10094, + + /* xattr (RFC8276) */ + NFS4ERR_NOXATTR = 10095, + NFS4ERR_XATTR2BIG = 10096, }; static inline bool seqid_mutating_err(u32 err) @@ -452,6 +462,7 @@ enum change_attr_type4 { #define FATTR4_WORD2_CHANGE_ATTR_TYPE (1UL << 15) #define FATTR4_WORD2_SECURITY_LABEL (1UL << 16) #define FATTR4_WORD2_MODE_UMASK (1UL << 17) +#define FATTR4_WORD2_XATTR_SUPPORT (1UL << 18) /* MDS threshold bitmap bits */ #define THRESHOLD_RD (1UL << 0) @@ -700,4 +711,13 @@ struct nl4_server { struct nfs42_netaddr nl4_addr; /* NL4_NETADDR */ } u; }; + +/* + * Options for setxattr. These match the flags for setxattr(2). + */ +enum nfs4_setxattr_options { + SETXATTR4_EITHER = 0, + SETXATTR4_CREATE = 1, + SETXATTR4_REPLACE = 2, +}; #endif diff --git a/include/uapi/linux/nfs4.h b/include/uapi/linux/nfs4.h index 8572930cf5b0..bf197e99b98f 100644 --- a/include/uapi/linux/nfs4.h +++ b/include/uapi/linux/nfs4.h @@ -33,6 +33,9 @@ #define NFS4_ACCESS_EXTEND 0x0008 #define NFS4_ACCESS_DELETE 0x0010 #define NFS4_ACCESS_EXECUTE 0x0020 +#define NFS4_ACCESS_XAREAD 0x0040 +#define NFS4_ACCESS_XAWRITE 0x0080 +#define NFS4_ACCESS_XALIST 0x0100 #define NFS4_FH_PERSISTENT 0x0000 #define NFS4_FH_NOEXPIRE_WITH_OPEN 0x0001 -- 2.17.2 ^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v3 04/10] nfsd: split off the write decode code in to a separate function 2020-06-23 22:39 [PATCH v3 00/10] server side user xattr support (RFC 8276) Frank van der Linden ` (2 preceding siblings ...) 2020-06-23 22:39 ` [PATCH v3 03/10] nfs,nfsd: NFSv4.2 extended attribute protocol definitions Frank van der Linden @ 2020-06-23 22:39 ` Frank van der Linden 2020-06-23 22:39 ` [PATCH v3 05/10] nfsd: add defines for NFSv4.2 extended attribute support Frank van der Linden ` (8 subsequent siblings) 12 siblings, 0 replies; 17+ messages in thread From: Frank van der Linden @ 2020-06-23 22:39 UTC (permalink / raw) To: bfields, chuck.lever, linux-nfs; +Cc: Frank van der Linden nfs4_decode_write has code to parse incoming XDR write data in to a kvec head, and a list of pages. Put this code in to a separate function, so that it can be used later by the xattr code, for setxattr. No functional change. Signed-off-by: Frank van der Linden <fllinden@amazon.com> --- fs/nfsd/nfs4xdr.c | 72 +++++++++++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 30 deletions(-) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 996ac01ee977..48806b493eba 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -257,6 +257,44 @@ svcxdr_dupstr(struct nfsd4_compoundargs *argp, void *buf, u32 len) return p; } +static __be32 +svcxdr_construct_vector(struct nfsd4_compoundargs *argp, struct kvec *head, + struct page ***pagelist, u32 buflen) +{ + int avail; + int len; + int pages; + + /* Sorry .. no magic macros for this.. * + * READ_BUF(write->wr_buflen); + * SAVEMEM(write->wr_buf, write->wr_buflen); + */ + avail = (char *)argp->end - (char *)argp->p; + if (avail + argp->pagelen < buflen) { + dprintk("NFSD: xdr error (%s:%d)\n", + __FILE__, __LINE__); + return nfserr_bad_xdr; + } + head->iov_base = argp->p; + head->iov_len = avail; + *pagelist = argp->pagelist; + + len = XDR_QUADLEN(buflen) << 2; + if (len >= avail) { + len -= avail; + + pages = len >> PAGE_SHIFT; + argp->pagelist += pages; + argp->pagelen -= pages * PAGE_SIZE; + len -= pages * PAGE_SIZE; + + next_decode_page(argp); + } + argp->p += XDR_QUADLEN(len); + + return 0; +} + /** * savemem - duplicate a chunk of memory for later processing * @argp: NFSv4 compound argument structure to be freed with @@ -1265,8 +1303,6 @@ nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify static __be32 nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) { - int avail; - int len; DECODE_HEAD; status = nfsd4_decode_stateid(argp, &write->wr_stateid); @@ -1279,34 +1315,10 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) goto xdr_error; write->wr_buflen = be32_to_cpup(p++); - /* Sorry .. no magic macros for this.. * - * READ_BUF(write->wr_buflen); - * SAVEMEM(write->wr_buf, write->wr_buflen); - */ - avail = (char*)argp->end - (char*)argp->p; - if (avail + argp->pagelen < write->wr_buflen) { - dprintk("NFSD: xdr error (%s:%d)\n", - __FILE__, __LINE__); - goto xdr_error; - } - write->wr_head.iov_base = p; - write->wr_head.iov_len = avail; - write->wr_pagelist = argp->pagelist; - - len = XDR_QUADLEN(write->wr_buflen) << 2; - if (len >= avail) { - int pages; - - len -= avail; - - pages = len >> PAGE_SHIFT; - argp->pagelist += pages; - argp->pagelen -= pages * PAGE_SIZE; - len -= pages * PAGE_SIZE; - - next_decode_page(argp); - } - argp->p += XDR_QUADLEN(len); + status = svcxdr_construct_vector(argp, &write->wr_head, + &write->wr_pagelist, write->wr_buflen); + if (status) + return status; DECODE_TAIL; } -- 2.17.2 ^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v3 05/10] nfsd: add defines for NFSv4.2 extended attribute support 2020-06-23 22:39 [PATCH v3 00/10] server side user xattr support (RFC 8276) Frank van der Linden ` (3 preceding siblings ...) 2020-06-23 22:39 ` [PATCH v3 04/10] nfsd: split off the write decode code in to a separate function Frank van der Linden @ 2020-06-23 22:39 ` Frank van der Linden 2020-06-23 22:39 ` [PATCH v3 06/10] nfsd: define xattr functions to call in to their vfs counterparts Frank van der Linden ` (7 subsequent siblings) 12 siblings, 0 replies; 17+ messages in thread From: Frank van der Linden @ 2020-06-23 22:39 UTC (permalink / raw) To: bfields, chuck.lever, linux-nfs; +Cc: Frank van der Linden Add defines for server-side extended attribute support. Most have already been added as part of client support, but these are the network order error codes for the noxattr and xattr2big errors, and the addition of the xattr support to the supported file attributes (if configured). Signed-off-by: Frank van der Linden <fllinden@amazon.com> --- fs/nfsd/nfsd.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index 36cdd81b6688..5343c771da18 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -283,6 +283,8 @@ void nfsd_lockd_shutdown(void); #define nfserr_wrong_lfs cpu_to_be32(NFS4ERR_WRONG_LFS) #define nfserr_badlabel cpu_to_be32(NFS4ERR_BADLABEL) #define nfserr_file_open cpu_to_be32(NFS4ERR_FILE_OPEN) +#define nfserr_xattr2big cpu_to_be32(NFS4ERR_XATTR2BIG) +#define nfserr_noxattr cpu_to_be32(NFS4ERR_NOXATTR) /* error codes for internal use */ /* if a request fails due to kmalloc failure, it gets dropped. @@ -384,7 +386,8 @@ void nfsd_lockd_shutdown(void); (NFSD4_1_SUPPORTED_ATTRS_WORD2 | \ FATTR4_WORD2_CHANGE_ATTR_TYPE | \ FATTR4_WORD2_MODE_UMASK | \ - NFSD4_2_SECURITY_ATTRS) + NFSD4_2_SECURITY_ATTRS | \ + FATTR4_WORD2_XATTR_SUPPORT) extern const u32 nfsd_suppattrs[3][3]; -- 2.17.2 ^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v3 06/10] nfsd: define xattr functions to call in to their vfs counterparts 2020-06-23 22:39 [PATCH v3 00/10] server side user xattr support (RFC 8276) Frank van der Linden ` (4 preceding siblings ...) 2020-06-23 22:39 ` [PATCH v3 05/10] nfsd: add defines for NFSv4.2 extended attribute support Frank van der Linden @ 2020-06-23 22:39 ` Frank van der Linden 2020-06-23 22:39 ` [PATCH v3 07/10] nfsd: take xattr bits in to account for permission checks Frank van der Linden ` (6 subsequent siblings) 12 siblings, 0 replies; 17+ messages in thread From: Frank van der Linden @ 2020-06-23 22:39 UTC (permalink / raw) To: bfields, chuck.lever, linux-nfs; +Cc: Frank van der Linden This adds the filehandle based functions for the xattr operations that call in to the vfs layer to do the actual work. Signed-off-by: Frank van der Linden <fllinden@amazon.com> --- fs/nfsd/vfs.c | 227 ++++++++++++++++++++++++++++++++++++++++++++++++++ fs/nfsd/vfs.h | 10 +++ 2 files changed, 237 insertions(+) diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index c3fbab1753ec..b1dd8690e25d 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -2059,6 +2059,233 @@ static int exp_rdonly(struct svc_rqst *rqstp, struct svc_export *exp) return nfsexp_flags(rqstp, exp) & NFSEXP_READONLY; } +#ifdef CONFIG_NFSD_V4 +/* + * Helper function to translate error numbers. In the case of xattr operations, + * some error codes need to be translated outside of the standard translations. + * + * ENODATA needs to be translated to nfserr_noxattr. + * E2BIG to nfserr_xattr2big. + * + * Additionally, vfs_listxattr can return -ERANGE. This means that the + * file has too many extended attributes to retrieve inside an + * XATTR_LIST_MAX sized buffer. This is a bug in the xattr implementation: + * filesystems will allow the adding of extended attributes until they hit + * their own internal limit. This limit may be larger than XATTR_LIST_MAX. + * So, at that point, the attributes are present and valid, but can't + * be retrieved using listxattr, since the upper level xattr code enforces + * the XATTR_LIST_MAX limit. + * + * This bug means that we need to deal with listxattr returning -ERANGE. The + * best mapping is to return TOOSMALL. + */ +static __be32 +nfsd_xattr_errno(int err) +{ + switch (err) { + case -ENODATA: + return nfserr_noxattr; + case -E2BIG: + return nfserr_xattr2big; + case -ERANGE: + return nfserr_toosmall; + } + return nfserrno(err); +} + +/* + * Retrieve the specified user extended attribute. To avoid always + * having to allocate the maximum size (since we are not getting + * a maximum size from the RPC), do a probe + alloc. Hold a reader + * lock on i_rwsem to prevent the extended attribute from changing + * size while we're doing this. + */ +__be32 +nfsd_getxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name, + void **bufp, int *lenp) +{ + ssize_t len; + __be32 err; + char *buf; + struct inode *inode; + struct dentry *dentry; + + err = fh_verify(rqstp, fhp, 0, NFSD_MAY_READ); + if (err) + return err; + + err = nfs_ok; + dentry = fhp->fh_dentry; + inode = d_inode(dentry); + + inode_lock_shared(inode); + + len = vfs_getxattr(dentry, name, NULL, 0); + + /* + * Zero-length attribute, just return. + */ + if (len == 0) { + *bufp = NULL; + *lenp = 0; + goto out; + } + + if (len < 0) { + err = nfsd_xattr_errno(len); + goto out; + } + + if (len > *lenp) { + err = nfserr_toosmall; + goto out; + } + + buf = kvmalloc(len, GFP_KERNEL | GFP_NOFS); + if (buf == NULL) { + err = nfserr_jukebox; + goto out; + } + + len = vfs_getxattr(dentry, name, buf, len); + if (len <= 0) { + kvfree(buf); + buf = NULL; + err = nfsd_xattr_errno(len); + } + + *lenp = len; + *bufp = buf; + +out: + inode_unlock_shared(inode); + + return err; +} + +/* + * Retrieve the xattr names. Since we can't know how many are + * user extended attributes, we must get all attributes here, + * and have the XDR encode filter out the "user." ones. + * + * While this could always just allocate an XATTR_LIST_MAX + * buffer, that's a waste, so do a probe + allocate. To + * avoid any changes between the probe and allocate, wrap + * this in inode_lock. + */ +__be32 +nfsd_listxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char **bufp, + int *lenp) +{ + ssize_t len; + __be32 err; + char *buf; + struct inode *inode; + struct dentry *dentry; + + err = fh_verify(rqstp, fhp, 0, NFSD_MAY_READ); + if (err) + return err; + + dentry = fhp->fh_dentry; + inode = d_inode(dentry); + *lenp = 0; + + inode_lock_shared(inode); + + len = vfs_listxattr(dentry, NULL, 0); + if (len <= 0) { + err = nfsd_xattr_errno(len); + goto out; + } + + if (len > XATTR_LIST_MAX) { + err = nfserr_xattr2big; + goto out; + } + + /* + * We're holding i_rwsem - use GFP_NOFS. + */ + buf = kvmalloc(len, GFP_KERNEL | GFP_NOFS); + if (buf == NULL) { + err= nfserr_jukebox; + goto out; + } + + len = vfs_listxattr(dentry, buf, len); + if (len <= 0) { + kvfree(buf); + err = nfsd_xattr_errno(len); + goto out; + } + + *lenp = len; + *bufp = buf; + + err = nfs_ok; +out: + inode_unlock_shared(inode); + + return err; +} + +/* + * Removexattr and setxattr need to call fh_lock to both lock the inode + * and set the change attribute. Since the top-level vfs_removexattr + * and vfs_setxattr calls already do their own inode_lock calls, call + * the _locked variant. Pass in a NULL pointer for delegated_inode, + * and let the client deal with NFS4ERR_DELAY (same as with e.g. + * setattr and remove). + */ +__be32 +nfsd_removexattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name) +{ + int err, ret; + + err = fh_verify(rqstp, fhp, 0, NFSD_MAY_WRITE); + if (err) + return err; + + ret = fh_want_write(fhp); + if (ret) + return nfserrno(ret); + + fh_lock(fhp); + + ret = __vfs_removexattr_locked(fhp->fh_dentry, name, NULL); + + fh_unlock(fhp); + fh_drop_write(fhp); + + return nfsd_xattr_errno(ret); +} + +__be32 +nfsd_setxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name, + void *buf, u32 len, u32 flags) +{ + int err, ret; + + err = fh_verify(rqstp, fhp, 0, NFSD_MAY_WRITE); + if (err) + return err; + + ret = fh_want_write(fhp); + if (ret) + return nfserrno(ret); + fh_lock(fhp); + + ret = __vfs_setxattr_locked(fhp->fh_dentry, name, buf, len, flags, + NULL); + + fh_unlock(fhp); + fh_drop_write(fhp); + + return nfsd_xattr_errno(ret); +} +#endif + /* * Check for a user's access permissions to this inode. */ diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h index 3eb660ad80d1..a2442ebe5acf 100644 --- a/fs/nfsd/vfs.h +++ b/fs/nfsd/vfs.h @@ -76,6 +76,16 @@ __be32 do_nfsd_create(struct svc_rqst *, struct svc_fh *, __be32 nfsd_commit(struct svc_rqst *, struct svc_fh *, loff_t, unsigned long, __be32 *verf); #endif /* CONFIG_NFSD_V3 */ +#ifdef CONFIG_NFSD_V4 +__be32 nfsd_getxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, + char *name, void **bufp, int *lenp); +__be32 nfsd_listxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, + char **bufp, int *lenp); +__be32 nfsd_removexattr(struct svc_rqst *rqstp, struct svc_fh *fhp, + char *name); +__be32 nfsd_setxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, + char *name, void *buf, u32 len, u32 flags); +#endif int nfsd_open_break_lease(struct inode *, int); __be32 nfsd_open(struct svc_rqst *, struct svc_fh *, umode_t, int, struct file **); -- 2.17.2 ^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v3 07/10] nfsd: take xattr bits in to account for permission checks 2020-06-23 22:39 [PATCH v3 00/10] server side user xattr support (RFC 8276) Frank van der Linden ` (5 preceding siblings ...) 2020-06-23 22:39 ` [PATCH v3 06/10] nfsd: define xattr functions to call in to their vfs counterparts Frank van der Linden @ 2020-06-23 22:39 ` Frank van der Linden 2020-06-23 22:39 ` [PATCH v3 08/10] nfsd: add structure definitions for xattr requests / responses Frank van der Linden ` (5 subsequent siblings) 12 siblings, 0 replies; 17+ messages in thread From: Frank van der Linden @ 2020-06-23 22:39 UTC (permalink / raw) To: bfields, chuck.lever, linux-nfs; +Cc: Frank van der Linden Since the NFSv4.2 extended attributes extension defines 3 new access bits for xattr operations, take them in to account when validating what the client is asking for, and when checking permissions. Signed-off-by: Frank van der Linden <fllinden@amazon.com> --- fs/nfsd/nfs4proc.c | 8 +++++++- fs/nfsd/vfs.c | 12 ++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index a09c35f0f6f0..841aad772798 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -566,8 +566,14 @@ nfsd4_access(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, union nfsd4_op_u *u) { struct nfsd4_access *access = &u->access; + u32 access_full; - if (access->ac_req_access & ~NFS3_ACCESS_FULL) + access_full = NFS3_ACCESS_FULL; + if (cstate->minorversion >= 2) + access_full |= NFS4_ACCESS_XALIST | NFS4_ACCESS_XAREAD | + NFS4_ACCESS_XAWRITE; + + if (access->ac_req_access & ~access_full) return nfserr_inval; access->ac_resp_access = access->ac_req_access; diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index b1dd8690e25d..8e223b3bf26f 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -612,6 +612,12 @@ static struct accessmap nfs3_regaccess[] = { { NFS3_ACCESS_MODIFY, NFSD_MAY_WRITE|NFSD_MAY_TRUNC }, { NFS3_ACCESS_EXTEND, NFSD_MAY_WRITE }, +#ifdef CONFIG_NFSD_V4 + { NFS4_ACCESS_XAREAD, NFSD_MAY_READ }, + { NFS4_ACCESS_XAWRITE, NFSD_MAY_WRITE }, + { NFS4_ACCESS_XALIST, NFSD_MAY_READ }, +#endif + { 0, 0 } }; @@ -622,6 +628,12 @@ static struct accessmap nfs3_diraccess[] = { { NFS3_ACCESS_EXTEND, NFSD_MAY_EXEC|NFSD_MAY_WRITE }, { NFS3_ACCESS_DELETE, NFSD_MAY_REMOVE }, +#ifdef CONFIG_NFSD_V4 + { NFS4_ACCESS_XAREAD, NFSD_MAY_READ }, + { NFS4_ACCESS_XAWRITE, NFSD_MAY_WRITE }, + { NFS4_ACCESS_XALIST, NFSD_MAY_READ }, +#endif + { 0, 0 } }; -- 2.17.2 ^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v3 08/10] nfsd: add structure definitions for xattr requests / responses 2020-06-23 22:39 [PATCH v3 00/10] server side user xattr support (RFC 8276) Frank van der Linden ` (6 preceding siblings ...) 2020-06-23 22:39 ` [PATCH v3 07/10] nfsd: take xattr bits in to account for permission checks Frank van der Linden @ 2020-06-23 22:39 ` Frank van der Linden 2020-06-23 22:39 ` [PATCH v3 09/10] nfsd: implement the xattr functions and en/decode logic Frank van der Linden ` (4 subsequent siblings) 12 siblings, 0 replies; 17+ messages in thread From: Frank van der Linden @ 2020-06-23 22:39 UTC (permalink / raw) To: bfields, chuck.lever, linux-nfs; +Cc: Frank van der Linden Add the structures used in extended attribute request / response handling. Signed-off-by: Frank van der Linden <fllinden@amazon.com> --- fs/nfsd/xdr4.h | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index db63d39b1507..66499fb6b567 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -224,6 +224,32 @@ struct nfsd4_putfh { bool no_verify; /* represents foreigh fh */ }; +struct nfsd4_getxattr { + char *getxa_name; /* request */ + u32 getxa_len; /* request */ + void *getxa_buf; +}; + +struct nfsd4_setxattr { + u32 setxa_flags; /* request */ + char *setxa_name; /* request */ + char *setxa_buf; /* request */ + u32 setxa_len; /* request */ + struct nfsd4_change_info setxa_cinfo; /* response */ +}; + +struct nfsd4_removexattr { + char *rmxa_name; /* request */ + struct nfsd4_change_info rmxa_cinfo; /* response */ +}; + +struct nfsd4_listxattrs { + u64 lsxa_cookie; /* request */ + u32 lsxa_maxcount; /* request */ + char *lsxa_buf; /* unfiltered buffer (reply) */ + u32 lsxa_len; /* unfiltered len (reply) */ +}; + struct nfsd4_open { u32 op_claim_type; /* request */ struct xdr_netobj op_fname; /* request - everything but CLAIM_PREV */ @@ -649,6 +675,11 @@ struct nfsd4_op { struct nfsd4_offload_status offload_status; struct nfsd4_copy_notify copy_notify; struct nfsd4_seek seek; + + struct nfsd4_getxattr getxattr; + struct nfsd4_setxattr setxattr; + struct nfsd4_listxattrs listxattrs; + struct nfsd4_removexattr removexattr; } u; struct nfs4_replay * replay; }; -- 2.17.2 ^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v3 09/10] nfsd: implement the xattr functions and en/decode logic 2020-06-23 22:39 [PATCH v3 00/10] server side user xattr support (RFC 8276) Frank van der Linden ` (7 preceding siblings ...) 2020-06-23 22:39 ` [PATCH v3 08/10] nfsd: add structure definitions for xattr requests / responses Frank van der Linden @ 2020-06-23 22:39 ` Frank van der Linden 2020-06-23 22:39 ` [PATCH v3 10/10] nfsd: add fattr support for user extended attributes Frank van der Linden ` (3 subsequent siblings) 12 siblings, 0 replies; 17+ messages in thread From: Frank van der Linden @ 2020-06-23 22:39 UTC (permalink / raw) To: bfields, chuck.lever, linux-nfs; +Cc: Frank van der Linden Implement the main entry points for the *XATTR operations. Add functions to calculate the reply size for the user extended attribute operations, and implement the XDR encode / decode logic for these operations. Add the user extended attributes operations to nfsd4_ops. Signed-off-by: Frank van der Linden <fllinden@amazon.com> --- fs/nfsd/nfs4proc.c | 120 ++++++++++++ fs/nfsd/nfs4xdr.c | 450 +++++++++++++++++++++++++++++++++++++++++++ include/linux/nfs4.h | 2 +- 3 files changed, 571 insertions(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 841aad772798..a527da3d8052 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -2097,6 +2097,68 @@ nfsd4_layoutreturn(struct svc_rqst *rqstp, } #endif /* CONFIG_NFSD_PNFS */ +static __be32 +nfsd4_getxattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + union nfsd4_op_u *u) +{ + struct nfsd4_getxattr *getxattr = &u->getxattr; + + return nfsd_getxattr(rqstp, &cstate->current_fh, + getxattr->getxa_name, &getxattr->getxa_buf, + &getxattr->getxa_len); +} + +static __be32 +nfsd4_setxattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + union nfsd4_op_u *u) +{ + struct nfsd4_setxattr *setxattr = &u->setxattr; + __be32 ret; + + if (opens_in_grace(SVC_NET(rqstp))) + return nfserr_grace; + + ret = nfsd_setxattr(rqstp, &cstate->current_fh, setxattr->setxa_name, + setxattr->setxa_buf, setxattr->setxa_len, + setxattr->setxa_flags); + + if (!ret) + set_change_info(&setxattr->setxa_cinfo, &cstate->current_fh); + + return ret; +} + +static __be32 +nfsd4_listxattrs(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + union nfsd4_op_u *u) +{ + /* + * Get the entire list, then copy out only the user attributes + * in the encode function. + */ + return nfsd_listxattr(rqstp, &cstate->current_fh, + &u->listxattrs.lsxa_buf, &u->listxattrs.lsxa_len); +} + +static __be32 +nfsd4_removexattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + union nfsd4_op_u *u) +{ + struct nfsd4_removexattr *removexattr = &u->removexattr; + __be32 ret; + + if (opens_in_grace(SVC_NET(rqstp))) + return nfserr_grace; + + ret = nfsd_removexattr(rqstp, &cstate->current_fh, + removexattr->rmxa_name); + + if (!ret) + set_change_info(&removexattr->rmxa_cinfo, &cstate->current_fh); + + return ret; +} + /* * NULL call. */ @@ -2706,6 +2768,42 @@ static inline u32 nfsd4_seek_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) return (op_encode_hdr_size + 3) * sizeof(__be32); } +static inline u32 nfsd4_getxattr_rsize(struct svc_rqst *rqstp, + struct nfsd4_op *op) +{ + u32 maxcount, rlen; + + maxcount = svc_max_payload(rqstp); + rlen = min_t(u32, XATTR_SIZE_MAX, maxcount); + + return (op_encode_hdr_size + 1 + XDR_QUADLEN(rlen)) * sizeof(__be32); +} + +static inline u32 nfsd4_setxattr_rsize(struct svc_rqst *rqstp, + struct nfsd4_op *op) +{ + return (op_encode_hdr_size + op_encode_change_info_maxsz) + * sizeof(__be32); +} +static inline u32 nfsd4_listxattrs_rsize(struct svc_rqst *rqstp, + struct nfsd4_op *op) +{ + u32 maxcount, rlen; + + maxcount = svc_max_payload(rqstp); + rlen = min(op->u.listxattrs.lsxa_maxcount, maxcount); + + return (op_encode_hdr_size + 4 + XDR_QUADLEN(rlen)) * sizeof(__be32); +} + +static inline u32 nfsd4_removexattr_rsize(struct svc_rqst *rqstp, + struct nfsd4_op *op) +{ + return (op_encode_hdr_size + op_encode_change_info_maxsz) + * sizeof(__be32); +} + + static const struct nfsd4_operation nfsd4_ops[] = { [OP_ACCESS] = { .op_func = nfsd4_access, @@ -3087,6 +3185,28 @@ static const struct nfsd4_operation nfsd4_ops[] = { .op_name = "OP_COPY_NOTIFY", .op_rsize_bop = nfsd4_copy_notify_rsize, }, + [OP_GETXATTR] = { + .op_func = nfsd4_getxattr, + .op_name = "OP_GETXATTR", + .op_rsize_bop = nfsd4_getxattr_rsize, + }, + [OP_SETXATTR] = { + .op_func = nfsd4_setxattr, + .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME, + .op_name = "OP_SETXATTR", + .op_rsize_bop = nfsd4_setxattr_rsize, + }, + [OP_LISTXATTRS] = { + .op_func = nfsd4_listxattrs, + .op_name = "OP_LISTXATTRS", + .op_rsize_bop = nfsd4_listxattrs_rsize, + }, + [OP_REMOVEXATTR] = { + .op_func = nfsd4_removexattr, + .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME, + .op_name = "OP_REMOVEXATTR", + .op_rsize_bop = nfsd4_removexattr_rsize, + }, }; /** diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 48806b493eba..8bacc0ceae19 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -41,6 +41,8 @@ #include <linux/pagemap.h> #include <linux/sunrpc/svcauth_gss.h> #include <linux/sunrpc/addr.h> +#include <linux/xattr.h> +#include <uapi/linux/xattr.h> #include "idmap.h" #include "acl.h" @@ -1877,6 +1879,208 @@ nfsd4_decode_seek(struct nfsd4_compoundargs *argp, struct nfsd4_seek *seek) DECODE_TAIL; } +/* + * XDR data that is more than PAGE_SIZE in size is normally part of a + * read or write. However, the size of extended attributes is limited + * by the maximum request size, and then further limited by the underlying + * filesystem limits. This can exceed PAGE_SIZE (currently, XATTR_SIZE_MAX + * is 64k). Since there is no kvec- or page-based interface to xattrs, + * and we're not dealing with contiguous pages, we need to do some copying. + */ + +/* + * Decode data into buffer. Uses head and pages constructed by + * svcxdr_construct_vector. + */ +static __be32 +nfsd4_vbuf_from_vector(struct nfsd4_compoundargs *argp, struct kvec *head, + struct page **pages, char **bufp, u32 buflen) +{ + char *tmp, *dp; + u32 len; + + if (buflen <= head->iov_len) { + /* + * We're in luck, the head has enough space. Just return + * the head, no need for copying. + */ + *bufp = head->iov_base; + return 0; + } + + tmp = svcxdr_tmpalloc(argp, buflen); + if (tmp == NULL) + return nfserr_jukebox; + + dp = tmp; + memcpy(dp, head->iov_base, head->iov_len); + buflen -= head->iov_len; + dp += head->iov_len; + + while (buflen > 0) { + len = min_t(u32, buflen, PAGE_SIZE); + memcpy(dp, page_address(*pages), len); + + buflen -= len; + dp += len; + pages++; + } + + *bufp = tmp; + return 0; +} + +/* + * Get a user extended attribute name from the XDR buffer. + * It will not have the "user." prefix, so prepend it. + * Lastly, check for nul characters in the name. + */ +static __be32 +nfsd4_decode_xattr_name(struct nfsd4_compoundargs *argp, char **namep) +{ + DECODE_HEAD; + char *name, *sp, *dp; + u32 namelen, cnt; + + READ_BUF(4); + namelen = be32_to_cpup(p++); + + if (namelen > (XATTR_NAME_MAX - XATTR_USER_PREFIX_LEN)) + return nfserr_nametoolong; + + if (namelen == 0) + goto xdr_error; + + READ_BUF(namelen); + + name = svcxdr_tmpalloc(argp, namelen + XATTR_USER_PREFIX_LEN + 1); + if (!name) + return nfserr_jukebox; + + memcpy(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN); + + /* + * Copy the extended attribute name over while checking for 0 + * characters. + */ + sp = (char *)p; + dp = name + XATTR_USER_PREFIX_LEN; + cnt = namelen; + + while (cnt-- > 0) { + if (*sp == '\0') + goto xdr_error; + *dp++ = *sp++; + } + *dp = '\0'; + + *namep = name; + + DECODE_TAIL; +} + +/* + * A GETXATTR op request comes without a length specifier. We just set the + * maximum length for the reply based on XATTR_SIZE_MAX and the maximum + * channel reply size. nfsd_getxattr will probe the length of the xattr, + * check it against getxa_len, and allocate + return the value. + */ +static __be32 +nfsd4_decode_getxattr(struct nfsd4_compoundargs *argp, + struct nfsd4_getxattr *getxattr) +{ + __be32 status; + u32 maxcount; + + status = nfsd4_decode_xattr_name(argp, &getxattr->getxa_name); + if (status) + return status; + + maxcount = svc_max_payload(argp->rqstp); + maxcount = min_t(u32, XATTR_SIZE_MAX, maxcount); + + getxattr->getxa_len = maxcount; + + return status; +} + +static __be32 +nfsd4_decode_setxattr(struct nfsd4_compoundargs *argp, + struct nfsd4_setxattr *setxattr) +{ + DECODE_HEAD; + u32 flags, maxcount, size; + struct kvec head; + struct page **pagelist; + + READ_BUF(4); + flags = be32_to_cpup(p++); + + if (flags > SETXATTR4_REPLACE) + return nfserr_inval; + setxattr->setxa_flags = flags; + + status = nfsd4_decode_xattr_name(argp, &setxattr->setxa_name); + if (status) + return status; + + maxcount = svc_max_payload(argp->rqstp); + maxcount = min_t(u32, XATTR_SIZE_MAX, maxcount); + + READ_BUF(4); + size = be32_to_cpup(p++); + if (size > maxcount) + return nfserr_xattr2big; + + setxattr->setxa_len = size; + if (size > 0) { + status = svcxdr_construct_vector(argp, &head, &pagelist, size); + if (status) + return status; + + status = nfsd4_vbuf_from_vector(argp, &head, pagelist, + &setxattr->setxa_buf, size); + } + + DECODE_TAIL; +} + +static __be32 +nfsd4_decode_listxattrs(struct nfsd4_compoundargs *argp, + struct nfsd4_listxattrs *listxattrs) +{ + DECODE_HEAD; + u32 maxcount; + + READ_BUF(12); + p = xdr_decode_hyper(p, &listxattrs->lsxa_cookie); + + /* + * If the cookie is too large to have even one user.x attribute + * plus trailing '\0' left in a maximum size buffer, it's invalid. + */ + if (listxattrs->lsxa_cookie >= + (XATTR_LIST_MAX / (XATTR_USER_PREFIX_LEN + 2))) + return nfserr_badcookie; + + maxcount = be32_to_cpup(p++); + if (maxcount < 8) + /* Always need at least 2 words (length and one character) */ + return nfserr_inval; + + maxcount = min(maxcount, svc_max_payload(argp->rqstp)); + listxattrs->lsxa_maxcount = maxcount; + + DECODE_TAIL; +} + +static __be32 +nfsd4_decode_removexattr(struct nfsd4_compoundargs *argp, + struct nfsd4_removexattr *removexattr) +{ + return nfsd4_decode_xattr_name(argp, &removexattr->rmxa_name); +} + static __be32 nfsd4_decode_noop(struct nfsd4_compoundargs *argp, void *p) { @@ -1973,6 +2177,11 @@ static const nfsd4_dec nfsd4_dec_ops[] = { [OP_SEEK] = (nfsd4_dec)nfsd4_decode_seek, [OP_WRITE_SAME] = (nfsd4_dec)nfsd4_decode_notsupp, [OP_CLONE] = (nfsd4_dec)nfsd4_decode_clone, + /* RFC 8276 extended atributes operations */ + [OP_GETXATTR] = (nfsd4_dec)nfsd4_decode_getxattr, + [OP_SETXATTR] = (nfsd4_dec)nfsd4_decode_setxattr, + [OP_LISTXATTRS] = (nfsd4_dec)nfsd4_decode_listxattrs, + [OP_REMOVEXATTR] = (nfsd4_dec)nfsd4_decode_removexattr, }; static inline bool @@ -4458,6 +4667,241 @@ nfsd4_encode_noop(struct nfsd4_compoundres *resp, __be32 nfserr, void *p) return nfserr; } +/* + * Encode kmalloc-ed buffer in to XDR stream. + */ +static int +nfsd4_vbuf_to_stream(struct xdr_stream *xdr, char *buf, u32 buflen) +{ + u32 cplen; + __be32 *p; + + cplen = min_t(unsigned long, buflen, + ((void *)xdr->end - (void *)xdr->p)); + p = xdr_reserve_space(xdr, cplen); + if (!p) + return nfserr_resource; + + memcpy(p, buf, cplen); + buf += cplen; + buflen -= cplen; + + while (buflen) { + cplen = min_t(u32, buflen, PAGE_SIZE); + p = xdr_reserve_space(xdr, cplen); + if (!p) + return nfserr_resource; + + memcpy(p, buf, cplen); + + if (cplen < PAGE_SIZE) { + /* + * We're done, with a length that wasn't page + * aligned, so possibly not word aligned. Pad + * any trailing bytes with 0. + */ + xdr_encode_opaque_fixed(p, NULL, cplen); + break; + } + + buflen -= PAGE_SIZE; + buf += PAGE_SIZE; + } + + return 0; +} + +static __be32 +nfsd4_encode_getxattr(struct nfsd4_compoundres *resp, __be32 nfserr, + struct nfsd4_getxattr *getxattr) +{ + struct xdr_stream *xdr = &resp->xdr; + __be32 *p, err; + + p = xdr_reserve_space(xdr, 4); + if (!p) + return nfserr_resource; + + *p = cpu_to_be32(getxattr->getxa_len); + + if (getxattr->getxa_len == 0) + return 0; + + err = nfsd4_vbuf_to_stream(xdr, getxattr->getxa_buf, + getxattr->getxa_len); + + kvfree(getxattr->getxa_buf); + + return err; +} + +static __be32 +nfsd4_encode_setxattr(struct nfsd4_compoundres *resp, __be32 nfserr, + struct nfsd4_setxattr *setxattr) +{ + struct xdr_stream *xdr = &resp->xdr; + __be32 *p; + + p = xdr_reserve_space(xdr, 20); + if (!p) + return nfserr_resource; + + encode_cinfo(p, &setxattr->setxa_cinfo); + + return 0; +} + +/* + * See if there are cookie values that can be rejected outright. + */ +static __be32 +nfsd4_listxattr_validate_cookie(struct nfsd4_listxattrs *listxattrs, + u32 *offsetp) +{ + u64 cookie = listxattrs->lsxa_cookie; + + /* + * If the cookie is larger than the maximum number we can fit + * in either the buffer we just got back from vfs_listxattr, or, + * XDR-encoded, in the return buffer, it's invalid. + */ + if (cookie > (listxattrs->lsxa_len) / (XATTR_USER_PREFIX_LEN + 2)) + return nfserr_badcookie; + + if (cookie > (listxattrs->lsxa_maxcount / + (XDR_QUADLEN(XATTR_USER_PREFIX_LEN + 2) + 4))) + return nfserr_badcookie; + + *offsetp = (u32)cookie; + return 0; +} + +static __be32 +nfsd4_encode_listxattrs(struct nfsd4_compoundres *resp, __be32 nfserr, + struct nfsd4_listxattrs *listxattrs) +{ + struct xdr_stream *xdr = &resp->xdr; + u32 cookie_offset, count_offset, eof; + u32 left, xdrleft, slen, count; + u32 xdrlen, offset; + u64 cookie; + char *sp; + __be32 status; + __be32 *p; + u32 nuser; + + eof = 1; + + status = nfsd4_listxattr_validate_cookie(listxattrs, &offset); + if (status) + goto out; + + /* + * Reserve space for the cookie and the name array count. Record + * the offsets to save them later. + */ + cookie_offset = xdr->buf->len; + count_offset = cookie_offset + 8; + p = xdr_reserve_space(xdr, 12); + if (!p) { + status = nfserr_resource; + goto out; + } + + count = 0; + left = listxattrs->lsxa_len; + sp = listxattrs->lsxa_buf; + nuser = 0; + + xdrleft = listxattrs->lsxa_maxcount; + + while (left > 0 && xdrleft > 0) { + slen = strlen(sp); + + /* + * Check if this a user. attribute, skip it if not. + */ + if (strncmp(sp, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) + goto contloop; + + slen -= XATTR_USER_PREFIX_LEN; + xdrlen = 4 + ((slen + 3) & ~3); + if (xdrlen > xdrleft) { + if (count == 0) { + /* + * Can't even fit the first attribute name. + */ + status = nfserr_toosmall; + goto out; + } + eof = 0; + goto wreof; + } + + left -= XATTR_USER_PREFIX_LEN; + sp += XATTR_USER_PREFIX_LEN; + if (nuser++ < offset) + goto contloop; + + + p = xdr_reserve_space(xdr, xdrlen); + if (!p) { + status = nfserr_resource; + goto out; + } + + p = xdr_encode_opaque(p, sp, slen); + + xdrleft -= xdrlen; + count++; +contloop: + sp += slen + 1; + left -= slen + 1; + } + + /* + * If there were user attributes to copy, but we didn't copy + * any, the offset was too large (e.g. the cookie was invalid). + */ + if (nuser > 0 && count == 0) { + status = nfserr_badcookie; + goto out; + } + +wreof: + p = xdr_reserve_space(xdr, 4); + if (!p) { + status = nfserr_resource; + goto out; + } + *p = cpu_to_be32(eof); + + cookie = offset + count; + + write_bytes_to_xdr_buf(xdr->buf, cookie_offset, &cookie, 8); + count = htonl(count); + write_bytes_to_xdr_buf(xdr->buf, count_offset, &count, 4); +out: + if (listxattrs->lsxa_len) + kvfree(listxattrs->lsxa_buf); + return status; +} + +static __be32 +nfsd4_encode_removexattr(struct nfsd4_compoundres *resp, __be32 nfserr, + struct nfsd4_removexattr *removexattr) +{ + struct xdr_stream *xdr = &resp->xdr; + __be32 *p; + + p = xdr_reserve_space(xdr, 20); + if (!p) + return nfserr_resource; + + p = encode_cinfo(p, &removexattr->rmxa_cinfo); + return 0; +} + typedef __be32(* nfsd4_enc)(struct nfsd4_compoundres *, __be32, void *); /* @@ -4547,6 +4991,12 @@ static const nfsd4_enc nfsd4_enc_ops[] = { [OP_SEEK] = (nfsd4_enc)nfsd4_encode_seek, [OP_WRITE_SAME] = (nfsd4_enc)nfsd4_encode_noop, [OP_CLONE] = (nfsd4_enc)nfsd4_encode_noop, + + /* RFC 8276 extended atributes operations */ + [OP_GETXATTR] = (nfsd4_enc)nfsd4_encode_getxattr, + [OP_SETXATTR] = (nfsd4_enc)nfsd4_encode_setxattr, + [OP_LISTXATTRS] = (nfsd4_enc)nfsd4_encode_listxattrs, + [OP_REMOVEXATTR] = (nfsd4_enc)nfsd4_encode_removexattr, }; /* diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index e6ca9d1d2e76..33ebe476428e 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -165,7 +165,7 @@ Needs to be updated if more operations are defined in future.*/ #define FIRST_NFS4_OP OP_ACCESS #define LAST_NFS40_OP OP_RELEASE_LOCKOWNER #define LAST_NFS41_OP OP_RECLAIM_COMPLETE -#define LAST_NFS42_OP OP_CLONE +#define LAST_NFS42_OP OP_REMOVEXATTR #define LAST_NFS4_OP LAST_NFS42_OP enum nfsstat4 { -- 2.17.2 ^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v3 10/10] nfsd: add fattr support for user extended attributes 2020-06-23 22:39 [PATCH v3 00/10] server side user xattr support (RFC 8276) Frank van der Linden ` (8 preceding siblings ...) 2020-06-23 22:39 ` [PATCH v3 09/10] nfsd: implement the xattr functions and en/decode logic Frank van der Linden @ 2020-06-23 22:39 ` Frank van der Linden 2020-06-25 16:50 ` [PATCH v3 00/10] server side user xattr support (RFC 8276) J. Bruce Fields ` (2 subsequent siblings) 12 siblings, 0 replies; 17+ messages in thread From: Frank van der Linden @ 2020-06-23 22:39 UTC (permalink / raw) To: bfields, chuck.lever, linux-nfs; +Cc: Frank van der Linden Check if user extended attributes are supported for an inode, and return the answer when being queried for file attributes. An exported filesystem can now signal its RFC8276 user extended attributes capability. Signed-off-by: Frank van der Linden <fllinden@amazon.com> --- fs/nfsd/nfs4xdr.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 8bacc0ceae19..259d5ad0e3f4 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3213,6 +3213,15 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, } #endif + if (bmval2 & FATTR4_WORD2_XATTR_SUPPORT) { + p = xdr_reserve_space(xdr, 4); + if (!p) + goto out_resource; + err = xattr_supported_namespace(d_inode(dentry), + XATTR_USER_PREFIX); + *p++ = cpu_to_be32(err == 0); + } + attrlen = htonl(xdr->buf->len - attrlen_offset - 4); write_bytes_to_xdr_buf(xdr->buf, attrlen_offset, &attrlen, 4); status = nfs_ok; -- 2.17.2 ^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH v3 00/10] server side user xattr support (RFC 8276) 2020-06-23 22:39 [PATCH v3 00/10] server side user xattr support (RFC 8276) Frank van der Linden ` (9 preceding siblings ...) 2020-06-23 22:39 ` [PATCH v3 10/10] nfsd: add fattr support for user extended attributes Frank van der Linden @ 2020-06-25 16:50 ` J. Bruce Fields 2020-06-25 17:13 ` Frank van der Linden 2020-06-25 16:53 ` J. Bruce Fields 2020-07-04 14:37 ` Chuck Lever 12 siblings, 1 reply; 17+ messages in thread From: J. Bruce Fields @ 2020-06-25 16:50 UTC (permalink / raw) To: Frank van der Linden; +Cc: chuck.lever, linux-nfs On Tue, Jun 23, 2020 at 10:39:17PM +0000, Frank van der Linden wrote: > v3: > * Rebase to v5.8-rc2 > * Use length probe + allocate + query for the listxattr and setxattr > operations to avoid allocating unneeded space. > * Because of the above, drop the 'use kvmalloc for svcxdr_tmpalloc' patch, > as it's no longer needed. > > v2: > * As per the discussion, user extended attributes are enabled if > the client and server support them (e.g. they support 4.2 and > advertise the user extended attribute FATTR). There are no longer > options to switch them off. > * The code is no longer conditioned on a config option. > * The number of patches has been reduced somewhat by merging > smaller, related ones. > * Renamed some functions and added parameter comments as requested. > > v1: > > * Split in to client and server (changed from the original RFC patch). > > Original RFC combined set is here: > > https://www.spinics.net/lists/linux-nfs/msg74843.html > > In general, these patches were, both server and client, tested as > follows: > * stress-ng-xattr with 1000 workers > * Test all corner cases (XATTR_SIZE_*) > * Test all failure cases (no xattr, setxattr with different or > invalid flags, etc). > * Verify the content of xattrs across several operations. Do you have some code to share for these tests? --b. > * Interop run against FreeBSD server/client implementation. > * Ran xfstests-dev, with no unexpected/new failures as compared > to an unpatched kernel. To fully use xfstests-dev, it needed > some modifications, as it expects to either use all xattr > namespaces, or none. Whereas NFS only suppors the "user." > namespace (+ optional ACLs). I will send the changes in > seperately. > > > Frank van der Linden (10): > xattr: break delegations in {set,remove}xattr > xattr: add a function to check if a namespace is supported > nfs,nfsd: NFSv4.2 extended attribute protocol definitions > nfsd: split off the write decode code in to a separate function > nfsd: add defines for NFSv4.2 extended attribute support > nfsd: define xattr functions to call in to their vfs counterparts > nfsd: take xattr bits in to account for permission checks > nfsd: add structure definitions for xattr requests / responses > nfsd: implement the xattr functions and en/decode logic > nfsd: add fattr support for user extended attributes > > fs/nfsd/nfs4proc.c | 128 ++++++++- > fs/nfsd/nfs4xdr.c | 531 +++++++++++++++++++++++++++++++++++--- > fs/nfsd/nfsd.h | 5 +- > fs/nfsd/vfs.c | 239 +++++++++++++++++ > fs/nfsd/vfs.h | 10 + > fs/nfsd/xdr4.h | 31 +++ > fs/xattr.c | 111 +++++++- > include/linux/nfs4.h | 22 +- > include/linux/xattr.h | 4 + > include/uapi/linux/nfs4.h | 3 + > 10 files changed, 1044 insertions(+), 40 deletions(-) > > -- > 2.17.2 ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v3 00/10] server side user xattr support (RFC 8276) 2020-06-25 16:50 ` [PATCH v3 00/10] server side user xattr support (RFC 8276) J. Bruce Fields @ 2020-06-25 17:13 ` Frank van der Linden 0 siblings, 0 replies; 17+ messages in thread From: Frank van der Linden @ 2020-06-25 17:13 UTC (permalink / raw) To: J. Bruce Fields; +Cc: chuck.lever, linux-nfs [-- Attachment #1: Type: text/plain, Size: 536 bytes --] On Thu, Jun 25, 2020 at 12:50:38PM -0400, J. Bruce Fields wrote: > > In general, these patches were, both server and client, tested as > > follows: > > * stress-ng-xattr with 1000 workers > > * Test all corner cases (XATTR_SIZE_*) > > * Test all failure cases (no xattr, setxattr with different or > > invalid flags, etc). > > * Verify the content of xattrs across several operations. > > Do you have some code to share for these tests? > > --b. Sure, my main piece of test code is attached. - Frank [-- Attachment #2: xattr.c --] [-- Type: text/plain, Size: 22154 bytes --] #define _GNU_SOURCE #include <sys/types.h> #include <sys/stat.h> #include <sys/xattr.h> #include <stdio.h> #include <stdlib.h> #include <malloc.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <string.h> #include <time.h> #include <stdarg.h> #include <limits.h> #ifndef XATTR_SIZE_MAX #define XATTR_SIZE_MAX 65536 #endif #ifndef XATTR_LIST_MAX #define XATR_LIST_MAX 65536 #endif #define XATTR_TEST_ATTRLEN (5 + 4 + 1) /* "user.NNNN\0" */ #define XATTR_TEST_NATTR_MAX (XATTR_LIST_MAX / XATTR_TEST_ATTRLEN) static const char *xt_dir; typedef struct xattr_test_handle { const char *xt_test; char xt_filename[256]; char xt_attrkey[2 * 256]; /* Long to test limit */ char *xt_attrbuf; ssize_t xt_attrlen; char xt_fillc; ssize_t xt_failoff; int xt_fd; char *xt_listbuf; ssize_t xt_listlen; } xt_hdl; #define xt_value_len(xth) ((xth)->xt_attrlen) #define xt_value_failoff(xth) ((xth)->xt_failoff) #define xt_fillc(xth) ((xth)->xt_fillc) #define xt_filename(xth) ((xth)->xt_filename) #define PAGE_SIZE sysconf(_SC_PAGE_SIZE) static void usage(void) { fprintf(stderr, "usage: xattr <dir>\n"); exit(1); } static void fail(xt_hdl *xth, const char *fmt, ...) { va_list ap; printf("%-24s FAIL: ", xth->xt_test); va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); printf("\n"); } static void pass(xt_hdl *xth, const char *fmt, ...) { va_list ap; printf("%-24s PASS: ", xth->xt_test); va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); printf("\n"); } static int xt_set_fs(const char *dir) { int ret; struct stat st; ret = stat(dir, &st); if (ret < 0) return ret; if (!S_ISDIR(st.st_mode)) return -ENOTDIR; xt_dir = dir; return 0; } static xt_hdl * xt_init(const char *test) { xt_hdl *xth; if (xt_dir == NULL) { errno = EINVAL; return NULL; } xth = calloc(1, sizeof (xt_hdl)); if (xth == NULL) return NULL; xth->xt_test = test; snprintf(xth->xt_filename, sizeof xth->xt_filename, "%s/%sXXXXXX", xt_dir, test); /* * Default value, can be changed. */ snprintf(xth->xt_attrkey, sizeof xth->xt_attrkey, "user.%s", test); return xth; } static int xt_file_create(xt_hdl *xth) { int fd; int ret; fd = mkostemp(xth->xt_filename, O_TRUNC); if (fd < 0) return -errno; close(fd); return 0; } static void xt_file_remove(xt_hdl *xth) { unlink(xth->xt_filename); } static int xt_file_open(xt_hdl *xth, int flags) { int fd; fd = open(xth->xt_filename, flags); if (fd < 0) return errno; xth->xt_fd = fd; return fd; } static int xt_file_close(xt_hdl *xth) { if (xth->xt_fd != -1) { close(xth->xt_fd); xth->xt_fd = -1; } } static void xt_value_fill(xt_hdl *xth) { char c; char *p; ssize_t i; if (xth->xt_attrlen == 0) return; p = xth->xt_attrbuf; c = random() & 0xff; if (c == 0) c++; for (i = 0; i < xth->xt_attrlen; i++) p[i] = c; xth->xt_fillc = c; } static void xt_value_free(xt_hdl *xth) { if (xth->xt_attrbuf != NULL) { free(xth->xt_attrbuf); xth->xt_attrbuf = NULL; xth->xt_attrlen = 0; } } static int xt_value_alloc(xt_hdl *xth, ssize_t len) { char *p; xt_value_free(xth); if (len == 0) return 0; p = malloc(len); if (p == NULL) return ENOMEM; xth->xt_attrbuf = p; xth->xt_attrlen = len; xth->xt_failoff = 0; xth->xt_fd = -1; xt_value_fill(xth); return 0; } static int __xt_value_check(xt_hdl *xth, ssize_t len, char c) { ssize_t i; for (i = 0; i < len; i++) { if (xth->xt_attrbuf[i] != c) { xth->xt_failoff = i; return -EINVAL; } } return 0; } static int xt_value_check(xt_hdl *xth, ssize_t len) { return __xt_value_check(xth, len, xth->xt_fillc); } static int xt_list_alloc(xt_hdl *xth, ssize_t size) { char *p; p = calloc(1, size); if (p == NULL) return -ENOMEM; xth->xt_listbuf = p; xth->xt_listlen = size; return 0; } static void xt_value_clear(xt_hdl *xth) { memset(xth->xt_attrbuf, 0, xth->xt_attrlen); } static void xt_list_free(xt_hdl *xth) { if (xth->xt_attrbuf != NULL) { free(xth->xt_listbuf); xth->xt_listbuf = NULL; xth->xt_listlen = 0; } } static void xt_free(xt_hdl *xth) { xt_value_free(xth); xt_list_free(xth); free(xth); } static int xt_set_attr_name(xt_hdl *xth, const char *name) { if (strlen(name) > (sizeof xth->xt_attrkey) - 1) return -EINVAL; strcpy(xth->xt_attrkey, name); return 0; } static int xt_getxattr(xt_hdl *xth) { ssize_t ret; ret = getxattr(xth->xt_filename, xth->xt_attrkey, xth->xt_attrbuf, xth->xt_attrlen); return ret < 0 ? -errno : ret; } static int xt_fgetxattr(xt_hdl *xth) { ssize_t ret; ret = fgetxattr(xth->xt_fd, xth->xt_attrkey, xth->xt_attrbuf, xth->xt_attrlen); return ret < 0 ? -errno : ret; } static int xt_setxattr(xt_hdl *xth, int flags) { int ret; ret = setxattr(xth->xt_filename, xth->xt_attrkey, xth->xt_attrbuf, xth->xt_attrlen, flags); return ret < 0 ? -errno : 0; } static int xt_fsetxattr(xt_hdl *xth, int flags) { int ret; ret = fsetxattr(xth->xt_fd, xth->xt_attrkey, xth->xt_attrbuf, xth->xt_attrlen, flags); return ret < 0 ? -errno : 0; } static int xt_removexattr(xt_hdl *xth) { int ret; ret = removexattr(xth->xt_filename, xth->xt_attrkey); return ret < 0 ? -errno : 0; } static int xt_fremovexattr(xt_hdl *xth) { int ret; ret = fremovexattr(xth->xt_fd, xth->xt_attrkey); return ret < 0 ? -errno : 0; } static int cmpstr(const void *p1, const void *p2) { char *s1, *s2; s1 = *(char * const *) p1; s2 = *(char * const *) p2; if (s1 == s2) return 0; if (s1 == NULL) return 1; if (s2 == NULL) return -1; return strcmp(s1, s2); } static void xattrs_sort(char **list, ssize_t count) { qsort(list, count, sizeof (char *), cmpstr); } static int xattrs_alloc(char ***listp, ssize_t count, ssize_t *lenp) { ssize_t i, n, len, j; size_t slen; char **list; n = count; len = 0; #ifdef LIST_MAX_CHECK if (n > (XATTR_LIST_MAX / 6)) return -EINVAL; #endif list = calloc(n, sizeof (char *)); if (list == NULL) return -ENOMEM; for (i = 0; i < n; i++) { #ifdef LIST_MAX_CHECK if ((len + 10) > XATTR_LIST_MAX) break; #endif len += 10; if (asprintf(&list[i], "user.%04d", (int)i) < 0) break; } if (i < n) { for (j = 0; j < i; j++) { free(list[j]); } free(list); return -ENOMEM; } if (lenp) *lenp = len; *listp = list; return 0; } static int xattrs_free(char **list, ssize_t count) { ssize_t i; for (i = 0; i < count; i++) { if (list[i] != NULL) free(list[i]); } free(list); } static int xattrs_buf2list(char *buf, ssize_t buflen, char ***listp, ssize_t *countp) { ssize_t slen, count, len, i; char *p; char **list; p = buf; len = buflen; count = 0; while (len > 0) { slen = strlen(p) + 1; if (!strncmp(p, "user.", 5)) count++; p += slen; len -= slen; } if (count == 0) { list = NULL; goto out; } p = buf; len = buflen; list = calloc(count, sizeof (char *)); if (list == NULL) return -ENOMEM; i = 0; while (len > 0) { slen = strlen(p) + 1; if (!strncmp(p, "user.", 5)) list[i++] = strdup(p); p += slen; len -= slen; } xattrs_sort(list, count); out: *listp = list; *countp = count; return 0; } static int xattrs_file2list(const char *filename, char ***listp, ssize_t *countp) { ssize_t len, ret; int error; char *buf; len = listxattr(filename, NULL, 0); if (len < 0) return -errno; buf = malloc(len); if (buf == NULL) return -ENOMEM; ret = listxattr(filename, buf, len); if (ret < 0) { error = errno; *listp = NULL; free(buf); return -error; } error = xattrs_buf2list(buf, ret, listp, countp); free(buf); return error; } /* * Compare two string arrays that may have NULL entries. Counts are * the number of entries that include possible NULL entries. */ static int xattrs_cmplists(char **list1, ssize_t count1, char **list2, ssize_t count2) { ssize_t n1, n2; for (n1 = n2 = 0; n1 < count1 && n2 < count2;) { while (n1 < count1 && list1[n1] == NULL) n1++; while (n2 < count2 && list2[n2] == NULL) n2++; if (n1 >= count1) { if (n2 >= count2) return 0; return -1; } if (n2 >= count2) { if (n1 >= count1) return 0; return -1; } if (strcmp(list1[n1++], list2[n2++])) return -1; } return 0; } static int xattrs_listset(const char *filename, char **list, ssize_t len) { ssize_t i; int ret; for (i = 0; i < len; i++) { if (list[i] == NULL) continue; ret = setxattr(filename, list[i], NULL, 0, 0); if (ret < 0) { ret = -errno; fprintf(stderr, "%s: failed at %d (%s)\n", __func__, i, strerror(ret)); return ret; } } return 0; } static int xattrs_listrm(const char *filename, char **list, ssize_t len) { ssize_t i; int ret; for (i = 0; i < len; i++) { if (list[i] == NULL) continue; ret = removexattr(filename, list[i]); if (ret < 0) return -errno; } return 0; } static void __test_xattr_len(xt_hdl *xth, ssize_t len) { int ret; ssize_t xlen; ret = xt_file_create(xth); if (ret < 0) { fail(xth, "file create errno %d (%s)", errno, strerror(errno)); return; } ret = xt_value_alloc(xth, len); if (ret < 0) { fail(xth, "value alloc errno %d (%s)", errno, strerror(errno)); goto cleanup; } ret = xt_setxattr(xth, 0); if (ret < 0) { fail(xth, "setxattr errno %d (%s)", errno, strerror(errno)); goto cleanup; } xt_value_clear(xth); xlen = xt_getxattr(xth); if (xlen < 0) { fail(xth, "getxattr errno %d (%s)", errno, strerror(errno)); goto cleanup; } if (xlen != xt_value_len(xth)) { fail(xth, "getxattr length mismatch (expected %lld got %lld)", (long long)xt_value_len(xth), (long long)xlen); goto cleanup; } ret = xt_value_check(xth, len); if (ret < 0) { fail(xth, "value check failed at offset %lld", xt_value_failoff(xth)); goto cleanup; } pass(xth, "success setting / getting %lld length xattr", (long long)len); cleanup: xt_file_remove(xth); } void test_xattr_probe() { int ret; xt_hdl *xth; ssize_t xlen; char c; xth = xt_init(__func__); if (xth == NULL) { printf("%-24s FAIL: can't initialize handle", __func__); return; } ret = xt_file_create(xth); if (ret < 0) { fail(xth, "file create errno %d (%s)", errno, strerror(errno)); return; } ret = xt_value_alloc(xth, 37); if (ret < 0) { fail(xth, "value alloc failure"); goto cleanup; } c = xt_fillc(xth); ret = xt_setxattr(xth, 0); if (ret < 0) { fail(xth, "setxattr errno %d (%s)", errno, strerror(errno)); goto cleanup; } ret = xt_value_alloc(xth, 0); if (ret < 0) { fail(xth, "value reset failure"); goto cleanup; } xlen = xt_getxattr(xth); if (xlen < 0) { fail(xth, "getxattr errno %d (%s)", errno, strerror(errno)); goto cleanup; } if (xlen != 37) { fail(xth, "getxattr length mismatch (expected 37, got %lld)", (long long)xlen); goto cleanup; } ret = xt_value_alloc(xth, 37); if (ret < 0) { fail(xth, "value realloc failure"); goto cleanup; } xlen = xt_getxattr(xth); if (xlen < 0) { fail(xth, "getxattr errno %d (%s)", errno, strerror(errno)); goto cleanup; } if (__xt_value_check(xth, 37, c) < 0) { fail(xth, "value check failed at offset %lld", xt_value_failoff(xth)); goto cleanup; } pass(xth, "getxattr length probe works correctly"); cleanup: xt_file_remove(xth); xt_free(xth); } void test_xattr_0() { int ret; xt_hdl *xth; xth = xt_init(__func__); if (xth == NULL) { printf("%-24s FAIL: can't initialize handle", __func__); return; } __test_xattr_len(xth, 0); xt_free(xth); } void test_xattr_1() { xt_hdl *xth; xth = xt_init(__func__); if (xth == NULL) { printf("%-24s FAIL: can't initialize handle", __func__); return; } __test_xattr_len(xth, 1); xt_free(xth); } void test_xattr_256() { xt_hdl *xth; xth = xt_init(__func__); if (xth == NULL) { printf("%-24s FAIL: can't initialize handle", __func__); return; } __test_xattr_len(xth, 256); xt_free(xth); } void test_xattr_1page() { xt_hdl *xth; xth = xt_init(__func__); if (xth == NULL) { printf("%-24s FAIL: can't initialize handle", __func__); return; } __test_xattr_len(xth, PAGE_SIZE); xt_free(xth); } void test_xattr_2pages() { xt_hdl *xth; xth = xt_init(__func__); if (xth == NULL) { printf("%-24s FAIL: can't initialize handle", __func__); return; } __test_xattr_len(xth, 2 * PAGE_SIZE); xt_free(xth); } void test_xattr_max() { xt_hdl *xth; xth = xt_init(__func__); if (xth == NULL) { printf("%-24s FAIL: can't initialize handle", __func__); return; } __test_xattr_len(xth, 65536); xt_free(xth); } void test_xattr_toolarge() { xt_hdl *xth; ssize_t ret; xth = xt_init(__func__); if (xth == NULL) { printf("%-24s FAIL: can't initialize handle", __func__); return; } ret = xt_file_create(xth); if (ret < 0) { fail(xth, "file create errno %d (%s)", errno, strerror(errno)); return; } ret = xt_value_alloc(xth, XATTR_SIZE_MAX + 1); if (ret < 0) { fail(xth, "value alloc errno %d (%s)", errno, strerror(errno)); goto cleanup; } ret = xt_setxattr(xth, 0); if (ret != -E2BIG) { fail(xth, "expected %d got %d (%s)", E2BIG, -ret, ret == 0 ? "no error" : strerror(-ret)); goto cleanup; } pass(xth, "setxattr beyond max length fails as expected"); cleanup: xt_file_remove(xth); xt_free(xth); } void test_setxattr_create() { xt_hdl *xth; int ret; ssize_t xlen; xth = xt_init(__func__); if (xth == NULL) { printf("%-24s FAIL: can't initialize handle", __func__); return; } ret = xt_file_create(xth); if (ret < 0) { fail(xth, "file create errno %d (%s)", errno, strerror(errno)); return; } ret = xt_value_alloc(xth, 16); if (ret < 0) { fail(xth, "value alloc errno %d (%s)", errno, strerror(errno)); goto cleanup; } /* * XATTR_CREATE for a non-existing xattr ==> OK */ ret = xt_setxattr(xth, XATTR_CREATE); if (ret < 0) { fail(xth, "setxattr errno %d (%s)", errno, strerror(errno)); goto cleanup; } /* * XATTR_CREATE for an existing xattr ==> EEXIST */ ret = xt_setxattr(xth, XATTR_CREATE); if (ret != -EEXIST) { fail(xth, "expected %d got %d (%s)", EEXIST, -ret, ret == 0 ? "no error" : strerror(-ret)); goto cleanup; } /* * Verify value (xattr should still exist). */ xt_value_clear(xth); xlen = xt_getxattr(xth); if (xlen < 0) { fail(xth, "getxattr errno %d (%s)", errno, strerror(errno)); goto cleanup; } if (xlen != xt_value_len(xth)) { fail(xth, "getxattr length mismatch (expected %lld got %lld)", (long long)xt_value_len(xth), (long long)xlen); goto cleanup; } ret = xt_value_check(xth, 16); if (ret < 0) { fail(xth, "value check failed at offset %lld", xt_value_failoff(xth)); goto cleanup; } pass(xth, "setxattr with XATTR_CREATE behaves correctly"); cleanup: xt_file_remove(xth); xt_free(xth); } void test_setxattr_replace() { xt_hdl *xth; int ret; ssize_t xlen; xth = xt_init(__func__); if (xth == NULL) { printf("%-24s FAIL: can't initialize handle", __func__); return; } ret = xt_file_create(xth); if (ret < 0) { fail(xth, "file create errno %d (%s)", errno, strerror(errno)); return; } ret = xt_value_alloc(xth, 16); if (ret < 0) { fail(xth, "value alloc errno %d (%s)", errno, strerror(errno)); goto cleanup; } /* * XATTR_REPLACE for a non-existing xattr ==> ENODATA */ ret = xt_setxattr(xth, XATTR_REPLACE); if (ret != -ENODATA) { fail(xth, "expected %d got %d (%s)", ENODATA, -ret, ret == 0 ? "no error" : strerror(-ret)); goto cleanup; } /* * Create it, try to replace it afterwards. */ ret = xt_setxattr(xth, 0); if (ret < 0) { fail(xth, "setxattr errno %d (%s)", errno, strerror(errno)); goto cleanup; } xt_value_fill(xth); /* * XATTR_REPLACE should work. */ ret = xt_setxattr(xth, XATTR_REPLACE); if (ret < 0) { fail(xth, "setxattr errno %d (%s)", errno, strerror(errno)); goto cleanup; } /* * Verify value (xattr should still exist). */ xt_value_clear(xth); xlen = xt_getxattr(xth); if (xlen < 0) { fail(xth, "getxattr errno %d (%s)", errno, strerror(errno)); goto cleanup; } if (xlen != xt_value_len(xth)) { fail(xth, "getxattr length mismatch (expected %lld got %lld)", (long long)xt_value_len(xth), (long long)xlen); goto cleanup; } ret = xt_value_check(xth, 16); if (ret < 0) { fail(xth, "value check failed at offset %lld", xt_value_failoff(xth)); goto cleanup; } pass(xth, "setxattr with XATTR_REPLACE behaves correctly"); cleanup: xt_file_remove(xth); xt_free(xth); } void test_setxattr_badflag() { xt_hdl *xth; int ret; ssize_t xlen; xth = xt_init(__func__); if (xth == NULL) { printf("%-24s FAIL: can't initialize handle", __func__); return; } ret = xt_file_create(xth); if (ret < 0) { fail(xth, "file create errno %d (%s)", errno, strerror(errno)); return; } ret = xt_value_alloc(xth, 16); if (ret < 0) { fail(xth, "value alloc errno %d (%s)", errno, strerror(errno)); goto cleanup; } /* * XATTR_REPLACE for a non-existing xattr ==> ENODATA */ ret = xt_setxattr(xth, XATTR_REPLACE); if (ret != -ENODATA) { fail(xth, "expected %d got %d (%s)", ENODATA, -ret, ret == 0 ? "no error" : strerror(-ret)); goto cleanup; } ret = xt_setxattr(xth, -1); if (ret != -EINVAL) { fail(xth, "setxattr errno %d (%s)", errno, strerror(errno)); goto cleanup; } pass(xth, "setxattr with a bad flag behaves correctly"); cleanup: xt_file_remove(xth); xt_free(xth); } void test_removexattr() { xt_hdl *xth; int ret; ssize_t xlen; xth = xt_init(__func__); if (xth == NULL) { printf("%-24s FAIL: can't initialize handle", __func__); return; } ret = xt_file_create(xth); if (ret < 0) { fail(xth, "file create errno %d (%s)", errno, strerror(errno)); return; } ret = xt_value_alloc(xth, 16); if (ret < 0) { fail(xth, "value alloc errno %d (%s)", errno, strerror(errno)); goto cleanup; } ret = xt_removexattr(xth); if (ret != -ENODATA) { fail(xth, "expected %d got %d (%s)", ENODATA, -ret, ret == 0 ? "no error" : strerror(-ret)); goto cleanup; } /* * Create it, try to remove it afterwards. */ ret = xt_setxattr(xth, 0); if (ret < 0) { fail(xth, "setxattr errno %d (%s)", errno, strerror(errno)); goto cleanup; } ret = xt_removexattr(xth); if (ret < 0) { fail(xth, "removexattr errno %d (%s)", errno, strerror(errno)); goto cleanup; } /* * See if it's actually gone. */ xlen = xt_getxattr(xth); if (xlen != -ENODATA) { fail(xth, "expected %d got %d (%s)", ENODATA, -xlen, xlen == 0 ? "no error" : strerror(xlen)); goto cleanup; } pass(xth, "removexattr behaves correctly"); cleanup: xt_file_remove(xth); xt_free(xth); } void __test_listxattr(xt_hdl *xth, ssize_t nattr) { ssize_t len, alen; char **list1, **list2; int ret; list1 = list2 = NULL; ret = xattrs_alloc(&list1, nattr, &alen); if (ret < 0) { fail(xth, "failed to allocate xattr names"); return; } ret = xattrs_listset(xt_filename(xth), list1, nattr); if (ret < 0) { fail(xth, "failed to set xattrs"); goto out; } ret = xattrs_file2list(xt_filename(xth), &list2, &len); if (ret < 0) { if (alen > XATTR_SIZE_MAX && ret == -E2BIG) { /* * Expected failure. */ goto rm; } fail(xth, "failed to get xattrs"); goto out; } if (xattrs_cmplists(list1, nattr, list2, len)) { ret = -EINVAL; /* XXX */ fail(xth, "list comparison failed"); goto out; } rm: ret = xattrs_listrm(xt_filename(xth), list1, nattr); if (ret < 0) { fail(xth, "failed to remove xattrs"); goto out; } pass(xth, "expected results listing and removing %lld xattrs", (long long)nattr); out: if (list2 != NULL) xattrs_free(list2, len); if (list1 != NULL) xattrs_free(list1, nattr); } void test_listxattr_1() { xt_hdl *xth; int ret; char **list1, **list2; ssize_t len; xth = xt_init(__func__); if (xth == NULL) { printf("%-24s FAIL: can't initialize handle", __func__); return; } ret = xt_file_create(xth); if (ret < 0) { fail(xth, "file create errno %d (%s)", errno, strerror(errno)); return; } __test_listxattr(xth, 1); xt_file_remove(xth); xt_free(xth); } void test_listxattr_256() { xt_hdl *xth; int ret; char **list1, **list2; ssize_t len; xth = xt_init(__func__); if (xth == NULL) { printf("%-24s FAIL: can't initialize handle", __func__); return; } ret = xt_file_create(xth); if (ret < 0) { fail(xth, "file create errno %d (%s)", errno, strerror(errno)); return; } __test_listxattr(xth, 256); xt_file_remove(xth); xt_free(xth); } void test_listxattr_large() { xt_hdl *xth; int ret; char **list1, **list2; ssize_t len; xth = xt_init(__func__); if (xth == NULL) { printf("%-24s FAIL: can't initialize handle", __func__); return; } ret = xt_file_create(xth); if (ret < 0) { fail(xth, "file create errno %d (%s)", errno, strerror(errno)); return; } __test_listxattr(xth, XATTR_TEST_NATTR_MAX - 2); xt_file_remove(xth); xt_free(xth); } void test_listxattr_2big() { xt_hdl *xth; int ret; char **list1, **list2; ssize_t len; xth = xt_init(__func__); if (xth == NULL) { printf("%-24s FAIL: can't initialize handle", __func__); return; } ret = xt_file_create(xth); if (ret < 0) { fail(xth, "file create errno %d (%s)", errno, strerror(errno)); return; } __test_listxattr(xth, XATTR_TEST_NATTR_MAX + 1); xt_file_remove(xth); xt_free(xth); } int main(int argc, char **argv) { struct stat st; int fd, ret; if (argc < 2) usage(); ret = xt_set_fs(argv[1]); if (ret != 0) { fprintf(stderr, "xattr: set fs: %s\n", strerror(ret)); exit(1); } srandom(time(NULL)); test_xattr_probe(); test_xattr_0(); test_xattr_1(); test_xattr_256(); test_xattr_1page(); test_xattr_2pages(); test_xattr_max(); test_xattr_toolarge(); test_setxattr_create(); test_setxattr_replace(); test_setxattr_badflag(); test_removexattr(); test_listxattr_1(); test_listxattr_256(); test_listxattr_large(); test_listxattr_2big(); return 0; } ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v3 00/10] server side user xattr support (RFC 8276) 2020-06-23 22:39 [PATCH v3 00/10] server side user xattr support (RFC 8276) Frank van der Linden ` (10 preceding siblings ...) 2020-06-25 16:50 ` [PATCH v3 00/10] server side user xattr support (RFC 8276) J. Bruce Fields @ 2020-06-25 16:53 ` J. Bruce Fields 2020-06-25 17:39 ` Frank van der Linden 2020-07-04 14:37 ` Chuck Lever 12 siblings, 1 reply; 17+ messages in thread From: J. Bruce Fields @ 2020-06-25 16:53 UTC (permalink / raw) To: Frank van der Linden; +Cc: chuck.lever, linux-nfs By the way, I can't remember if I asked this before: is there a particular use case that motivates this xattr work? --b. On Tue, Jun 23, 2020 at 10:39:17PM +0000, Frank van der Linden wrote: > v3: > * Rebase to v5.8-rc2 > * Use length probe + allocate + query for the listxattr and setxattr > operations to avoid allocating unneeded space. > * Because of the above, drop the 'use kvmalloc for svcxdr_tmpalloc' patch, > as it's no longer needed. > > v2: > * As per the discussion, user extended attributes are enabled if > the client and server support them (e.g. they support 4.2 and > advertise the user extended attribute FATTR). There are no longer > options to switch them off. > * The code is no longer conditioned on a config option. > * The number of patches has been reduced somewhat by merging > smaller, related ones. > * Renamed some functions and added parameter comments as requested. > > v1: > > * Split in to client and server (changed from the original RFC patch). > > Original RFC combined set is here: > > https://www.spinics.net/lists/linux-nfs/msg74843.html > > In general, these patches were, both server and client, tested as > follows: > * stress-ng-xattr with 1000 workers > * Test all corner cases (XATTR_SIZE_*) > * Test all failure cases (no xattr, setxattr with different or > invalid flags, etc). > * Verify the content of xattrs across several operations. > * Use KASAN and KMEMLEAK for a longer mix of testruns to verify > that there were no leaks (after unmounting the filesystem). > * Interop run against FreeBSD server/client implementation. > * Ran xfstests-dev, with no unexpected/new failures as compared > to an unpatched kernel. To fully use xfstests-dev, it needed > some modifications, as it expects to either use all xattr > namespaces, or none. Whereas NFS only suppors the "user." > namespace (+ optional ACLs). I will send the changes in > seperately. > > > Frank van der Linden (10): > xattr: break delegations in {set,remove}xattr > xattr: add a function to check if a namespace is supported > nfs,nfsd: NFSv4.2 extended attribute protocol definitions > nfsd: split off the write decode code in to a separate function > nfsd: add defines for NFSv4.2 extended attribute support > nfsd: define xattr functions to call in to their vfs counterparts > nfsd: take xattr bits in to account for permission checks > nfsd: add structure definitions for xattr requests / responses > nfsd: implement the xattr functions and en/decode logic > nfsd: add fattr support for user extended attributes > > fs/nfsd/nfs4proc.c | 128 ++++++++- > fs/nfsd/nfs4xdr.c | 531 +++++++++++++++++++++++++++++++++++--- > fs/nfsd/nfsd.h | 5 +- > fs/nfsd/vfs.c | 239 +++++++++++++++++ > fs/nfsd/vfs.h | 10 + > fs/nfsd/xdr4.h | 31 +++ > fs/xattr.c | 111 +++++++- > include/linux/nfs4.h | 22 +- > include/linux/xattr.h | 4 + > include/uapi/linux/nfs4.h | 3 + > 10 files changed, 1044 insertions(+), 40 deletions(-) > > -- > 2.17.2 ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v3 00/10] server side user xattr support (RFC 8276) 2020-06-25 16:53 ` J. Bruce Fields @ 2020-06-25 17:39 ` Frank van der Linden 2020-06-25 20:07 ` J. Bruce Fields 0 siblings, 1 reply; 17+ messages in thread From: Frank van der Linden @ 2020-06-25 17:39 UTC (permalink / raw) To: J. Bruce Fields; +Cc: chuck.lever, linux-nfs On Thu, Jun 25, 2020 at 12:53:47PM -0400, J. Bruce Fields wrote: > CAUTION: This email originated from outside of the organization. Do not click links or open attachments unless you can confirm the sender and know the content is safe. > > > > By the way, I can't remember if I asked this before: is there a > particular use case that motivates this xattr work? > > --b. There's one use case that I can't really talk about publicly at this point (and it's not my code either, so I wouldn't have all the details). Nothing super secret or anything - it's just something that is not mine, so I won't try to speak for anyone. We wanted to get this upstreamed first, as that's the right thing to do. Since I posted my first RFC, I did get contacted off-list by several readers of linux-nfs who wanted to use the feature in practice, too, so there's definitely interest out there. - Frank ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v3 00/10] server side user xattr support (RFC 8276) 2020-06-25 17:39 ` Frank van der Linden @ 2020-06-25 20:07 ` J. Bruce Fields 0 siblings, 0 replies; 17+ messages in thread From: J. Bruce Fields @ 2020-06-25 20:07 UTC (permalink / raw) To: Frank van der Linden; +Cc: chuck.lever, linux-nfs On Thu, Jun 25, 2020 at 05:39:16PM +0000, Frank van der Linden wrote: > On Thu, Jun 25, 2020 at 12:53:47PM -0400, J. Bruce Fields wrote: > > CAUTION: This email originated from outside of the organization. Do not click links or open attachments unless you can confirm the sender and know the content is safe. > > > > By the way, I can't remember if I asked this before: is there a > > particular use case that motivates this xattr work? > > There's one use case that I can't really talk about publicly at this point > (and it's not my code either, so I wouldn't have all the details). Nothing > super secret or anything - it's just something that is not mine, > so I won't try to speak for anyone. We wanted to get this upstreamed first, > as that's the right thing to do. > > Since I posted my first RFC, I did get contacted off-list by several > readers of linux-nfs who wanted to use the feature in practice, too, so > there's definitely interest out there. Yeah, I always hear a lot of interest but then have trouble sorting through it for the cases that are actually *user* xattr cases, where the server has to just act as a dumb store of the values. There are some. But unfortunately xattrs are best known for enabling selinux and posix acls, and to a lesser extent accessing random other filesystem features, so that tends to be what comes to people's minds first, though it's not what we're doing. --b. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v3 00/10] server side user xattr support (RFC 8276) 2020-06-23 22:39 [PATCH v3 00/10] server side user xattr support (RFC 8276) Frank van der Linden ` (11 preceding siblings ...) 2020-06-25 16:53 ` J. Bruce Fields @ 2020-07-04 14:37 ` Chuck Lever 12 siblings, 0 replies; 17+ messages in thread From: Chuck Lever @ 2020-07-04 14:37 UTC (permalink / raw) To: Frank van der Linden, Al Viro Cc: Bruce Fields, Linux NFS Mailing List, linux-fsdevel > On Jun 23, 2020, at 6:39 PM, Frank van der Linden <fllinden@amazon.com> wrote: > > v3: > * Rebase to v5.8-rc2 > * Use length probe + allocate + query for the listxattr and setxattr > operations to avoid allocating unneeded space. > * Because of the above, drop the 'use kvmalloc for svcxdr_tmpalloc' patch, > as it's no longer needed. v3 of this series has been applied to nfsd-5.9. Thanks! See: git://git.linux-nfs.org/projects/cel/cel-2.6.git nfsd-5.9 Still waiting for Acks on 01/13 and 02/13. > v2: > * As per the discussion, user extended attributes are enabled if > the client and server support them (e.g. they support 4.2 and > advertise the user extended attribute FATTR). There are no longer > options to switch them off. > * The code is no longer conditioned on a config option. > * The number of patches has been reduced somewhat by merging > smaller, related ones. > * Renamed some functions and added parameter comments as requested. > > v1: > > * Split in to client and server (changed from the original RFC patch). > > Original RFC combined set is here: > > https://www.spinics.net/lists/linux-nfs/msg74843.html > > In general, these patches were, both server and client, tested as > follows: > * stress-ng-xattr with 1000 workers > * Test all corner cases (XATTR_SIZE_*) > * Test all failure cases (no xattr, setxattr with different or > invalid flags, etc). > * Verify the content of xattrs across several operations. > * Use KASAN and KMEMLEAK for a longer mix of testruns to verify > that there were no leaks (after unmounting the filesystem). > * Interop run against FreeBSD server/client implementation. > * Ran xfstests-dev, with no unexpected/new failures as compared > to an unpatched kernel. To fully use xfstests-dev, it needed > some modifications, as it expects to either use all xattr > namespaces, or none. Whereas NFS only suppors the "user." > namespace (+ optional ACLs). I will send the changes in > seperately. > > > Frank van der Linden (10): > xattr: break delegations in {set,remove}xattr > xattr: add a function to check if a namespace is supported > nfs,nfsd: NFSv4.2 extended attribute protocol definitions > nfsd: split off the write decode code in to a separate function > nfsd: add defines for NFSv4.2 extended attribute support > nfsd: define xattr functions to call in to their vfs counterparts > nfsd: take xattr bits in to account for permission checks > nfsd: add structure definitions for xattr requests / responses > nfsd: implement the xattr functions and en/decode logic > nfsd: add fattr support for user extended attributes > > fs/nfsd/nfs4proc.c | 128 ++++++++- > fs/nfsd/nfs4xdr.c | 531 +++++++++++++++++++++++++++++++++++--- > fs/nfsd/nfsd.h | 5 +- > fs/nfsd/vfs.c | 239 +++++++++++++++++ > fs/nfsd/vfs.h | 10 + > fs/nfsd/xdr4.h | 31 +++ > fs/xattr.c | 111 +++++++- > include/linux/nfs4.h | 22 +- > include/linux/xattr.h | 4 + > include/uapi/linux/nfs4.h | 3 + > 10 files changed, 1044 insertions(+), 40 deletions(-) > > -- > 2.17.2 > -- Chuck Lever ^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2020-07-04 14:39 UTC | newest] Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2020-06-23 22:39 [PATCH v3 00/10] server side user xattr support (RFC 8276) Frank van der Linden 2020-06-23 22:39 ` [PATCH v3 01/10] xattr: break delegations in {set,remove}xattr Frank van der Linden 2020-06-23 22:39 ` [PATCH v3 02/10] xattr: add a function to check if a namespace is supported Frank van der Linden 2020-06-23 22:39 ` [PATCH v3 03/10] nfs,nfsd: NFSv4.2 extended attribute protocol definitions Frank van der Linden 2020-06-23 22:39 ` [PATCH v3 04/10] nfsd: split off the write decode code in to a separate function Frank van der Linden 2020-06-23 22:39 ` [PATCH v3 05/10] nfsd: add defines for NFSv4.2 extended attribute support Frank van der Linden 2020-06-23 22:39 ` [PATCH v3 06/10] nfsd: define xattr functions to call in to their vfs counterparts Frank van der Linden 2020-06-23 22:39 ` [PATCH v3 07/10] nfsd: take xattr bits in to account for permission checks Frank van der Linden 2020-06-23 22:39 ` [PATCH v3 08/10] nfsd: add structure definitions for xattr requests / responses Frank van der Linden 2020-06-23 22:39 ` [PATCH v3 09/10] nfsd: implement the xattr functions and en/decode logic Frank van der Linden 2020-06-23 22:39 ` [PATCH v3 10/10] nfsd: add fattr support for user extended attributes Frank van der Linden 2020-06-25 16:50 ` [PATCH v3 00/10] server side user xattr support (RFC 8276) J. Bruce Fields 2020-06-25 17:13 ` Frank van der Linden 2020-06-25 16:53 ` J. Bruce Fields 2020-06-25 17:39 ` Frank van der Linden 2020-06-25 20:07 ` J. Bruce Fields 2020-07-04 14:37 ` Chuck Lever
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).