Skip to content

Commit 53663f4

Browse files
committed
Merge tag 'nfs-for-6.5-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client fixes from Trond Myklebust: - fix a use after free in nfs_direct_join_group() (Cc: stable) - fix sysfs server name memory leak - fix lock recovery hang in NFSv4.0 - fix page free in the error path for nfs42_proc_getxattr() and __nfs4_get_acl_uncached() - SUNRPC/rdma: fix receive buffer dma-mapping after a server disconnect * tag 'nfs-for-6.5-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: xprtrdma: Remap Receive buffers after a reconnect NFSv4: fix out path in __nfs4_get_acl_uncached NFSv4.2: fix error handling in nfs42_proc_getxattr NFS: Fix sysfs server name memory leak NFS: Fix a use after free in nfs_direct_join_group() NFSv4: Fix dropped lock for racing OPEN and delegation return
2 parents e4311f7 + 895cedc commit 53663f4

File tree

5 files changed

+35
-23
lines changed

5 files changed

+35
-23
lines changed

fs/nfs/direct.c

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -472,20 +472,26 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter,
472472
return result;
473473
}
474474

475-
static void
476-
nfs_direct_join_group(struct list_head *list, struct inode *inode)
475+
static void nfs_direct_join_group(struct list_head *list, struct inode *inode)
477476
{
478-
struct nfs_page *req, *next;
477+
struct nfs_page *req, *subreq;
479478

480479
list_for_each_entry(req, list, wb_list) {
481-
if (req->wb_head != req || req->wb_this_page == req)
480+
if (req->wb_head != req)
482481
continue;
483-
for (next = req->wb_this_page;
484-
next != req->wb_head;
485-
next = next->wb_this_page) {
486-
nfs_list_remove_request(next);
487-
nfs_release_request(next);
488-
}
482+
subreq = req->wb_this_page;
483+
if (subreq == req)
484+
continue;
485+
do {
486+
/*
487+
* Remove subrequests from this list before freeing
488+
* them in the call to nfs_join_page_group().
489+
*/
490+
if (!list_empty(&subreq->wb_list)) {
491+
nfs_list_remove_request(subreq);
492+
nfs_release_request(subreq);
493+
}
494+
} while ((subreq = subreq->wb_this_page) != req);
489495
nfs_join_page_group(req, inode);
490496
}
491497
}

fs/nfs/nfs42proc.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1377,7 +1377,6 @@ ssize_t nfs42_proc_getxattr(struct inode *inode, const char *name,
13771377
for (i = 0; i < np; i++) {
13781378
pages[i] = alloc_page(GFP_KERNEL);
13791379
if (!pages[i]) {
1380-
np = i + 1;
13811380
err = -ENOMEM;
13821381
goto out;
13831382
}
@@ -1401,8 +1400,8 @@ ssize_t nfs42_proc_getxattr(struct inode *inode, const char *name,
14011400
} while (exception.retry);
14021401

14031402
out:
1404-
while (--np >= 0)
1405-
__free_page(pages[np]);
1403+
while (--i >= 0)
1404+
__free_page(pages[i]);
14061405
kfree(pages);
14071406

14081407
return err;

fs/nfs/nfs4proc.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6004,9 +6004,8 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf,
60046004
out_ok:
60056005
ret = res.acl_len;
60066006
out_free:
6007-
for (i = 0; i < npages; i++)
6008-
if (pages[i])
6009-
__free_page(pages[i]);
6007+
while (--i >= 0)
6008+
__free_page(pages[i]);
60106009
if (res.acl_scratch)
60116010
__free_page(res.acl_scratch);
60126011
kfree(pages);
@@ -7181,8 +7180,15 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata)
71817180
} else if (!nfs4_update_lock_stateid(lsp, &data->res.stateid))
71827181
goto out_restart;
71837182
break;
7184-
case -NFS4ERR_BAD_STATEID:
71857183
case -NFS4ERR_OLD_STATEID:
7184+
if (data->arg.new_lock_owner != 0 &&
7185+
nfs4_refresh_open_old_stateid(&data->arg.open_stateid,
7186+
lsp->ls_state))
7187+
goto out_restart;
7188+
if (nfs4_refresh_lock_old_stateid(&data->arg.lock_stateid, lsp))
7189+
goto out_restart;
7190+
fallthrough;
7191+
case -NFS4ERR_BAD_STATEID:
71867192
case -NFS4ERR_STALE_STATEID:
71877193
case -NFS4ERR_EXPIRED:
71887194
if (data->arg.new_lock_owner != 0) {

fs/nfs/sysfs.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,8 +345,10 @@ void nfs_sysfs_move_sb_to_server(struct nfs_server *server)
345345
int ret = -ENOMEM;
346346

347347
s = kasprintf(GFP_KERNEL, "server-%d", server->s_sysfs_id);
348-
if (s)
348+
if (s) {
349349
ret = kobject_rename(&server->kobj, s);
350+
kfree(s);
351+
}
350352
if (ret < 0)
351353
pr_warn("NFS: rename sysfs %s failed (%d)\n",
352354
server->kobj.name, ret);

net/sunrpc/xprtrdma/verbs.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -935,9 +935,6 @@ struct rpcrdma_rep *rpcrdma_rep_create(struct rpcrdma_xprt *r_xprt,
935935
if (!rep->rr_rdmabuf)
936936
goto out_free;
937937

938-
if (!rpcrdma_regbuf_dma_map(r_xprt, rep->rr_rdmabuf))
939-
goto out_free_regbuf;
940-
941938
rep->rr_cid.ci_completion_id =
942939
atomic_inc_return(&r_xprt->rx_ep->re_completion_ids);
943940

@@ -956,8 +953,6 @@ struct rpcrdma_rep *rpcrdma_rep_create(struct rpcrdma_xprt *r_xprt,
956953
spin_unlock(&buf->rb_lock);
957954
return rep;
958955

959-
out_free_regbuf:
960-
rpcrdma_regbuf_free(rep->rr_rdmabuf);
961956
out_free:
962957
kfree(rep);
963958
out:
@@ -1363,6 +1358,10 @@ void rpcrdma_post_recvs(struct rpcrdma_xprt *r_xprt, int needed, bool temp)
13631358
rep = rpcrdma_rep_create(r_xprt, temp);
13641359
if (!rep)
13651360
break;
1361+
if (!rpcrdma_regbuf_dma_map(r_xprt, rep->rr_rdmabuf)) {
1362+
rpcrdma_rep_put(buf, rep);
1363+
break;
1364+
}
13661365

13671366
rep->rr_cid.ci_queue_id = ep->re_attr.recv_cq->res.id;
13681367
trace_xprtrdma_post_recv(rep);

0 commit comments

Comments
 (0)