Skip to content

Commit 948f072

Browse files
neilbrownchucklever
authored andcommitted
SUNRPC: always free ctxt when freeing deferred request
Since the ->xprt_ctxt pointer was added to svc_deferred_req, it has not been sufficient to use kfree() to free a deferred request. We may need to free the ctxt as well. As freeing the ctxt is all that ->xpo_release_rqst() does, we repurpose it to explicit do that even when the ctxt is not stored in an rqst. So we now have ->xpo_release_ctxt() which is given an xprt and a ctxt, which may have been taken either from an rqst or from a dreq. The caller is now responsible for clearing that pointer after the call to ->xpo_release_ctxt. We also clear dr->xprt_ctxt when the ctxt is moved into a new rqst when revisiting a deferred request. This ensures there is only one pointer to the ctxt, so the risk of double freeing in future is reduced. The new code in svc_xprt_release which releases both the ctxt and any rq_deferred depends on this. Fixes: 773f91b ("SUNRPC: Fix NFSD's request deferral on RDMA transports") Signed-off-by: NeilBrown <[email protected]> Reviewed-by: Jeff Layton <[email protected]> Signed-off-by: Chuck Lever <[email protected]>
1 parent eb8d3a2 commit 948f072

File tree

6 files changed

+41
-29
lines changed

6 files changed

+41
-29
lines changed

include/linux/sunrpc/svc_rdma.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ extern struct svc_rdma_recv_ctxt *
176176
extern void svc_rdma_recv_ctxt_put(struct svcxprt_rdma *rdma,
177177
struct svc_rdma_recv_ctxt *ctxt);
178178
extern void svc_rdma_flush_recv_queues(struct svcxprt_rdma *rdma);
179-
extern void svc_rdma_release_rqst(struct svc_rqst *rqstp);
179+
extern void svc_rdma_release_ctxt(struct svc_xprt *xprt, void *ctxt);
180180
extern int svc_rdma_recvfrom(struct svc_rqst *);
181181

182182
/* svc_rdma_rw.c */

include/linux/sunrpc/svc_xprt.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ struct svc_xprt_ops {
2323
int (*xpo_sendto)(struct svc_rqst *);
2424
int (*xpo_result_payload)(struct svc_rqst *, unsigned int,
2525
unsigned int);
26-
void (*xpo_release_rqst)(struct svc_rqst *);
26+
void (*xpo_release_ctxt)(struct svc_xprt *xprt, void *ctxt);
2727
void (*xpo_detach)(struct svc_xprt *);
2828
void (*xpo_free)(struct svc_xprt *);
2929
void (*xpo_kill_temp_xprt)(struct svc_xprt *);

net/sunrpc/svc_xprt.c

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -532,13 +532,23 @@ void svc_reserve(struct svc_rqst *rqstp, int space)
532532
}
533533
EXPORT_SYMBOL_GPL(svc_reserve);
534534

