Miscellaneous NFSD fixes for v5.12-rc.

-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEKLLlsBKG3yQ88j7+M2qzM29mf5cFAmBLe0AACgkQM2qzM29m
 f5efQQ//RE+kcXPczmmlNuRWMsVVTmlLw7lV6qOKeiaQAoNCD+Y4I99iAJPyCLeH
 NbZrnSqJstvoRIo1fS9koVuOfSlIzBOvjKeQuIw4vP9pGyEHfKfxPe2BH9Ijlb9W
 BxasLSukin7ju+5MHVZz2Z1GYopHU+hjn33uRLZk/JcSA97bLfoJFWZbWafXFBiK
 1OY0gK26tkucTEYDobwVn7uUM4Swl4VlpsqJOoR2wCiUwBa9aOo9A/zJaQ2XS7Ut
 8y5AxiBiVRlhrFkrN4cidpzV3OhDXIxPP9sa3qQ6PVUE2waS1QC0vTEx3Bsw4X3G
 RzgrS3Ceq7YXJCMminzM9SbTtInsAeToJHDDzXiLDrzh+3u4u7dhknh+Ag8M2vDL
 s4ZSBoIX74XFEGTU/KMCRXtBjum4WfzGE5p1tXBx44hVBUx75i0Ktdgl/8ap1uxE
 YqlpH1zLXpfe1zxbOd7huD+A5QbXWoHjALwMj7KewBp8j8/UZ/RrHAWc+ZOaxJwO
 7PejnTPn6agdpNRXHhnV+XIAU9eoaMbCTVnxRN++ddaP6jIS6CdHSRVOtpUvhW9u
 VMprXUQ8ozA6ZXyyV41sVmzVC8l2f8DtwMm14yONgTA/0DX+JgrDKzXHbkW7ol3+
 7RuSM8mcmXAq+PxG9osUFOGxcZktgGzUhhYINm3twI0YShBPY4k=
 =4Nt4
 -----END PGP SIGNATURE-----

Merge tag 'nfsd-5.12-2' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux

Pull nfsd fixes from Chuck Lever:
 "Miscellaneous NFSD fixes for v5.12-rc"

* tag 'nfsd-5.12-2' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux:
  svcrdma: Revert "svcrdma: Reduce Receive doorbell rate"
  NFSD: fix error handling in NFSv4.0 callbacks
  NFSD: fix dest to src mount in inter-server COPY
  Revert "nfsd4: a client's own opens needn't prevent delegations"
  Revert "nfsd4: remove check_conflicting_opens warning"
  rpc: fix NULL dereference on kmalloc failure
  sunrpc: fix refcount leak for rpc auth modules
  NFSD: Repair misuse of sv_lock in 5.10.16-rt30.
  nfsd: don't abort copies early
  fs: nfsd: fix kconfig dependency warning for NFSD_V4
  svcrdma: disable timeouts on rdma backchannel
  nfsd: Don't keep looking up unhashed files in the nfsd file cache
This commit is contained in:
Linus Torvalds 2021-03-16 10:22:50 -07:00
commit 4108e10197
12 changed files with 75 additions and 99 deletions

View File

@ -1808,9 +1808,6 @@ 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;

View File

@ -73,6 +73,7 @@ config NFSD_V4
select NFSD_V3
select FS_POSIX_ACL
select SUNRPC_GSS
select CRYPTO
select CRYPTO_MD5
select CRYPTO_SHA256
select GRACE_PERIOD

View File

@ -898,6 +898,8 @@ nfsd_file_find_locked(struct inode *inode, unsigned int may_flags,
continue;
if (!nfsd_match_cred(nf->nf_cred, current_cred()))
continue;
if (!test_bit(NFSD_FILE_HASHED, &nf->nf_flags))
continue;
if (nfsd_file_get(nf) != NULL)
return nf;
}

View File

@ -1189,6 +1189,7 @@ static void nfsd4_cb_done(struct rpc_task *task, void *calldata)
switch (task->tk_status) {
case -EIO:
case -ETIMEDOUT:
case -EACCES:
nfsd4_mark_cb_down(clp, task->tk_status);
}
break;

View File

@ -1302,7 +1302,7 @@ nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct nfsd_file *src,
struct nfsd_file *dst)
{
nfs42_ssc_close(src->nf_file);
/* 'src' is freed by nfsd4_do_async_copy */
fput(src->nf_file);
nfsd_file_put(dst);
mntput(ss_mnt);
}

View File

