Skip to content

Commit 1ddd873

Browse files
committed
Merge tag 'nfsd-5.7-rc-1' of git://git.linux-nfs.org/projects/cel/cel-2.6
Pull nfsd fixes from Chuck Lever: "The first set of 5.7-rc fixes for NFS server issues. These were all unresolved at the time the 5.7 window opened, and needed some additional time to ensure they were correctly addressed. They are ready now. At the moment I know of one more urgent issue regarding the NFS server. A fix has been tested and is under review. I expect to send one more pull request, containing this fix (which now consists of 3 patches). Fixes: - Address several use-after-free and memory leak bugs - Prevent a backchannel livelock" * tag 'nfsd-5.7-rc-1' of git://git.linux-nfs.org/projects/cel/cel-2.6: svcrdma: Fix leak of svc_rdma_recv_ctxt objects svcrdma: Fix trace point use-after-free race SUNRPC: Fix backchannel RPC soft lockups SUNRPC/cache: Fix unsafe traverse caused double-free in cache_purge nfsd: memory corruption in nfsd4_lock()
2 parents 6f8cd03 + 23cf1ee commit 1ddd873

File tree

13 files changed

+89
-44
lines changed

13 files changed

+89
-44
lines changed

fs/nfsd/nfs4callback.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1312,6 +1312,7 @@ nfsd4_run_cb_work(struct work_struct *work)
13121312
container_of(work, struct nfsd4_callback, cb_work);
13131313
struct nfs4_client *clp = cb->cb_clp;
13141314
struct rpc_clnt *clnt;
1315+
int flags;
13151316

13161317
if (cb->cb_need_restart) {
13171318
cb->cb_need_restart = false;
@@ -1340,7 +1341,8 @@ nfsd4_run_cb_work(struct work_struct *work)
13401341
}
13411342

13421343
cb->cb_msg.rpc_cred = clp->cl_cb_cred;
1343-
rpc_call_async(clnt, &cb->cb_msg, RPC_TASK_SOFT | RPC_TASK_SOFTCONN,
1344+
flags = clp->cl_minorversion ? RPC_TASK_NOCONNECT : RPC_TASK_SOFTCONN;
1345+
rpc_call_async(clnt, &cb->cb_msg, RPC_TASK_SOFT | flags,
13441346
cb->cb_ops ? &nfsd4_cb_ops : &nfsd4_cb_probe_ops, cb);
13451347
}
13461348