535+
static void free_deferred(struct svc_xprt *xprt, struct svc_deferred_req *dr)
536+
{
537+
if (!dr)
538+
return;
539+
540+
xprt->xpt_ops->xpo_release_ctxt(xprt, dr->xprt_ctxt);
541+
kfree(dr);
542+
}
543+
535544
static void svc_xprt_release(struct svc_rqst *rqstp)
536545
{
537546
struct svc_xprt *xprt = rqstp->rq_xprt;
538547

539-
xprt->xpt_ops->xpo_release_rqst(rqstp);
548+
xprt->xpt_ops->xpo_release_ctxt(xprt, rqstp->rq_xprt_ctxt);
549+
rqstp->rq_xprt_ctxt = NULL;
540550

541-
kfree(rqstp->rq_deferred);
551+
free_deferred(xprt, rqstp->rq_deferred);
542552
rqstp->rq_deferred = NULL;
543553

544554
svc_rqst_release_pages(rqstp);
@@ -1054,7 +1064,7 @@ static void svc_delete_xprt(struct svc_xprt *xprt)
10541064
spin_unlock_bh(&serv->sv_lock);
10551065

10561066
while ((dr = svc_deferred_dequeue(xprt)) != NULL)
1057-
kfree(dr);
1067+
free_deferred(xprt, dr);
10581068

10591069
call_xpt_users(xprt);
10601070
svc_xprt_put(xprt);
@@ -1176,8 +1186,8 @@ static void svc_revisit(struct cache_deferred_req *dreq, int too_many)
11761186
if (too_many || test_bit(XPT_DEAD, &xprt->xpt_flags)) {
11771187
spin_unlock(&xprt->xpt_lock);
11781188
trace_svc_defer_drop(dr);
1189+
free_deferred(xprt, dr);
11791190
svc_xprt_put(xprt);
1180-
kfree(dr);
11811191
return;
11821192
}
11831193
dr->xprt = NULL;
@@ -1222,14 +1232,13 @@ static struct cache_deferred_req *svc_defer(struct cache_req *req)
12221232
dr->addrlen = rqstp->rq_addrlen;
12231233
dr->daddr = rqstp->rq_daddr;
12241234
dr->argslen = rqstp->rq_arg.len >> 2;
1225-
dr->xprt_ctxt = rqstp->rq_xprt_ctxt;
12261235

12271236
/* back up head to the start of the buffer and copy */
12281237
skip = rqstp->rq_arg.len - rqstp->rq_arg.head[0].iov_len;
12291238
memcpy(dr->args, rqstp->rq_arg.head[0].iov_base - skip,
12301239
dr->argslen << 2);
12311240
}
1232-
WARN_ON_ONCE(rqstp->rq_xprt_ctxt != dr->xprt_ctxt);
1241+
dr->xprt_ctxt = rqstp->rq_xprt_ctxt;
12331242
rqstp->rq_xprt_ctxt = NULL;
12341243
trace_svc_defer(rqstp);
12351244
svc_xprt_get(rqstp->rq_xprt);
@@ -1263,6 +1272,8 @@ static noinline int svc_deferred_recv(struct svc_rqst *rqstp)
12631272
rqstp->rq_daddr = dr->daddr;
12641273
rqstp->rq_respages = rqstp->rq_pages;
12651274
rqstp->rq_xprt_ctxt = dr->xprt_ctxt;
1275+
1276+
dr->xprt_ctxt = NULL;
12661277
svc_xprt_received(rqstp->rq_xprt);
12671278
return dr->argslen << 2;
12681279
}

net/sunrpc/svcsock.c

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -121,27 +121,27 @@ static void svc_reclassify_socket(struct socket *sock)
121121
#endif
122122

123123
/**
124-
* svc_tcp_release_rqst - Release transport-related resources
125-
* @rqstp: request structure with resources to be released
124+
* svc_tcp_release_ctxt - Release transport-related resources
125+
* @xprt: the transport which owned the context
126+
* @ctxt: the context from rqstp->rq_xprt_ctxt or dr->xprt_ctxt
126127
*
127128
*/
128-
static void svc_tcp_release_rqst(struct svc_rqst *rqstp)
129+
static void svc_tcp_release_ctxt(struct svc_xprt *xprt, void *ctxt)
129130
{
130131
}
131132

132133
/**
133-
* svc_udp_release_rqst - Release transport-related resources
134-
* @rqstp: request structure with resources to be released
134+
* svc_udp_release_ctxt - Release transport-related resources
135+
* @xprt: the transport which owned the context
136+
* @ctxt: the context from rqstp->rq_xprt_ctxt or dr->xprt_ctxt
135137
*
136138
*/
137-
static void svc_udp_release_rqst(struct svc_rqst *rqstp)
139+
static void svc_udp_release_ctxt(struct svc_xprt *xprt, void *ctxt)
138140
{
139-
struct sk_buff *skb = rqstp->rq_xprt_ctxt;
141+
struct sk_buff *skb = ctxt;
140142

141-
if (skb) {
142-
rqstp->rq_xprt_ctxt = NULL;
143+
if (skb)
143144
consume_skb(skb);
144-
}
145145
}
146146

