The following commit has been merged in the master branch: commit 7a6b60441f02f6e22e7c0936ef16fa3f51832a48 Merge: 8d3e09b43312991c503478bf0f5f99e92c23ccf1 b297fed699ad9e50315b27e78de42ac631c9990d Author: Linus Torvalds torvalds@linux-foundation.org Date: Sun Aug 9 13:58:04 2020 -0700
Merge tag 'nfsd-5.9' of git://git.linux-nfs.org/projects/cel/cel-2.6
Pull NFS server updates from Chuck Lever: "Highlights: - Support for user extended attributes on NFS (RFC 8276) - Further reduce unnecessary NFSv4 delegation recalls
Notable fixes: - Fix recent krb5p regression - Address a few resource leaks and a rare NULL dereference
Other: - De-duplicate RPC/RDMA error handling and other utility functions - Replace storage and display of kernel memory addresses by tracepoints"
* tag 'nfsd-5.9' of git://git.linux-nfs.org/projects/cel/cel-2.6: (38 commits) svcrdma: CM event handler clean up svcrdma: Remove transport reference counting svcrdma: Fix another Receive buffer leak SUNRPC: Refresh the show_rqstp_flags() macro nfsd: netns.h: delete a duplicated word SUNRPC: Fix ("SUNRPC: Add "@len" parameter to gss_unwrap()") nfsd: avoid a NULL dereference in __cld_pipe_upcall() nfsd4: a client's own opens needn't prevent delegations nfsd: Use seq_putc() in two functions svcrdma: Display chunk completion ID when posting a rw_ctxt svcrdma: Record send_ctxt completion ID in trace_svcrdma_post_send() svcrdma: Introduce Send completion IDs svcrdma: Record Receive completion ID in svc_rdma_decode_rqst svcrdma: Introduce Receive completion IDs svcrdma: Introduce infrastructure to support completion IDs svcrdma: Add common XDR encoders for RDMA and Read segments svcrdma: Add common XDR decoders for RDMA and Read segments SUNRPC: Add helpers for decoding list discriminators symbolically svcrdma: Remove declarations for functions long removed svcrdma: Clean up trace_svcrdma_send_failed() tracepoint ...
diff --combined fs/locks.c index 938fe325bc54,d5de9039dbd7..8fc0542f5132 --- a/fs/locks.c +++ b/fs/locks.c @@@ -1282,7 -1282,6 +1282,7 @@@ static int posix_lock_inode(struct inod if (!new_fl) goto out; locks_copy_lock(new_fl, request); + locks_move_blocks(new_fl, request); request = new_fl; new_fl = NULL; locks_insert_lock_ctx(request, &fl->fl_list); @@@ -1808,6 -1807,9 +1808,9 @@@ check_conflicting_open(struct file *fil
if (flags & FL_LAYOUT) return 0; + if (flags & FL_DELEG) + /* We leave these checks to the caller. */ + return 0;
if (arg == F_RDLCK) return inode_is_open_for_write(inode) ? -EAGAIN : 0; diff --combined fs/nfsd/nfs4state.c index c9056316a0b3,fdba971d06c3..81ed8e8bab3f --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@@ -507,17 -507,6 +507,17 @@@ find_any_file(struct nfs4_file *f return ret; }
+static struct nfsd_file *find_deleg_file(struct nfs4_file *f) +{ + struct nfsd_file *ret = NULL; + + spin_lock(&f->fi_lock); + if (f->fi_deleg_file) + ret = nfsd_file_get(f->fi_deleg_file); + spin_unlock(&f->fi_lock); + return ret; +} + static atomic_long_t num_delegations; unsigned long max_delegations;
@@@ -2455,8 -2444,6 +2455,8 @@@ static int nfs4_show_open(struct seq_fi oo = ols->st_stateowner; nf = st->sc_file; file = find_any_file(nf); + if (!file) + return 0;
seq_printf(s, "- "); nfs4_show_stateid(s, &st->sc_stateid); @@@ -2494,8 -2481,6 +2494,8 @@@ static int nfs4_show_lock(struct seq_fi oo = ols->st_stateowner; nf = st->sc_file; file = find_any_file(nf); + if (!file) + return 0;
seq_printf(s, "- "); nfs4_show_stateid(s, &st->sc_stateid); @@@ -2528,9 -2513,7 +2528,9 @@@ static int nfs4_show_deleg(struct seq_f
ds = delegstateid(st); nf = st->sc_file; - file = nf->fi_deleg_file; + file = find_deleg_file(nf); + if (!file) + return 0;
seq_printf(s, "- "); nfs4_show_stateid(s, &st->sc_stateid); @@@ -2546,7 -2529,6 +2546,7 @@@ seq_printf(s, ", "); nfs4_show_fname(s, file); seq_printf(s, " }\n"); + nfsd_file_put(file);
return 0; } @@@ -4940,6 -4922,32 +4940,32 @@@ static struct file_lock *nfs4_alloc_ini return fl; }
+ static int nfsd4_check_conflicting_opens(struct nfs4_client *clp, + struct nfs4_file *fp) + { + struct nfs4_clnt_odstate *co; + struct file *f = fp->fi_deleg_file->nf_file; + struct inode *ino = locks_inode(f); + int writes = atomic_read(&ino->i_writecount); + + if (fp->fi_fds[O_WRONLY]) + writes--; + if (fp->fi_fds[O_RDWR]) + writes--; + WARN_ON_ONCE(writes < 0); + if (writes > 0) + return -EAGAIN; + spin_lock(&fp->fi_lock); + list_for_each_entry(co, &fp->fi_clnt_odstate, co_perfile) { + if (co->co_client != clp) { + spin_unlock(&fp->fi_lock); + return -EAGAIN; + } + } + spin_unlock(&fp->fi_lock); + return 0; + } + static struct nfs4_delegation * nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh, struct nfs4_file *fp, struct nfs4_clnt_odstate *odstate) @@@ -4959,9 -4967,12 +4985,12 @@@
nf = find_readable_file(fp); if (!nf) { - /* We should always have a readable file here */ - WARN_ON_ONCE(1); - return ERR_PTR(-EBADF); + /* + * We probably could attempt another open and get a read + * delegation, but for now, don't bother until the + * client actually sends us one. + */ + return ERR_PTR(-EAGAIN); } spin_lock(&state_lock); spin_lock(&fp->fi_lock); @@@ -4991,11 -5002,19 +5020,19 @@@ if (!fl) goto out_clnt_odstate;
+ status = nfsd4_check_conflicting_opens(clp, fp); + if (status) { + locks_free_lock(fl); + goto out_clnt_odstate; + } status = vfs_setlease(fp->fi_deleg_file->nf_file, fl->fl_type, &fl, NULL); if (fl) locks_free_lock(fl); if (status) goto out_clnt_odstate; + status = nfsd4_check_conflicting_opens(clp, fp); + if (status) + goto out_clnt_odstate;
spin_lock(&state_lock); spin_lock(&fp->fi_lock); @@@ -5077,17 -5096,6 +5114,6 @@@ nfs4_open_delegation(struct svc_fh *fh goto out_no_deleg; if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED)) goto out_no_deleg; - /* - * Also, if the file was opened for write or - * create, there's a good chance the client's - * about to write to it, resulting in an - * immediate recall (since we don't support - * write delegations): - */ - if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) - goto out_no_deleg; - if (open->op_create == NFS4_OPEN_CREATE) - goto out_no_deleg; break; default: goto out_no_deleg; diff --combined include/linux/xattr.h index c5afaf8ca7a2,fac75810d9d3..10b4dc2709f0 --- a/include/linux/xattr.h +++ b/include/linux/xattr.h @@@ -15,7 -15,6 +15,7 @@@ #include <linux/slab.h> #include <linux/types.h> #include <linux/spinlock.h> +#include <linux/mm.h> #include <uapi/linux/xattr.h>
struct inode; @@@ -52,14 -51,18 +52,18 @@@ ssize_t vfs_getxattr(struct dentry *, c 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); 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; @@@ -95,7 -98,7 +99,7 @@@ static inline void simple_xattrs_free(s
list_for_each_entry_safe(xattr, node, &xattrs->head, list) { kfree(xattr->name); - kfree(xattr); + kvfree(xattr); } }
diff --combined net/sunrpc/xprtrdma/rpc_rdma.c index 453bacc99907,73ed51893175..0f5120c7668f --- a/net/sunrpc/xprtrdma/rpc_rdma.c +++ b/net/sunrpc/xprtrdma/rpc_rdma.c @@@ -71,7 -71,7 +71,7 @@@ static unsigned int rpcrdma_max_call_he size = RPCRDMA_HDRLEN_MIN;
/* Maximum Read list size */ - size = maxsegs * rpcrdma_readchunk_maxsz * sizeof(__be32); + size += maxsegs * rpcrdma_readchunk_maxsz * sizeof(__be32);
/* Minimal Read chunk size */ size += sizeof(__be32); /* segment count */ @@@ -94,7 -94,7 +94,7 @@@ static unsigned int rpcrdma_max_reply_h size = RPCRDMA_HDRLEN_MIN;
/* Maximum Write list size */ - size = sizeof(__be32); /* segment count */ + size += sizeof(__be32); /* segment count */ size += maxsegs * rpcrdma_segment_maxsz * sizeof(__be32); size += sizeof(__be32); /* list discriminator */
@@@ -275,14 -275,6 +275,6 @@@ out return n; }
- static void - xdr_encode_rdma_segment(__be32 *iptr, struct rpcrdma_mr *mr) - { - *iptr++ = cpu_to_be32(mr->mr_handle); - *iptr++ = cpu_to_be32(mr->mr_length); - xdr_encode_hyper(iptr, mr->mr_offset); - } - static int encode_rdma_segment(struct xdr_stream *xdr, struct rpcrdma_mr *mr) { @@@ -292,7 -284,7 +284,7 @@@ if (unlikely(!p)) return -EMSGSIZE;
- xdr_encode_rdma_segment(p, mr); + xdr_encode_rdma_segment(p, mr->mr_handle, mr->mr_length, mr->mr_offset); return 0; }
@@@ -307,8 -299,8 +299,8 @@@ encode_read_segment(struct xdr_stream * return -EMSGSIZE;
*p++ = xdr_one; /* Item present */ - *p++ = cpu_to_be32(position); - xdr_encode_rdma_segment(p, mr); + xdr_encode_read_segment(p, position, mr->mr_handle, mr->mr_length, + mr->mr_offset); return 0; }
@@@ -1133,11 -1125,11 +1125,11 @@@ rpcrdma_is_bcall(struct rpcrdma_xprt *r p = xdr_inline_decode(xdr, 0);
/* Chunk lists */ - if (*p++ != xdr_zero) + if (xdr_item_is_present(p++)) return false; - if (*p++ != xdr_zero) + if (xdr_item_is_present(p++)) return false; - if (*p++ != xdr_zero) + if (xdr_item_is_present(p++)) return false;
/* RPC header */ @@@ -1176,10 -1168,7 +1168,7 @@@ static int decode_rdma_segment(struct x if (unlikely(!p)) return -EIO;
- handle = be32_to_cpup(p++); - *length = be32_to_cpup(p++); - xdr_decode_hyper(p, &offset); - + xdr_decode_rdma_segment(p, &handle, length, &offset); trace_xprtrdma_decode_seg(handle, *length, offset); return 0; } @@@ -1215,7 -1204,7 +1204,7 @@@ static int decode_read_list(struct xdr_ p = xdr_inline_decode(xdr, sizeof(*p)); if (unlikely(!p)) return -EIO; - if (unlikely(*p != xdr_zero)) + if (unlikely(xdr_item_is_present(p))) return -EIO; return 0; } @@@ -1234,7 -1223,7 +1223,7 @@@ static int decode_write_list(struct xdr p = xdr_inline_decode(xdr, sizeof(*p)); if (unlikely(!p)) return -EIO; - if (*p == xdr_zero) + if (xdr_item_is_absent(p)) break; if (!first) return -EIO; @@@ -1256,7 -1245,7 +1245,7 @@@ static int decode_reply_chunk(struct xd return -EIO;
*length = 0; - if (*p != xdr_zero) + if (xdr_item_is_present(p)) if (decode_write_chunk(xdr, length)) return -EIO; return 0;