Commit cbf3a2cb authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull NFS client fixes from Anna Schumaker:
 "Stable fixes:
   - Revert "SUNRPC dont update timeout value on connection reset"
   - NFSv4: Fix a state manager thread deadlock regression

  Fixes:
   - Fix potential NULL pointer dereference in nfs_inode_remove_request()
   - Fix rare NULL pointer dereference in xs_tcp_tls_setup_socket()
   - Fix long delay before failing a TLS mount when server does not
     support TLS
   - Fix various NFS state manager issues"

* tag 'nfs-for-6.6-3' of git://git.linux-nfs.org/projects/anna/linux-nfs:
  nfs: decrement nrequests counter before releasing the req
  SUNRPC/TLS: Lock the lower_xprt during the tls handshake
  Revert "SUNRPC dont update timeout value on connection reset"
  NFSv4: Fix a state manager thread deadlock regression
  NFSv4: Fix a nfs4_state_manager() race
  SUNRPC: Fail quickly when server does not recognize TLS
parents 7cccbeca dd1b2026
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -10622,7 +10622,9 @@ static void nfs4_disable_swap(struct inode *inode)
	 */
	struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;

	nfs4_schedule_state_manager(clp);
	set_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state);
	clear_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state);
	wake_up_var(&clp->cl_state);
}

static const struct inode_operations nfs4_dir_inode_operations = {
+33 −12
Original line number Diff line number Diff line
@@ -1209,16 +1209,26 @@ void nfs4_schedule_state_manager(struct nfs_client *clp)
{
	struct task_struct *task;
	char buf[INET6_ADDRSTRLEN + sizeof("-manager") + 1];
	struct rpc_clnt *clnt = clp->cl_rpcclient;
	bool swapon = false;

	if (clp->cl_rpcclient->cl_shutdown)
	if (clnt->cl_shutdown)
		return;

	set_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state);
	if (test_and_set_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state) != 0) {

	if (atomic_read(&clnt->cl_swapper)) {
		swapon = !test_and_set_bit(NFS4CLNT_MANAGER_AVAILABLE,
					   &clp->cl_state);
		if (!swapon) {
			wake_up_var(&clp->cl_state);
			return;
		}
	set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state);
	}

	if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
		return;

	__module_get(THIS_MODULE);
	refcount_inc(&clp->cl_count);

@@ -1235,8 +1245,9 @@ void nfs4_schedule_state_manager(struct nfs_client *clp)
			__func__, PTR_ERR(task));
		if (!nfs_client_init_is_complete(clp))
			nfs_mark_client_ready(clp, PTR_ERR(task));
		nfs4_clear_state_manager_bit(clp);
		if (swapon)
			clear_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state);
		nfs4_clear_state_manager_bit(clp);
		nfs_put_client(clp);
		module_put(THIS_MODULE);
	}
@@ -2703,6 +2714,13 @@ static void nfs4_state_manager(struct nfs_client *clp)
		nfs4_end_drain_session(clp);
		nfs4_clear_state_manager_bit(clp);

		if (test_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state) &&
		    !test_and_set_bit(NFS4CLNT_MANAGER_RUNNING,
				      &clp->cl_state)) {
			memflags = memalloc_nofs_save();
			continue;
		}

		if (!test_and_set_bit(NFS4CLNT_RECALL_RUNNING, &clp->cl_state)) {
			if (test_and_clear_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) {
				nfs_client_return_marked_delegations(clp);
@@ -2741,22 +2759,25 @@ static int nfs4_run_state_manager(void *ptr)

	allow_signal(SIGKILL);
again:
	set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state);
	nfs4_state_manager(clp);
	if (atomic_read(&cl->cl_swapper)) {

	if (test_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state) &&
	    !test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state)) {
		wait_var_event_interruptible(&clp->cl_state,
					     test_bit(NFS4CLNT_RUN_MANAGER,
						      &clp->cl_state));
		if (atomic_read(&cl->cl_swapper) &&
		    test_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state))
		if (!atomic_read(&cl->cl_swapper))
			clear_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state);
		if (refcount_read(&clp->cl_count) > 1 && !signalled() &&
		    !test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state))
			goto again;
		/* Either no longer a swapper, or were signalled */
	}
		clear_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state);
	}

	if (refcount_read(&clp->cl_count) > 1 && !signalled() &&
	    test_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state) &&
	    !test_and_set_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state))
	    !test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state))
		goto again;

	nfs_put_client(clp);
+1 −1
Original line number Diff line number Diff line
@@ -802,8 +802,8 @@ static void nfs_inode_remove_request(struct nfs_page *req)
	}

	if (test_and_clear_bit(PG_INODE_REF, &req->wb_flags)) {
		nfs_release_request(req);
		atomic_long_dec(&NFS_I(nfs_page_to_inode(req))->nrequests);
		nfs_release_request(req);
	}
}

+8 −3
Original line number Diff line number Diff line
@@ -769,9 +769,14 @@ int rpcauth_wrap_req(struct rpc_task *task, struct xdr_stream *xdr)
 * @task: controlling RPC task
 * @xdr: xdr_stream containing RPC Reply header
 *
 * On success, @xdr is updated to point past the verifier and
 * zero is returned. Otherwise, @xdr is in an undefined state
 * and a negative errno is returned.
 * Return values:
 *   %0: Verifier is valid. @xdr now points past the verifier.
 *   %-EIO: Verifier is corrupted or message ended early.
 *   %-EACCES: Verifier is intact but not valid.
 *   %-EPROTONOSUPPORT: Server does not support the requested auth type.
 *
 * When a negative errno is returned, @xdr is left in an undefined
 * state.
 */
int
rpcauth_checkverf(struct rpc_task *task, struct xdr_stream *xdr)
+2 −2
Original line number Diff line number Diff line
@@ -129,9 +129,9 @@ static int tls_validate(struct rpc_task *task, struct xdr_stream *xdr)
	if (*p != rpc_auth_null)
		return -EIO;
	if (xdr_stream_decode_opaque_inline(xdr, &str, starttls_len) != starttls_len)
		return -EIO;
		return -EPROTONOSUPPORT;
	if (memcmp(str, starttls_token, starttls_len))
		return -EIO;
		return -EPROTONOSUPPORT;
	return 0;
}

Loading