Skip to content

Commit 4e99b32

Browse files
committed
Merge tag 'nfs-for-5.8-2' of git://git.linux-nfs.org/projects/anna/linux-nfs
Pull NFS client bugfixes from Anna Schumaker: "Stable Fixes: - xprtrdma: Fix handling of RDMA_ERROR replies - sunrpc: Fix rollback in rpc_gssd_dummy_populate() - pNFS/flexfiles: Fix list corruption if the mirror count changes - NFSv4: Fix CLOSE not waiting for direct IO completion - SUNRPC: Properly set the @Subbuf parameter of xdr_buf_subsegment() Other Fixes: - xprtrdma: Fix a use-after-free with r_xprt->rx_ep - Fix other xprtrdma races during disconnect - NFS: Fix memory leak of export_path" * tag 'nfs-for-5.8-2' of git://git.linux-nfs.org/projects/anna/linux-nfs: SUNRPC: Properly set the @Subbuf parameter of xdr_buf_subsegment() NFSv4 fix CLOSE not waiting for direct IO compeletion pNFS/flexfiles: Fix list corruption if the mirror count changes nfs: Fix memory leak of export_path sunrpc: fixed rollback in rpc_gssd_dummy_populate() xprtrdma: Fix handling of RDMA_ERROR replies xprtrdma: Clean up disconnect xprtrdma: Clean up synopsis of rpcrdma_flush_disconnect() xprtrdma: Use re_connect_status safely in rpcrdma_xprt_connect() xprtrdma: Prevent dereferencing r_xprt->rx_ep after it is freed
2 parents ab0f247 + 89a3c9f commit 4e99b32

File tree

11 files changed

+75
-49
lines changed

11 files changed

+75
-49
lines changed

fs/nfs/direct.c

