forked from Minki/linux
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:
commit
4108e10197
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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++;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user