@ -4940,31 +4940,6 @@ 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--;
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)
@ -4984,12 +4959,9 @@ nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh,
nf = find_readable_file(fp);
if (!nf) {
/*
* 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);
/* We should always have a readable file here */
WARN_ON_ONCE(1);
return ERR_PTR(-EBADF);
}
spin_lock(&state_lock);
spin_lock(&fp->fi_lock);
@ -5019,19 +4991,11 @@ 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);
@ -5113,6 +5077,17 @@ 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;
@ -5389,7 +5364,7 @@ nfs4_laundromat(struct nfsd_net *nn)
idr_for_each_entry(&nn->s2s_cp_stateids, cps_t, i) {
cps = container_of(cps_t, struct nfs4_cpntf_state, cp_stateid);
if (cps->cp_stateid.sc_type == NFS4_COPYNOTIFY_STID &&
cps->cpntf_time > cutoff)
cps->cpntf_time < cutoff)
_free_cpntf_state_locked(nn, cps);
}
spin_unlock(&nn->s2s_cp_lock);

View File

@ -104,7 +104,6 @@ struct svcxprt_rdma {
wait_queue_head_t sc_send_wait; /* SQ exhaustion waitlist */
unsigned long sc_flags;
u32 sc_pending_recvs;
struct list_head sc_read_complete_q;
struct work_struct sc_work;

View File

@ -1825,11 +1825,14 @@ static int
svcauth_gss_release(struct svc_rqst *rqstp)
{
struct gss_svc_data *gsd = (struct gss_svc_data *)rqstp->rq_auth_data;
struct rpc_gss_wire_cred *gc = &gsd->clcred;
struct rpc_gss_wire_cred *gc;
struct xdr_buf *resbuf = &rqstp->rq_res;
int stat = -EINVAL;
struct sunrpc_net *sn = net_generic(SVC_NET(rqstp), sunrpc_net_id);
if (!gsd)
goto out;
gc = &gsd->clcred;
if (gc->gc_proc != RPC_GSS_PROC_DATA)
goto out;
/* Release can be called twice, but we only wrap once. */
@ -1870,10 +1873,10 @@ out_err:
if (rqstp->rq_cred.cr_group_info)
put_group_info(rqstp->rq_cred.cr_group_info);
rqstp->rq_cred.cr_group_info = NULL;
if (gsd->rsci)
if (gsd && gsd->rsci) {
cache_put(&gsd->rsci->h, sn->rsc_cache);
gsd->rsci = NULL;
gsd->rsci = NULL;
}
return stat;
}

View File

@ -1413,7 +1413,7 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
sendit:
if (svc_authorise(rqstp))
goto close;
goto close_xprt;
return 1; /* Caller can now send it */
release_dropit:
@ -1425,6 +1425,8 @@ release_dropit:
return 0;
close:
svc_authorise(rqstp);
close_xprt:
if (rqstp->rq_xprt && test_bit(XPT_TEMP, &rqstp->rq_xprt->xpt_flags))
svc_close_xprt(rqstp->rq_xprt);
dprintk("svc: svc_process close\n");
@ -1433,7 +1435,7 @@ release_dropit:
err_short_len:
svc_printk(rqstp, "short len %zd, dropping request\n",
argv->iov_len);
goto close;
goto close_xprt;
err_bad_rpc:
serv->sv_stats->rpcbadfmt++;

View File

@ -1060,7 +1060,7 @@ static int svc_close_list(struct svc_serv *serv, struct list_head *xprt_list, st
struct svc_xprt *xprt;
int ret = 0;
spin_lock(&serv->sv_lock);
spin_lock_bh(&serv->sv_lock);
list_for_each_entry(xprt, xprt_list, xpt_list) {
if (xprt->xpt_net != net)
continue;
@ -1068,7 +1068,7 @@ static int svc_close_list(struct svc_serv *serv, struct list_head *xprt_list, st
set_bit(XPT_CLOSE, &xprt->xpt_flags);
svc_xprt_enqueue(xprt);
}
spin_unlock(&serv->sv_lock);
spin_unlock_bh(&serv->sv_lock);
return ret;
}

View File

@ -252,9 +252,9 @@ xprt_setup_rdma_bc(struct xprt_create *args)
xprt->timeout = &xprt_rdma_bc_timeout;
xprt_set_bound(xprt);
xprt_set_connected(xprt);
xprt->bind_timeout = RPCRDMA_BIND_TO;
xprt->reestablish_timeout = RPCRDMA_INIT_REEST_TO;
xprt->idle_timeout = RPCRDMA_IDLE_DISC_TO;
xprt->bind_timeout = 0;
xprt->reestablish_timeout = 0;
xprt->idle_timeout = 0;
xprt->prot = XPRT_TRANSPORT_BC_RDMA;
xprt->ops = &xprt_rdma_bc_procs;

View File

@ -266,46 +266,33 @@ void svc_rdma_release_rqst(struct svc_rqst *rqstp)
svc_rdma_recv_ctxt_put(rdma, ctxt);
}
static bool svc_rdma_refresh_recvs(struct svcxprt_rdma *rdma,
unsigned int wanted, bool temp)
static int __svc_rdma_post_recv(struct svcxprt_rdma *rdma,
struct svc_rdma_recv_ctxt *ctxt)
{
const struct ib_recv_wr *bad_wr = NULL;
struct svc_rdma_recv_ctxt *ctxt;
struct ib_recv_wr *recv_chain;
int ret;
recv_chain = NULL;
while (wanted--) {
ctxt = svc_rdma_recv_ctxt_get(rdma);
if (!ctxt)
break;
trace_svcrdma_post_recv(ctxt);
ctxt->rc_temp = temp;
ctxt->rc_recv_wr.next = recv_chain;
recv_chain = &ctxt->rc_recv_wr;
rdma->sc_pending_recvs++;
}
if (!recv_chain)
return false;
ret = ib_post_recv(rdma->sc_qp, recv_chain, &bad_wr);
trace_svcrdma_post_recv(ctxt);
ret = ib_post_recv(rdma->sc_qp, &ctxt->rc_recv_wr, NULL);
if (ret)
goto err_post;
return true;
return 0;
err_post:
while (bad_wr) {
ctxt = container_of(bad_wr, struct svc_rdma_recv_ctxt,
rc_recv_wr);
bad_wr = bad_wr->next;
svc_rdma_recv_ctxt_put(rdma, ctxt);
}
trace_svcrdma_rq_post_err(rdma, ret);
/* Since we're destroying the xprt, no need to reset
* sc_pending_recvs. */
return false;
svc_rdma_recv_ctxt_put(rdma, ctxt);
return ret;
}
static int svc_rdma_post_recv(struct svcxprt_rdma *rdma)
{
struct svc_rdma_recv_ctxt *ctxt;
if (test_bit(XPT_CLOSE, &rdma->sc_xprt.xpt_flags))
return 0;
ctxt = svc_rdma_recv_ctxt_get(rdma);
if (!ctxt)
return -ENOMEM;
return __svc_rdma_post_recv(rdma, ctxt);
}
/**
@ -316,7 +303,20 @@ err_post:
*/
bool svc_rdma_post_recvs(struct svcxprt_rdma *rdma)
{
return svc_rdma_refresh_recvs(rdma, rdma->sc_max_requests, true);
struct svc_rdma_recv_ctxt *ctxt;
unsigned int i;
int ret;
for (i = 0; i < rdma->sc_max_requests; i++) {
ctxt = svc_rdma_recv_ctxt_get(rdma);
if (!ctxt)
return false;
ctxt->rc_temp = true;
ret = __svc_rdma_post_recv(rdma, ctxt);
if (ret)
return false;
}
return true;
}
/**
@ -324,6 +324,8 @@ bool svc_rdma_post_recvs(struct svcxprt_rdma *rdma)
* @cq: Completion Queue context
* @wc: Work Completion object
*
* NB: The svc_xprt/svcxprt_rdma is pinned whenever it's possible that
* the Receive completion handler could be running.
*/
static void svc_rdma_wc_receive(struct ib_cq *cq, struct ib_wc *wc)
{
@ -331,8 +333,6 @@ static void svc_rdma_wc_receive(struct ib_cq *cq, struct ib_wc *wc)
struct ib_cqe *cqe = wc->wr_cqe;
struct svc_rdma_recv_ctxt *ctxt;
rdma->sc_pending_recvs--;
/* WARNING: Only wc->wr_cqe and wc->status are reliable */
ctxt = container_of(cqe, struct svc_rdma_recv_ctxt, rc_cqe);
@ -340,6 +340,9 @@ static void svc_rdma_wc_receive(struct ib_cq *cq, struct ib_wc *wc)
if (wc->status != IB_WC_SUCCESS)
goto flushed;
if (svc_rdma_post_recv(rdma))
goto post_err;
/* All wc fields are now known to be valid */
ctxt->rc_byte_len = wc->byte_len;
@ -350,18 +353,11 @@ static void svc_rdma_wc_receive(struct ib_cq *cq, struct ib_wc *wc)
spin_unlock(&rdma->sc_rq_dto_lock);
if (!test_bit(RDMAXPRT_CONN_PENDING, &rdma->sc_flags))
svc_xprt_enqueue(&rdma->sc_xprt);
if (!test_bit(XPT_CLOSE, &rdma->sc_xprt.xpt_flags) &&
rdma->sc_pending_recvs < rdma->sc_max_requests)
if (!svc_rdma_refresh_recvs(rdma, RPCRDMA_MAX_RECV_BATCH,
false))
goto post_err;
return;
flushed:
svc_rdma_recv_ctxt_put(rdma, ctxt);
post_err:
svc_rdma_recv_ctxt_put(rdma, ctxt);
set_bit(XPT_CLOSE, &rdma->sc_xprt.xpt_flags);
svc_xprt_enqueue(&rdma->sc_xprt);
}