+9-4
Original file line numberDiff line numberDiff line change
@@ -267,8 +267,6 @@ static void nfs_direct_complete(struct nfs_direct_req *dreq)
267267
{
268268
struct inode *inode = dreq->inode;
269269

270-
inode_dio_end(inode);
271-
272270
if (dreq->iocb) {
273271
long res = (long) dreq->error;
274272
if (dreq->count != 0) {
@@ -280,7 +278,10 @@ static void nfs_direct_complete(struct nfs_direct_req *dreq)
280278

281279
complete(&dreq->completion);
282280

281+
igrab(inode);
283282
nfs_direct_req_release(dreq);
283+
inode_dio_end(inode);
284+
iput(inode);
284285
}
285286

286287
static void nfs_direct_read_completion(struct nfs_pgio_header *hdr)
@@ -410,8 +411,10 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
410411
* generic layer handle the completion.
411412
*/
412413
if (requested_bytes == 0) {
413-
inode_dio_end(inode);
414+
igrab(inode);
414415
nfs_direct_req_release(dreq);
416+
inode_dio_end(inode);
417+
iput(inode);
415418
return result < 0 ? result : -EIO;
416419
}
417420

@@ -864,8 +867,10 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
864867
* generic layer handle the completion.
865868
*/
866869
if (requested_bytes == 0) {
867-
inode_dio_end(inode);
870+
igrab(inode);
868871
nfs_direct_req_release(dreq);
872+
inode_dio_end(inode);
873+
iput(inode);
869874
return result < 0 ? result : -EIO;
870875
}
871876

fs/nfs/file.c

+1
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ nfs_file_release(struct inode *inode, struct file *filp)
8383
dprintk("NFS: release(%pD2)\n", filp);
8484

8585
nfs_inc_stats(inode, NFSIOS_VFSRELEASE);
86+
inode_dio_wait(inode);
8687
nfs_file_clear_open_context(filp);
8788
return 0;
8889
}

fs/nfs/flexfilelayout/flexfilelayout.c

+7-4
Original file line numberDiff line numberDiff line change
@@ -907,9 +907,8 @@ ff_layout_pg_init_write(struct nfs_pageio_descriptor *pgio,
907907
goto out_mds;
908908

909909
/* Use a direct mapping of ds_idx to pgio mirror_idx */
910-
if (WARN_ON_ONCE(pgio->pg_mirror_count !=
911-
FF_LAYOUT_MIRROR_COUNT(pgio->pg_lseg)))
912-
goto out_mds;
910+
if (pgio->pg_mirror_count != FF_LAYOUT_MIRROR_COUNT(pgio->pg_lseg))
911+
goto out_eagain;
913912

914913
for (i = 0; i < pgio->pg_mirror_count; i++) {
915914
mirror = FF_LAYOUT_COMP(pgio->pg_lseg, i);
@@ -931,7 +930,10 @@ ff_layout_pg_init_write(struct nfs_pageio_descriptor *pgio,
931930
(NFS_MOUNT_SOFT|NFS_MOUNT_SOFTERR))
932931
pgio->pg_maxretrans = io_maxretrans;
933932
return;
934-
933+
out_eagain:
934+
pnfs_generic_pg_cleanup(pgio);
935+
pgio->pg_error = -EAGAIN;
936+
return;
935937
out_mds:
936938
trace_pnfs_mds_fallback_pg_init_write(pgio->pg_inode,
937939
0, NFS4_MAX_UINT64, IOMODE_RW,
@@ -941,6 +943,7 @@ ff_layout_pg_init_write(struct nfs_pageio_descriptor *pgio,
941943
pgio->pg_lseg = NULL;
942944
pgio->pg_maxretrans = 0;
943945
nfs_pageio_reset_write_mds(pgio);
946+
pgio->pg_error = -EAGAIN;
944947
}
945948

946949
static unsigned int

fs/nfs/nfs4namespace.c

+1
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@ static int try_location(struct fs_context *fc,
308308
if (IS_ERR(export_path))
309309
return PTR_ERR(export_path);
310310

311+
kfree(ctx->nfs_server.export_path);
311312
ctx->nfs_server.export_path = export_path;
312313

313314
source = kmalloc(len + 1 + ctx->nfs_server.export_path_len + 1,

net/sunrpc/rpc_pipe.c

+1
Original file line numberDiff line numberDiff line change
@@ -1317,6 +1317,7 @@ rpc_gssd_dummy_populate(struct dentry *root, struct rpc_pipe *pipe_data)
13171317
q.len = strlen(gssd_dummy_clnt_dir[0].name);
13181318
clnt_dentry = d_hash_and_lookup(gssd_dentry, &q);
13191319
if (!clnt_dentry) {
1320+
__rpc_depopulate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1);
13201321
pipe_dentry = ERR_PTR(-ENOENT);
13211322
goto out;
13221323
}

net/sunrpc/xdr.c

+4
Original file line numberDiff line numberDiff line change
@@ -1118,6 +1118,7 @@ xdr_buf_subsegment(struct xdr_buf *buf, struct xdr_buf *subbuf,
11181118
base = 0;
11191119
} else {
11201120
base -= buf->head[0].iov_len;
1121+
subbuf->head[0].iov_base = buf->head[0].iov_base;
11211122
subbuf->head[0].iov_len = 0;
11221123
}
11231124

@@ -1130,6 +1131,8 @@ xdr_buf_subsegment(struct xdr_buf *buf, struct xdr_buf *subbuf,
11301131
base = 0;
11311132
} else {
11321133
base -= buf->page_len;
1134+
subbuf->pages = buf->pages;
1135+
subbuf->page_base = 0;
11331136
subbuf->page_len = 0;
11341137
}
11351138

@@ -1141,6 +1144,7 @@ xdr_buf_subsegment(struct xdr_buf *buf, struct xdr_buf *subbuf,
11411144
base = 0;
11421145
} else {
11431146
base -= buf->tail[0].iov_len;
1147+
subbuf->tail[0].iov_base = buf->tail[0].iov_base;
11441148
subbuf->tail[0].iov_len = 0;
11451149
}
11461150

net/sunrpc/xprtrdma/frwr_ops.c

+4-4
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,7 @@ static void frwr_wc_fastreg(struct ib_cq *cq, struct ib_wc *wc)
367367
trace_xprtrdma_wc_fastreg(wc, frwr);
368368
/* The MR will get recycled when the associated req is retransmitted */
369369

370-
rpcrdma_flush_disconnect(cq, wc);
370+
rpcrdma_flush_disconnect(cq->cq_context, wc);
371371
}
372372

373373
/**
@@ -452,7 +452,7 @@ static void frwr_wc_localinv(struct ib_cq *cq, struct ib_wc *wc)
452452
trace_xprtrdma_wc_li(wc, frwr);
453453
__frwr_release_mr(wc, mr);
454454

455-
rpcrdma_flush_disconnect(cq, wc);
455+
rpcrdma_flush_disconnect(cq->cq_context, wc);
456456
}
457457

458458
/**
@@ -474,7 +474,7 @@ static void frwr_wc_localinv_wake(struct ib_cq *cq, struct ib_wc *wc)
474474
__frwr_release_mr(wc, mr);
475475
complete(&frwr->fr_linv_done);
476476

477-
rpcrdma_flush_disconnect(cq, wc);
477+
rpcrdma_flush_disconnect(cq->cq_context, wc);
478478
}
479479

480480
/**
@@ -582,7 +582,7 @@ static void frwr_wc_localinv_done(struct ib_cq *cq, struct ib_wc *wc)
582582
smp_rmb();
583583
rpcrdma_complete_rqst(rep);
584584

585-
rpcrdma_flush_disconnect(cq, wc);
585+
rpcrdma_flush_disconnect(cq->cq_context, wc);
586586
}
587587

588588
/**

net/sunrpc/xprtrdma/rpc_rdma.c

+3-6
Original file line numberDiff line numberDiff line change
@@ -1349,8 +1349,7 @@ rpcrdma_decode_error(struct rpcrdma_xprt *r_xprt, struct rpcrdma_rep *rep,
13491349
be32_to_cpup(p), be32_to_cpu(rep->rr_xid));
13501350
}
13511351

1352-
r_xprt->rx_stats.bad_reply_count++;
1353-
return -EREMOTEIO;
1352+
return -EIO;
13541353
}
13551354

13561355
/* Perform XID lookup, reconstruction of the RPC reply, and
@@ -1387,13 +1386,11 @@ void rpcrdma_complete_rqst(struct rpcrdma_rep *rep)
13871386
spin_unlock(&xprt->queue_lock);
13881387
return;
13891388

1390-
/* If the incoming reply terminated a pending RPC, the next
1391-
* RPC call will post a replacement receive buffer as it is
1392-
* being marshaled.
1393-
*/
13941389
out_badheader:
13951390
trace_xprtrdma_reply_hdr(rep);
13961391
r_xprt->rx_stats.bad_reply_count++;
1392+
rqst->rq_task->tk_status = status;
1393+
status = 0;
13971394
goto out;
13981395
}
13991396

net/sunrpc/xprtrdma/transport.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ xprt_rdma_connect_worker(struct work_struct *work)
242242

243243
rc = rpcrdma_xprt_connect(r_xprt);
244244
xprt_clear_connecting(xprt);
245-
if (r_xprt->rx_ep && r_xprt->rx_ep->re_connect_status > 0) {
245+
if (!rc) {
246246
xprt->connect_cookie++;
247247
xprt->stat.connect_count++;
248248
xprt->stat.connect_time += (long)jiffies -

net/sunrpc/xprtrdma/verbs.c

+42-29
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ static void rpcrdma_rep_destroy(struct rpcrdma_rep *rep);
8484
static void rpcrdma_reps_unmap(struct rpcrdma_xprt *r_xprt);
8585
static void rpcrdma_mrs_create(struct rpcrdma_xprt *r_xprt);
8686
static void rpcrdma_mrs_destroy(struct rpcrdma_xprt *r_xprt);
87-
static int rpcrdma_ep_destroy(struct rpcrdma_ep *ep);
87+
static void rpcrdma_ep_get(struct rpcrdma_ep *ep);
88+
static int rpcrdma_ep_put(struct rpcrdma_ep *ep);
8889
static struct rpcrdma_regbuf *
8990
rpcrdma_regbuf_alloc(size_t size, enum dma_data_direction direction,
9091
gfp_t flags);
@@ -97,7 +98,8 @@ static void rpcrdma_regbuf_free(struct rpcrdma_regbuf *rb);
9798
*/
9899
static void rpcrdma_xprt_drain(struct rpcrdma_xprt *r_xprt)
99100
{
100-
struct rdma_cm_id *id = r_xprt->rx_ep->re_id;
101+
struct rpcrdma_ep *ep = r_xprt->rx_ep;
102+
struct rdma_cm_id *id = ep->re_id;
101103

102104
/* Flush Receives, then wait for deferred Reply work
103105
* to complete.
@@ -108,6 +110,8 @@ static void rpcrdma_xprt_drain(struct rpcrdma_xprt *r_xprt)
108110
* local invalidations.
109111
*/
110112
ib_drain_sq(id->qp);
113+
114+
rpcrdma_ep_put(ep);
111115
}
112116

113117
/**
@@ -126,23 +130,27 @@ static void rpcrdma_qp_event_handler(struct ib_event *event, void *context)
126130
trace_xprtrdma_qp_event(ep, event);
127131
}
128132

133+
/* Ensure xprt_force_disconnect() is invoked exactly once when a
134+
* connection is closed or lost. (The important thing is it needs
135+
* to be invoked "at least" once).
136+
*/
137+
static void rpcrdma_force_disconnect(struct rpcrdma_ep *ep)
138+
{
139+
if (atomic_add_unless(&ep->re_force_disconnect, 1, 1))
140+
xprt_force_disconnect(ep->re_xprt);
141+
}
142+
129143
/**
130144
* rpcrdma_flush_disconnect - Disconnect on flushed completion
131-
* @cq: completion queue
145+
* @r_xprt: transport to disconnect
132146
* @wc: work completion entry
133147
*
134148
* Must be called in process context.
135149
*/
136-
void rpcrdma_flush_disconnect(struct ib_cq *cq, struct ib_wc *wc)
150+
void rpcrdma_flush_disconnect(struct rpcrdma_xprt *r_xprt, struct ib_wc *wc)
137151
{
138-
struct rpcrdma_xprt *r_xprt = cq->cq_context;
139-
struct rpc_xprt *xprt = &r_xprt->rx_xprt;
140-
141-
if (wc->status != IB_WC_SUCCESS &&
142-
r_xprt->rx_ep->re_connect_status == 1) {
143-
r_xprt->rx_ep->re_connect_status = -ECONNABORTED;
144-
xprt_force_disconnect(xprt);
145-
}
152+
if (wc->status != IB_WC_SUCCESS)
153+
rpcrdma_force_disconnect(r_xprt->rx_ep);
146154
}
147155

148156
/**
@@ -156,11 +164,12 @@ static void rpcrdma_wc_send(struct ib_cq *cq, struct ib_wc *wc)
156164
struct ib_cqe *cqe = wc->wr_cqe;
157165
struct rpcrdma_sendctx *sc =
158166
container_of(cqe, struct rpcrdma_sendctx, sc_cqe);
167+
struct rpcrdma_xprt *r_xprt = cq->cq_context;
159168

160169
/* WARNING: Only wr_cqe and status are reliable at this point */
161170
trace_xprtrdma_wc_send(sc, wc);
162-
rpcrdma_sendctx_put_locked((struct rpcrdma_xprt *)cq->cq_context, sc);
163-
rpcrdma_flush_disconnect(cq, wc);
171+
rpcrdma_sendctx_put_locked(r_xprt, sc);
172+
rpcrdma_flush_disconnect(r_xprt, wc);
164173
}
165174

166175
/**
@@ -195,7 +204,7 @@ static void rpcrdma_wc_receive(struct ib_cq *cq, struct ib_wc *wc)
195204
return;
196205

197206
out_flushed:
198-
rpcrdma_flush_disconnect(cq, wc);
207+
rpcrdma_flush_disconnect(r_xprt, wc);
199208
rpcrdma_rep_destroy(rep);
200209
}
201210

@@ -239,7 +248,6 @@ rpcrdma_cm_event_handler(struct rdma_cm_id *id, struct rdma_cm_event *event)
239248
{
240249
struct sockaddr *sap = (struct sockaddr *)&id->route.addr.dst_addr;
241250
struct rpcrdma_ep *ep = id->context;
242-
struct rpc_xprt *xprt = ep->re_xprt;
243251

244252
might_sleep();
245253

@@ -263,10 +271,9 @@ rpcrdma_cm_event_handler(struct rdma_cm_id *id, struct rdma_cm_event *event)
263271
/* fall through */
264272
case RDMA_CM_EVENT_ADDR_CHANGE:
265273
ep->re_connect_status = -ENODEV;
266-
xprt_force_disconnect(xprt);
267274
goto disconnected;
268275
case RDMA_CM_EVENT_ESTABLISHED:
269-
kref_get(&ep->re_kref);
276+
rpcrdma_ep_get(ep);
270277
ep->re_connect_status = 1;
271278
rpcrdma_update_cm_private(ep, &event->param.conn);
272279
trace_xprtrdma_inline_thresh(ep);
@@ -288,8 +295,8 @@ rpcrdma_cm_event_handler(struct rdma_cm_id *id, struct rdma_cm_event *event)
288295
case RDMA_CM_EVENT_DISCONNECTED:
289296
ep->re_connect_status = -ECONNABORTED;
290297
disconnected:
291-
xprt_force_disconnect(xprt);
292-
return rpcrdma_ep_destroy(ep);
298+
rpcrdma_force_disconnect(ep);
299+
return rpcrdma_ep_put(ep);
293300
default:
294301
break;
295302
}
@@ -345,7 +352,7 @@ static struct rdma_cm_id *rpcrdma_create_id(struct rpcrdma_xprt *r_xprt,
345352
return ERR_PTR(rc);
346353
}
347354

348-
static void rpcrdma_ep_put(struct kref *kref)
355+
static void rpcrdma_ep_destroy(struct kref *kref)
349356
{
350357
struct rpcrdma_ep *ep = container_of(kref, struct rpcrdma_ep, re_kref);
351358

@@ -369,13 +376,18 @@ static void rpcrdma_ep_put(struct kref *kref)
369376
module_put(THIS_MODULE);
370377
}
371378

379+
static noinline void rpcrdma_ep_get(struct rpcrdma_ep *ep)
380+
{
381+
kref_get(&ep->re_kref);
382+
}
383+
372384
/* Returns:
373385
* %0 if @ep still has a positive kref count, or
374386
* %1 if @ep was destroyed successfully.
375387
*/
376-
static int rpcrdma_ep_destroy(struct rpcrdma_ep *ep)
388+
static noinline int rpcrdma_ep_put(struct rpcrdma_ep *ep)
377389
{
378-
return kref_put(&ep->re_kref, rpcrdma_ep_put);
390+
return kref_put(&ep->re_kref, rpcrdma_ep_destroy);
379391
}
380392

381393
static int rpcrdma_ep_create(struct rpcrdma_xprt *r_xprt)
@@ -492,7 +504,7 @@ static int rpcrdma_ep_create(struct rpcrdma_xprt *r_xprt)
492504
return 0;
493505

494506
out_destroy:
495-
rpcrdma_ep_destroy(ep);
507+
rpcrdma_ep_put(ep);
496508
rdma_destroy_id(id);
497509
out_free:
498510
kfree(ep);
@@ -519,10 +531,13 @@ int rpcrdma_xprt_connect(struct rpcrdma_xprt *r_xprt)
519531
return rc;
520532
ep = r_xprt->rx_ep;
521533

522-
ep->re_connect_status = 0;
523534
xprt_clear_connected(xprt);
524-
525535
rpcrdma_reset_cwnd(r_xprt);
536+
537+
/* Bump the ep's reference count while there are
538+
* outstanding Receives.
539+
*/
540+
rpcrdma_ep_get(ep);
526541
rpcrdma_post_recvs(r_xprt, true);
527542

528543
rc = rpcrdma_sendctxs_create(r_xprt);
@@ -552,8 +567,6 @@ int rpcrdma_xprt_connect(struct rpcrdma_xprt *r_xprt)
552567
rpcrdma_mrs_create(r_xprt);
553568

554569
out:
555-
if (rc)
556-
ep->re_connect_status = rc;
557570
trace_xprtrdma_connect(r_xprt, rc);
558571
return rc;
559572
}
@@ -587,7 +600,7 @@ void rpcrdma_xprt_disconnect(struct rpcrdma_xprt *r_xprt)
587600
rpcrdma_mrs_destroy(r_xprt);
588601
rpcrdma_sendctxs_destroy(r_xprt);
589602

590-
if (rpcrdma_ep_destroy(ep))
603+
if (rpcrdma_ep_put(ep))
591604
rdma_destroy_id(id);
592605

593606
r_xprt->rx_ep = NULL;

0 commit comments

Comments
 (0)