147147
union svc_pktinfo_u {
@@ -696,7 +696,8 @@ static int svc_udp_sendto(struct svc_rqst *rqstp)
696696
unsigned int sent;
697697
int err;
698698

699-
svc_udp_release_rqst(rqstp);
699+
svc_udp_release_ctxt(xprt, rqstp->rq_xprt_ctxt);
700+
rqstp->rq_xprt_ctxt = NULL;
700701

701702
svc_set_cmsg_data(rqstp, cmh);
702703

@@ -768,7 +769,7 @@ static const struct svc_xprt_ops svc_udp_ops = {
768769
.xpo_recvfrom = svc_udp_recvfrom,
769770
.xpo_sendto = svc_udp_sendto,
770771
.xpo_result_payload = svc_sock_result_payload,
771-
.xpo_release_rqst = svc_udp_release_rqst,
772+
.xpo_release_ctxt = svc_udp_release_ctxt,
772773
.xpo_detach = svc_sock_detach,
773774
.xpo_free = svc_sock_free,
774775
.xpo_has_wspace = svc_udp_has_wspace,
@@ -1301,7 +1302,8 @@ static int svc_tcp_sendto(struct svc_rqst *rqstp)
13011302
unsigned int sent;
13021303
int err;
13031304

1304-
svc_tcp_release_rqst(rqstp);
1305+
svc_tcp_release_ctxt(xprt, rqstp->rq_xprt_ctxt);
1306+
rqstp->rq_xprt_ctxt = NULL;
13051307

13061308
atomic_inc(&svsk->sk_sendqlen);
13071309
mutex_lock(&xprt->xpt_mutex);
@@ -1346,7 +1348,7 @@ static const struct svc_xprt_ops svc_tcp_ops = {
13461348
.xpo_recvfrom = svc_tcp_recvfrom,
13471349
.xpo_sendto = svc_tcp_sendto,
13481350
.xpo_result_payload = svc_sock_result_payload,
1349-
.xpo_release_rqst = svc_tcp_release_rqst,
1351+
.xpo_release_ctxt = svc_tcp_release_ctxt,
13501352
.xpo_detach = svc_tcp_sock_detach,
13511353
.xpo_free = svc_sock_free,
13521354
.xpo_has_wspace = svc_tcp_has_wspace,

net/sunrpc/xprtrdma/svc_rdma_recvfrom.c

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -239,21 +239,20 @@ void svc_rdma_recv_ctxt_put(struct svcxprt_rdma *rdma,
239239
}
240240

241241
/**
242-
* svc_rdma_release_rqst - Release transport-specific per-rqst resources
243-
* @rqstp: svc_rqst being released
242+
* svc_rdma_release_ctxt - Release transport-specific per-rqst resources
243+
* @xprt: the transport which owned the context
244+
* @vctxt: the context from rqstp->rq_xprt_ctxt or dr->xprt_ctxt
244245
*
245246
* Ensure that the recv_ctxt is released whether or not a Reply
246247
* was sent. For example, the client could close the connection,
247248
* or svc_process could drop an RPC, before the Reply is sent.
248249
*/
249-
void svc_rdma_release_rqst(struct svc_rqst *rqstp)
250+
void svc_rdma_release_ctxt(struct svc_xprt *xprt, void *vctxt)
250251
{
251-
struct svc_rdma_recv_ctxt *ctxt = rqstp->rq_xprt_ctxt;
252-
struct svc_xprt *xprt = rqstp->rq_xprt;
252+
struct svc_rdma_recv_ctxt *ctxt = vctxt;
253253
struct svcxprt_rdma *rdma =
254254
container_of(xprt, struct svcxprt_rdma, sc_xprt);
255255

256-
rqstp->rq_xprt_ctxt = NULL;
257256
if (ctxt)
258257
svc_rdma_recv_ctxt_put(rdma, ctxt);
259258
}

net/sunrpc/xprtrdma/svc_rdma_transport.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ static const struct svc_xprt_ops svc_rdma_ops = {
8080
.xpo_recvfrom = svc_rdma_recvfrom,
8181
.xpo_sendto = svc_rdma_sendto,
8282
.xpo_result_payload = svc_rdma_result_payload,
83-
.xpo_release_rqst = svc_rdma_release_rqst,
83+
.xpo_release_ctxt = svc_rdma_release_ctxt,
8484
.xpo_detach = svc_rdma_detach,
8585
.xpo_free = svc_rdma_free,
8686
.xpo_has_wspace = svc_rdma_has_wspace,

0 commit comments

Comments
 (0)