Commit 53663f41 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
parents e4311f7c 895cedc1
Loading
Loading
Loading
Loading
+16 −10
Original line number Diff line number Diff line
@@ -472,20 +472,26 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter,
	return result;
}

static void
nfs_direct_join_group(struct list_head *list, struct inode *inode)
static void nfs_direct_join_group(struct list_head *list, struct inode *inode)
{
	struct nfs_page *req, *next;
	struct nfs_page *req, *subreq;

	list_for_each_entry(req, list, wb_list) {
		if (req->wb_head != req || req->wb_this_page == req)
		if (req->wb_head != req)
			continue;
		subreq = req->wb_this_page;
		if (subreq == req)
			continue;
		for (next = req->wb_this_page;
				next != req->wb_head;
				next = next->wb_this_page) {
			nfs_list_remove_request(next);
			nfs_release_request(next);
		do {
			/*
			 * Remove subrequests from this list before freeing
			 * them in the call to nfs_join_page_group().
			 */
			if (!list_empty(&subreq->wb_list)) {
				nfs_list_remove_request(subreq);
				nfs_release_request(subreq);
			}
		} while ((subreq = subreq->wb_this_page) != req);
		nfs_join_page_group(req, inode);
	}
}
+2 −3
Original line number Diff line number Diff line
@@ -1377,7 +1377,6 @@ ssize_t nfs42_proc_getxattr(struct inode *inode, const char *name,
	for (i = 0; i < np; i++) {
		pages[i] = alloc_page(GFP_KERNEL);
		if (!pages[i]) {
			np = i + 1;
			err = -ENOMEM;
			goto out;
		}
@@ -1401,8 +1400,8 @@ ssize_t nfs42_proc_getxattr(struct inode *inode, const char *name,
	} while (exception.retry);

out:
	while (--np >= 0)
		__free_page(pages[np]);
	while (--i >= 0)
		__free_page(pages[i]);
	kfree(pages);

	return err;
+10 −4
Original line number Diff line number Diff line
@@ -6004,8 +6004,7 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf,
out_ok:
	ret = res.acl_len;
out_free:
	for (i = 0; i < npages; i++)
		if (pages[i])
	while (--i >= 0)
		__free_page(pages[i]);
	if (res.acl_scratch)
		__free_page(res.acl_scratch);
@@ -7181,8 +7180,15 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata)
		} else if (!nfs4_update_lock_stateid(lsp, &data->res.stateid))
			goto out_restart;
		break;
	case -NFS4ERR_BAD_STATEID:
	case -NFS4ERR_OLD_STATEID:
		if (data->arg.new_lock_owner != 0 &&
			nfs4_refresh_open_old_stateid(&data->arg.open_stateid,
					lsp->ls_state))
			goto out_restart;
		if (nfs4_refresh_lock_old_stateid(&data->arg.lock_stateid, lsp))
			goto out_restart;
		fallthrough;
	case -NFS4ERR_BAD_STATEID:
	case -NFS4ERR_STALE_STATEID:
	case -NFS4ERR_EXPIRED:
		if (data->arg.new_lock_owner != 0) {
+3 −1
Original line number Diff line number Diff line
@@ -345,8 +345,10 @@ void nfs_sysfs_move_sb_to_server(struct nfs_server *server)
	int ret = -ENOMEM;

	s = kasprintf(GFP_KERNEL, "server-%d", server->s_sysfs_id);
	if (s)
	if (s) {
		ret = kobject_rename(&server->kobj, s);
		kfree(s);
	}
	if (ret < 0)
		pr_warn("NFS: rename sysfs %s failed (%d)\n",
					server->kobj.name, ret);
+4 −5
Original line number Diff line number Diff line
@@ -935,9 +935,6 @@ struct rpcrdma_rep *rpcrdma_rep_create(struct rpcrdma_xprt *r_xprt,
	if (!rep->rr_rdmabuf)
		goto out_free;

	if (!rpcrdma_regbuf_dma_map(r_xprt, rep->rr_rdmabuf))
		goto out_free_regbuf;

	rep->rr_cid.ci_completion_id =
		atomic_inc_return(&r_xprt->rx_ep->re_completion_ids);

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

out_free_regbuf:
	rpcrdma_regbuf_free(rep->rr_rdmabuf);
out_free:
	kfree(rep);
out:
@@ -1363,6 +1358,10 @@ void rpcrdma_post_recvs(struct rpcrdma_xprt *r_xprt, int needed, bool temp)
			rep = rpcrdma_rep_create(r_xprt, temp);
		if (!rep)
			break;
		if (!rpcrdma_regbuf_dma_map(r_xprt, rep->rr_rdmabuf)) {
			rpcrdma_rep_put(buf, rep);
			break;
		}

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