fs/nfsd/nfs4state.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,8 @@ find_or_allocate_block(struct nfs4_lockowner *lo, struct knfsd_fh *fh,
267267
if (!nbl) {
268268
nbl= kmalloc(sizeof(*nbl), GFP_KERNEL);
269269
if (nbl) {
270+
INIT_LIST_HEAD(&nbl->nbl_list);
271+
INIT_LIST_HEAD(&nbl->nbl_lru);
270272
fh_copy_shallow(&nbl->nbl_fh, fh);
271273
locks_init_lock(&nbl->nbl_lock);
272274
nfsd4_init_cb(&nbl->nbl_cb, lo->lo_owner.so_client,

include/linux/sunrpc/svc_rdma.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ extern bool svc_rdma_post_recvs(struct svcxprt_rdma *rdma);
170170
extern void svc_rdma_recv_ctxt_put(struct svcxprt_rdma *rdma,
171171
struct svc_rdma_recv_ctxt *ctxt);
172172
extern void svc_rdma_flush_recv_queues(struct svcxprt_rdma *rdma);
173+
extern void svc_rdma_release_rqst(struct svc_rqst *rqstp);
173174
extern int svc_rdma_recvfrom(struct svc_rqst *);
174175

175176
/* svc_rdma_rw.c */

include/trace/events/rpcrdma.h

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1695,30 +1695,27 @@ DECLARE_EVENT_CLASS(svcrdma_sendcomp_event,
16951695

16961696
TRACE_EVENT(svcrdma_post_send,
16971697
TP_PROTO(
1698-
const struct ib_send_wr *wr,
1699-
int status
1698+
const struct ib_send_wr *wr
17001699
),
17011700

1702-
TP_ARGS(wr, status),
1701+
TP_ARGS(wr),
17031702

17041703
TP_STRUCT__entry(
17051704
__field(const void *, cqe)
17061705
__field(unsigned int, num_sge)
17071706
__field(u32, inv_rkey)
1708-
__field(int, status)
17091707
),
17101708

17111709
TP_fast_assign(
17121710
__entry->cqe = wr->wr_cqe;
17131711
__entry->num_sge = wr->num_sge;
17141712
__entry->inv_rkey = (wr->opcode == IB_WR_SEND_WITH_INV) ?
17151713
wr->ex.invalidate_rkey : 0;
1716-
__entry->status = status;
17171714
),
17181715

1719-
TP_printk("cqe=%p num_sge=%u inv_rkey=0x%08x status=%d",
1716+
TP_printk("cqe=%p num_sge=%u inv_rkey=0x%08x",
17201717
__entry->cqe, __entry->num_sge,
1721-
__entry->inv_rkey, __entry->status
1718+
__entry->inv_rkey
17221719
)
17231720
);
17241721

@@ -1783,26 +1780,23 @@ TRACE_EVENT(svcrdma_wc_receive,
17831780
TRACE_EVENT(svcrdma_post_rw,
17841781
TP_PROTO(
17851782
const void *cqe,
1786-
int sqecount,
1787-
int status
1783+
int sqecount
17881784
),
17891785

1790-
TP_ARGS(cqe, sqecount, status),
1786+
TP_ARGS(cqe, sqecount),
17911787

17921788
TP_STRUCT__entry(
17931789
__field(const void *, cqe)
17941790
__field(int, sqecount)
1795-
__field(int, status)
17961791
),
17971792

17981793
TP_fast_assign(
17991794
__entry->cqe = cqe;
18001795
__entry->sqecount = sqecount;
1801-
__entry->status = status;
18021796
),
18031797

1804-
TP_printk("cqe=%p sqecount=%d status=%d",
1805-
__entry->cqe, __entry->sqecount, __entry->status
1798+
TP_printk("cqe=%p sqecount=%d",
1799+
__entry->cqe, __entry->sqecount
18061800
)
18071801
);
18081802

@@ -1870,6 +1864,34 @@ DECLARE_EVENT_CLASS(svcrdma_sendqueue_event,
18701864
DEFINE_SQ_EVENT(full);
18711865
DEFINE_SQ_EVENT(retry);
18721866

1867+
TRACE_EVENT(svcrdma_sq_post_err,
1868+
TP_PROTO(
1869+
const struct svcxprt_rdma *rdma,
1870+
int status
1871+
),
1872+
1873+
TP_ARGS(rdma, status),
1874+
1875+
TP_STRUCT__entry(
1876+
__field(int, avail)
1877+
__field(int, depth)
1878+
__field(int, status)
1879+
__string(addr, rdma->sc_xprt.xpt_remotebuf)
1880+
),
1881+
1882+
TP_fast_assign(
1883+
__entry->avail = atomic_read(&rdma->sc_sq_avail);
1884+
__entry->depth = rdma->sc_sq_depth;
1885+
__entry->status = status;
1886+
__assign_str(addr, rdma->sc_xprt.xpt_remotebuf);
1887+
),
1888+
1889+
TP_printk("addr=%s sc_sq_avail=%d/%d status=%d",
1890+
__get_str(addr), __entry->avail, __entry->depth,
1891+
__entry->status
1892+
)
1893+
);
1894+
18731895
#endif /* _TRACE_RPCRDMA_H */
18741896

18751897
#include <trace/define_trace.h>

net/sunrpc/cache.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -529,7 +529,6 @@ void cache_purge(struct cache_detail *detail)
529529
{
530530
struct cache_head *ch = NULL;
531531
struct hlist_head *head = NULL;
532-
struct hlist_node *tmp = NULL;
533532
int i = 0;
534533

535534
spin_lock(&detail->hash_lock);
@@ -541,7 +540,9 @@ void cache_purge(struct cache_detail *detail)
541540
dprintk("RPC: %d entries in %s cache\n", detail->entries, detail->name);
542541
for (i = 0; i < detail->hash_size; i++) {
543542
head = &detail->hash_table[i];
544-
hlist_for_each_entry_safe(ch, tmp, head, cache_list) {
543+
while (!hlist_empty(head)) {
544+
ch = hlist_entry(head->first, struct cache_head,
545+
cache_list);
545546
sunrpc_begin_cache_remove_entry(ch, detail);
546547
spin_unlock(&detail->hash_lock);
547548
sunrpc_end_cache_remove_entry(ch, detail);

net/sunrpc/svc_xprt.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -908,9 +908,6 @@ int svc_send(struct svc_rqst *rqstp)
908908
if (!xprt)
909909
goto out;
910910

911-
/* release the receive skb before sending the reply */
912-
xprt->xpt_ops->xpo_release_rqst(rqstp);
913-
914911
/* calculate over-all length */
915912
xb = &rqstp->rq_res;
916913
xb->len = xb->head[0].iov_len +
@@ -1040,6 +1037,8 @@ static void svc_delete_xprt(struct svc_xprt *xprt)
10401037

10411038
dprintk("svc: svc_delete_xprt(%p)\n", xprt);
10421039
xprt->xpt_ops->xpo_detach(xprt);
1040+
if (xprt->xpt_bc_xprt)
1041+
xprt->xpt_bc_xprt->ops->close(xprt->xpt_bc_xprt);
10431042

10441043
spin_lock_bh(&serv->sv_lock);
10451044
list_del_init(&xprt->xpt_list);

net/sunrpc/svcsock.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,8 @@ static int svc_udp_sendto(struct svc_rqst *rqstp)
527527
unsigned int uninitialized_var(sent);
528528
int err;
529529

530+
svc_release_udp_skb(rqstp);
531+
530532
svc_set_cmsg_data(rqstp, cmh);
531533

532534
err = xprt_sock_sendmsg(svsk->sk_sock, &msg, xdr, 0, 0, &sent);
@@ -1076,6 +1078,8 @@ static int svc_tcp_sendto(struct svc_rqst *rqstp)
10761078
unsigned int uninitialized_var(sent);
10771079
int err;
10781080

1081+
svc_release_skb(rqstp);
1082+
10791083
err = xprt_sock_sendmsg(svsk->sk_sock, &msg, xdr, 0, marker, &sent);
10801084
xdr_free_bvec(xdr);
10811085
if (err < 0 || sent != (xdr->len + sizeof(marker)))

net/sunrpc/xprtrdma/svc_rdma_backchannel.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,8 @@ static void
244244
xprt_rdma_bc_close(struct rpc_xprt *xprt)
245245
{
246246
dprintk("svcrdma: %s: xprt %p\n", __func__, xprt);
247+
248+
xprt_disconnect_done(xprt);
247249
xprt->cwnd = RPC_CWNDSHIFT;
248250
}
249251

net/sunrpc/xprtrdma/svc_rdma_recvfrom.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,26 @@ void svc_rdma_recv_ctxt_put(struct svcxprt_rdma *rdma,
223223
svc_rdma_recv_ctxt_destroy(rdma, ctxt);
224224
}
225225

226+
/**
227+
* svc_rdma_release_rqst - Release transport-specific per-rqst resources
228+
* @rqstp: svc_rqst being released
229+
*
230+
* Ensure that the recv_ctxt is released whether or not a Reply
231+
* was sent. For example, the client could close the connection,
232+
* or svc_process could drop an RPC, before the Reply is sent.
233+
*/
234+
void svc_rdma_release_rqst(struct svc_rqst *rqstp)
235+
{
236+
struct svc_rdma_recv_ctxt *ctxt = rqstp->rq_xprt_ctxt;
237+
struct svc_xprt *xprt = rqstp->rq_xprt;
238+
struct svcxprt_rdma *rdma =
239+
container_of(xprt, struct svcxprt_rdma, sc_xprt);
240+
241+
rqstp->rq_xprt_ctxt = NULL;
242+
if (ctxt)
243+
svc_rdma_recv_ctxt_put(rdma, ctxt);
244+
}
245+
226246
static int __svc_rdma_post_recv(struct svcxprt_rdma *rdma,
227247
struct svc_rdma_recv_ctxt *ctxt)
228248
{
@@ -820,6 +840,8 @@ int svc_rdma_recvfrom(struct svc_rqst *rqstp)
820840
__be32 *p;
821841
int ret;
822842

843+
rqstp->rq_xprt_ctxt = NULL;
844+
823845
spin_lock(&rdma_xprt->sc_rq_dto_lock);
824846
ctxt = svc_rdma_next_recv_ctxt(&rdma_xprt->sc_read_complete_q);
825847
if (ctxt) {

net/sunrpc/xprtrdma/svc_rdma_rw.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -323,8 +323,6 @@ static int svc_rdma_post_chunk_ctxt(struct svc_rdma_chunk_ctxt *cc)
323323
if (atomic_sub_return(cc->cc_sqecount,
324324
&rdma->sc_sq_avail) > 0) {
325325
ret = ib_post_send(rdma->sc_qp, first_wr, &bad_wr);
326-
trace_svcrdma_post_rw(&cc->cc_cqe,
327-
cc->cc_sqecount, ret);
328326
if (ret)
329327
break;
330328
return 0;
@@ -337,6 +335,7 @@ static int svc_rdma_post_chunk_ctxt(struct svc_rdma_chunk_ctxt *cc)
337335
trace_svcrdma_sq_retry(rdma);
338336
} while (1);
339337

338+
trace_svcrdma_sq_post_err(rdma, ret);
340339
set_bit(XPT_CLOSE, &xprt->xpt_flags);
341340

342341
/* If even one was posted, there will be a completion. */

0 commit comments

Comments
 (0)