Skip to content

Commit

Permalink
Merge tag 'nfsd-5.9' of git://git.linux-nfs.org/projects/cel/cel-2.6
Browse files Browse the repository at this point in the history
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
  ...
  • Loading branch information
torvalds committed Aug 9, 2020
2 parents 8d3e09b + b297fed commit 7a6b604
Show file tree
Hide file tree
Showing 32 changed files with 1,807 additions and 466 deletions.
3 changes: 3 additions & 0 deletions fs/locks.c
Original file line number Diff line number Diff line change
Expand Up @@ -1808,6 +1808,9 @@ check_conflicting_open(struct file *filp, const long arg, int flags)

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;
Expand Down
2 changes: 1 addition & 1 deletion fs/nfsd/netns.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ struct nfsd_net {
unsigned int longest_chain_cachesize;

struct shrinker nfsd_reply_cache_shrinker;
/* utsname taken from the the process that starts the server */
/* utsname taken from the process that starts the server */
char nfsd_name[UNX_MAXNODENAME+1];
};

Expand Down
4 changes: 2 additions & 2 deletions fs/nfsd/nfs4idmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ idtoname_show(struct seq_file *m, struct cache_detail *cd, struct cache_head *h)
ent->id);
if (test_bit(CACHE_VALID, &h->flags))
seq_printf(m, " %s", ent->name);
seq_printf(m, "\n");
seq_putc(m, '\n');
return 0;
}

Expand Down Expand Up @@ -346,7 +346,7 @@ nametoid_show(struct seq_file *m, struct cache_detail *cd, struct cache_head *h)
ent->name);
if (test_bit(CACHE_VALID, &h->flags))
seq_printf(m, " %u", ent->id);
seq_printf(m, "\n");
seq_putc(m, '\n');
return 0;
}

Expand Down
128 changes: 127 additions & 1 deletion fs/nfsd/nfs4proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -2091,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.
*/
Expand Down Expand Up @@ -2700,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,
Expand Down Expand Up @@ -3081,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,
},
};

/**
Expand Down
24 changes: 11 additions & 13 deletions fs/nfsd/nfs4recover.c
Original file line number Diff line number Diff line change
Expand Up @@ -747,13 +747,11 @@ struct cld_upcall {
};

static int
__cld_pipe_upcall(struct rpc_pipe *pipe, void *cmsg)
__cld_pipe_upcall(struct rpc_pipe *pipe, void *cmsg, struct nfsd_net *nn)
{
int ret;
struct rpc_pipe_msg msg;
struct cld_upcall *cup = container_of(cmsg, struct cld_upcall, cu_u);
struct nfsd_net *nn = net_generic(pipe->dentry->d_sb->s_fs_info,
nfsd_net_id);

memset(&msg, 0, sizeof(msg));
msg.data = cmsg;
Expand All @@ -773,7 +771,7 @@ __cld_pipe_upcall(struct rpc_pipe *pipe, void *cmsg)
}

static int
cld_pipe_upcall(struct rpc_pipe *pipe, void *cmsg)
cld_pipe_upcall(struct rpc_pipe *pipe, void *cmsg, struct nfsd_net *nn)
{
int ret;

Expand All @@ -782,7 +780,7 @@ cld_pipe_upcall(struct rpc_pipe *pipe, void *cmsg)
* upcalls queued.
*/
do {
ret = __cld_pipe_upcall(pipe, cmsg);
ret = __cld_pipe_upcall(pipe, cmsg, nn);
} while (ret == -EAGAIN);

return ret;
Expand Down Expand Up @@ -1115,7 +1113,7 @@ nfsd4_cld_create(struct nfs4_client *clp)
memcpy(cup->cu_u.cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data,
clp->cl_name.len);

ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg);
ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg, nn);
if (!ret) {
ret = cup->cu_u.cu_msg.cm_status;
set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
Expand Down Expand Up @@ -1180,7 +1178,7 @@ nfsd4_cld_create_v2(struct nfs4_client *clp)
} else
cmsg->cm_u.cm_clntinfo.cc_princhash.cp_len = 0;

ret = cld_pipe_upcall(cn->cn_pipe, cmsg);
ret = cld_pipe_upcall(cn->cn_pipe, cmsg, nn);
if (!ret) {
ret = cmsg->cm_status;
set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
Expand Down Expand Up @@ -1218,7 +1216,7 @@ nfsd4_cld_remove(struct nfs4_client *clp)
memcpy(cup->cu_u.cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data,
clp->cl_name.len);

ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg);
ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg, nn);
if (!ret) {
ret = cup->cu_u.cu_msg.cm_status;
clear_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
Expand Down Expand Up @@ -1261,7 +1259,7 @@ nfsd4_cld_check_v0(struct nfs4_client *clp)
memcpy(cup->cu_u.cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data,
clp->cl_name.len);

ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg);
ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg, nn);
if (!ret) {
ret = cup->cu_u.cu_msg.cm_status;
set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
Expand Down Expand Up @@ -1404,7 +1402,7 @@ nfsd4_cld_grace_start(struct nfsd_net *nn)
}

cup->cu_u.cu_msg.cm_cmd = Cld_GraceStart;
ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg);
ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg, nn);
if (!ret)
ret = cup->cu_u.cu_msg.cm_status;

Expand Down Expand Up @@ -1432,7 +1430,7 @@ nfsd4_cld_grace_done_v0(struct nfsd_net *nn)

cup->cu_u.cu_msg.cm_cmd = Cld_GraceDone;
cup->cu_u.cu_msg.cm_u.cm_gracetime = nn->boot_time;
ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg);
ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg, nn);
if (!ret)
ret = cup->cu_u.cu_msg.cm_status;

Expand Down Expand Up @@ -1460,7 +1458,7 @@ nfsd4_cld_grace_done(struct nfsd_net *nn)
}

cup->cu_u.cu_msg.cm_cmd = Cld_GraceDone;
ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg);
ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg, nn);
if (!ret)
ret = cup->cu_u.cu_msg.cm_status;

Expand Down Expand Up @@ -1524,7 +1522,7 @@ nfsd4_cld_get_version(struct nfsd_net *nn)
goto out_err;
}
cup->cu_u.cu_msg.cm_cmd = Cld_GetVersion;
ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg);
ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg, nn);
if (!ret) {
ret = cup->cu_u.cu_msg.cm_status;
if (ret)
Expand Down
54 changes: 40 additions & 14 deletions fs/nfsd/nfs4state.c
Original file line number Diff line number Diff line change
Expand Up @@ -4940,6 +4940,32 @@ static struct file_lock *nfs4_alloc_init_lease(struct nfs4_delegation *dp,
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)
Expand All @@ -4959,9 +4985,12 @@ nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh,

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);
Expand Down Expand Up @@ -4991,11 +5020,19 @@ nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh,
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);
Expand Down Expand Up @@ -5077,17 +5114,6 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open,
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;
Expand Down
Loading

0 comments on commit 7a6b604

Please sign in to comment.