Skip to content

Commit eb07d5a

Browse files
neilbrownTrond Myklebust
authored andcommitted
SUNRPC: handle malloc failure in ->request_prepare
If ->request_prepare() detects an error, it sets ->rq_task->tk_status. This is easy for callers to ignore. The only caller is xprt_request_enqueue_receive() and it does ignore the error, as does call_encode() which calls it. This can result in a request being queued to receive a reply without an allocated receive buffer. So instead of setting rq_task->tk_status, return an error, and store in ->tk_status only in call_encode(); The call to xprt_request_enqueue_receive() is now earlier in call_encode(), where the error can still be handled. Signed-off-by: NeilBrown <[email protected]> Signed-off-by: Trond Myklebust <[email protected]>
1 parent b243874 commit eb07d5a

File tree

4 files changed

+22
-16
lines changed

4 files changed

+22
-16
lines changed

include/linux/sunrpc/xprt.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ struct rpc_xprt_ops {
144144
unsigned short (*get_srcport)(struct rpc_xprt *xprt);
145145
int (*buf_alloc)(struct rpc_task *task);
146146
void (*buf_free)(struct rpc_task *task);
147-
void (*prepare_request)(struct rpc_rqst *req);
147+
int (*prepare_request)(struct rpc_rqst *req);
148148
int (*send_request)(struct rpc_rqst *req);
149149
void (*wait_for_reply_request)(struct rpc_task *task);
150150
void (*timer)(struct rpc_xprt *xprt, struct rpc_task *task);
@@ -357,10 +357,9 @@ int xprt_reserve_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task);
357357
void xprt_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task);
358358
void xprt_free_slot(struct rpc_xprt *xprt,
359359
struct rpc_rqst *req);
360-
void xprt_request_prepare(struct rpc_rqst *req);
361360
bool xprt_prepare_transmit(struct rpc_task *task);
362361
void xprt_request_enqueue_transmit(struct rpc_task *task);
363-
void xprt_request_enqueue_receive(struct rpc_task *task);
362+
int xprt_request_enqueue_receive(struct rpc_task *task);
364363
void xprt_request_wait_receive(struct rpc_task *task);
365364
void xprt_request_dequeue_xprt(struct rpc_task *task);
366365
bool xprt_request_need_retransmit(struct rpc_task *task);

net/sunrpc/clnt.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1858,6 +1858,9 @@ call_encode(struct rpc_task *task)
18581858
xprt_request_dequeue_xprt(task);
18591859
/* Encode here so that rpcsec_gss can use correct sequence number. */
18601860
rpc_xdr_encode(task);
1861+
/* Add task to reply queue before transmission to avoid races */
1862+
if (task->tk_status == 0 && rpc_reply_expected(task))
1863+
task->tk_status = xprt_request_enqueue_receive(task);
18611864
/* Did the encode result in an error condition? */
18621865
if (task->tk_status != 0) {
18631866
/* Was the error nonfatal? */
@@ -1881,9 +1884,6 @@ call_encode(struct rpc_task *task)
18811884
return;
18821885
}
18831886

1884-
/* Add task to reply queue before transmission to avoid races */
1885-
if (rpc_reply_expected(task))
1886-
xprt_request_enqueue_receive(task);
18871887
xprt_request_enqueue_transmit(task);
18881888
out:
18891889
task->tk_action = call_transmit;

net/sunrpc/xprt.c

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,11 @@
6969
/*
7070
* Local functions
7171
*/
72-
static void xprt_init(struct rpc_xprt *xprt, struct net *net);
72+
static void xprt_init(struct rpc_xprt *xprt, struct net *net);
7373
static __be32 xprt_alloc_xid(struct rpc_xprt *xprt);
74-
static void xprt_destroy(struct rpc_xprt *xprt);
75-
static void xprt_request_init(struct rpc_task *task);
74+
static void xprt_destroy(struct rpc_xprt *xprt);
75+
static void xprt_request_init(struct rpc_task *task);
76+
static int xprt_request_prepare(struct rpc_rqst *req);
7677

7778
static DEFINE_SPINLOCK(xprt_list_lock);
7879
static LIST_HEAD(xprt_list);
@@ -1143,16 +1144,19 @@ xprt_request_need_enqueue_receive(struct rpc_task *task, struct rpc_rqst *req)
11431144
* @task: RPC task
11441145
*
11451146
*/
1146-
void
1147+
int
11471148
xprt_request_enqueue_receive(struct rpc_task *task)
11481149
{
11491150
struct rpc_rqst *req = task->tk_rqstp;
11501151
struct rpc_xprt *xprt = req->rq_xprt;
1152+
int ret;
11511153

11521154
if (!xprt_request_need_enqueue_receive(task, req))
1153-
return;
1155+
return 0;
11541156

1155-
xprt_request_prepare(task->tk_rqstp);
1157+
ret = xprt_request_prepare(task->tk_rqstp);
1158+
if (ret)
1159+
return ret;
11561160
spin_lock(&xprt->queue_lock);
11571161

11581162
/* Update the softirq receive buffer */
@@ -1166,6 +1170,7 @@ xprt_request_enqueue_receive(struct rpc_task *task)
11661170

11671171
/* Turn off autodisconnect */
11681172
del_singleshot_timer_sync(&xprt->timer);
1173+
return 0;
11691174
}
11701175

11711176
/**
@@ -1452,14 +1457,16 @@ xprt_request_dequeue_xprt(struct rpc_task *task)
14521457
*
14531458
* Calls into the transport layer to do whatever is needed to prepare
14541459
* the request for transmission or receive.
1460+
* Returns error, or zero.
14551461
*/
1456-
void
1462+
static int
14571463
xprt_request_prepare(struct rpc_rqst *req)
14581464
{
14591465
struct rpc_xprt *xprt = req->rq_xprt;
14601466

14611467
if (xprt->ops->prepare_request)
1462-
xprt->ops->prepare_request(req);
1468+
return xprt->ops->prepare_request(req);
1469+
return 0;
14631470
}
14641471

14651472
/**

net/sunrpc/xprtsock.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -822,11 +822,11 @@ static int xs_stream_nospace(struct rpc_rqst *req, bool vm_wait)
822822
return ret;
823823
}
824824

825-
static void
825+
static int
826826
xs_stream_prepare_request(struct rpc_rqst *req)
827827
{
828828
xdr_free_bvec(&req->rq_rcv_buf);
829-
req->rq_task->tk_status = xdr_alloc_bvec(
829+
return xdr_alloc_bvec(
830830
&req->rq_rcv_buf, GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN);
831831
}
832832

0 commit comments

Comments
 (0)