Commit 29a47f45 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull NFS client bugfixes from Trond Myklebust:
 "Highlights include:

  Stable fixes:
   - fix handling of backchannel binding in BIND_CONN_TO_SESSION

  Bugfixes:
   - Fix a credential use-after-free issue in pnfs_roc()
   - Fix potential posix_acl refcnt leak in nfs3_set_acl
   - defer slow parts of rpc_free_client() to a workqueue
   - Fix an Oopsable race in __nfs_list_for_each_server()
   - Fix trace point use-after-free race
   - Regression: the RDMA client no longer responds to server disconnect
     requests
   - Fix return values of xdr_stream_encode_item_{present, absent}
   - _pnfs_return_layout() must always wait for layoutreturn completion

  Cleanups:
   - Remove unreachable error conditions"

* tag 'nfs-for-5.7-4' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
  NFS: Fix a race in __nfs_list_for_each_server()
  NFSv4.1: fix handling of backchannel binding in BIND_CONN_TO_SESSION
  SUNRPC: defer slow parts of rpc_free_client() to a workqueue.
  NFSv4: Remove unreachable error condition due to rpc_run_task()
  SUNRPC: Remove unreachable error condition
  xprtrdma: Fix use of xdr_stream_encode_item_{present, absent}
  xprtrdma: Fix trace point use-after-free race
  xprtrdma: Restore wake-up-all to rpcrdma_cm_event_handler()
  nfs: Fix potential posix_acl refcnt leak in nfs3_set_acl
  NFS/pnfs: Fix a credential use-after-free issue in pnfs_roc()
  NFS/pnfs: Ensure that _pnfs_return_layout() waits for layoutreturn completion
parents ed6889db 9c07b75b
Loading
Loading
Loading
Loading
+15 −7
Original line number Diff line number Diff line
@@ -253,37 +253,45 @@ int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,

int nfs3_set_acl(struct inode *inode, struct posix_acl *acl, int type)
{
	struct posix_acl *alloc = NULL, *dfacl = NULL;
	struct posix_acl *orig = acl, *dfacl = NULL, *alloc;
	int status;

	if (S_ISDIR(inode->i_mode)) {
		switch(type) {
		case ACL_TYPE_ACCESS:
			alloc = dfacl = get_acl(inode, ACL_TYPE_DEFAULT);
			alloc = get_acl(inode, ACL_TYPE_DEFAULT);
			if (IS_ERR(alloc))
				goto fail;
			dfacl = alloc;
			break;

		case ACL_TYPE_DEFAULT:
			dfacl = acl;
			alloc = acl = get_acl(inode, ACL_TYPE_ACCESS);
			alloc = get_acl(inode, ACL_TYPE_ACCESS);
			if (IS_ERR(alloc))
				goto fail;
			dfacl = acl;
			acl = alloc;
			break;
		}
	}

	if (acl == NULL) {
		alloc = acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
		alloc = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
		if (IS_ERR(alloc))
			goto fail;
		acl = alloc;
	}
	status = __nfs3_proc_setacls(inode, acl, dfacl);
	posix_acl_release(alloc);
out:
	if (acl != orig)
		posix_acl_release(acl);
	if (dfacl != orig)
		posix_acl_release(dfacl);
	return status;

fail:
	return PTR_ERR(alloc);
	status = PTR_ERR(alloc);
	goto out;
}

const struct xattr_handler *nfs3_xattr_handlers[] = {
+9 −2
Original line number Diff line number Diff line
@@ -7891,6 +7891,7 @@ static void
nfs4_bind_one_conn_to_session_done(struct rpc_task *task, void *calldata)
{
	struct nfs41_bind_conn_to_session_args *args = task->tk_msg.rpc_argp;
	struct nfs41_bind_conn_to_session_res *res = task->tk_msg.rpc_resp;
	struct nfs_client *clp = args->client;

	switch (task->tk_status) {
@@ -7899,6 +7900,12 @@ nfs4_bind_one_conn_to_session_done(struct rpc_task *task, void *calldata)
		nfs4_schedule_session_recovery(clp->cl_session,
				task->tk_status);
	}
	if (args->dir == NFS4_CDFC4_FORE_OR_BOTH &&
			res->dir != NFS4_CDFS4_BOTH) {
		rpc_task_close_connection(task);
		if (args->retries++ < MAX_BIND_CONN_TO_SESSION_RETRIES)
			rpc_restart_call(task);
	}
}

static const struct rpc_call_ops nfs4_bind_one_conn_to_session_ops = {
@@ -7921,6 +7928,7 @@ int nfs4_proc_bind_one_conn_to_session(struct rpc_clnt *clnt,
	struct nfs41_bind_conn_to_session_args args = {
		.client = clp,
		.dir = NFS4_CDFC4_FORE_OR_BOTH,
		.retries = 0,
	};
	struct nfs41_bind_conn_to_session_res res;
	struct rpc_message msg = {
@@ -9191,8 +9199,7 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, long *timeout)
	nfs4_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0, 0);

	task = rpc_run_task(&task_setup_data);
	if (IS_ERR(task))
		return ERR_CAST(task);

	status = rpc_wait_for_completion_task(task);
	if (status != 0)
		goto out;
+5 −6
Original line number Diff line number Diff line
@@ -1332,13 +1332,15 @@ _pnfs_return_layout(struct inode *ino)
			!valid_layout) {
		spin_unlock(&ino->i_lock);
		dprintk("NFS: %s no layout segments to return\n", __func__);
		goto out_put_layout_hdr;
		goto out_wait_layoutreturn;
	}

	send = pnfs_prepare_layoutreturn(lo, &stateid, &cred, NULL);
	spin_unlock(&ino->i_lock);
	if (send)
		status = pnfs_send_layoutreturn(lo, &stateid, &cred, IOMODE_ANY, true);
out_wait_layoutreturn:
	wait_on_bit(&lo->plh_flags, NFS_LAYOUT_RETURN, TASK_UNINTERRUPTIBLE);
out_put_layout_hdr:
	pnfs_free_lseg_list(&tmp_list);
	pnfs_put_layout_hdr(lo);
@@ -1456,18 +1458,15 @@ retry:
	/* lo ref dropped in pnfs_roc_release() */
	layoutreturn = pnfs_prepare_layoutreturn(lo, &stateid, &lc_cred, &iomode);
	/* If the creds don't match, we can't compound the layoutreturn */
	if (!layoutreturn)
	if (!layoutreturn || cred_fscmp(cred, lc_cred) != 0)
		goto out_noroc;
	if (cred_fscmp(cred, lc_cred) != 0)
		goto out_noroc_put_cred;

	roc = layoutreturn;
	pnfs_init_layoutreturn_args(args, lo, &stateid, iomode);
	res->lrs_present = 0;
	layoutreturn = false;

out_noroc_put_cred:
	put_cred(lc_cred);

out_noroc:
	spin_unlock(&ino->i_lock);
	rcu_read_unlock();
+1 −1
Original line number Diff line number Diff line
@@ -185,7 +185,7 @@ static int __nfs_list_for_each_server(struct list_head *head,

	rcu_read_lock();
	list_for_each_entry_rcu(server, head, client_link) {
		if (!nfs_sb_active(server->super))
		if (!(server->super && nfs_sb_active(server->super)))
			continue;
		rcu_read_unlock();
		if (last)
+2 −0
Original line number Diff line number Diff line
@@ -1317,11 +1317,13 @@ struct nfs41_impl_id {
	struct nfstime4			date;
};

#define MAX_BIND_CONN_TO_SESSION_RETRIES 3
struct nfs41_bind_conn_to_session_args {
	struct nfs_client		*client;
	struct nfs4_sessionid		sessionid;
	u32				dir;
	bool				use_conn_in_rdma_mode;
	int				retries;
};

struct nfs41_bind_conn_to_session_res {
Loading