Commit cbf3a2cb authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'nfs-for-6.6-3' of git://git.linux-nfs.org/projects/anna/linux-nfs

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
......@@ -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 = {
......
......@@ -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);
......
......@@ -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);
}
}
......
......@@ -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)
......
......@@ -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;
}
......
......@@ -2476,7 +2476,6 @@ call_status(struct rpc_task *task)
goto out_exit;
}
task->tk_action = call_encode;
if (status != -ECONNRESET && status != -ECONNABORTED)
rpc_check_timeout(task);
return;
out_exit:
......@@ -2725,7 +2724,15 @@ rpc_decode_header(struct rpc_task *task, struct xdr_stream *xdr)
out_verifier:
trace_rpc_bad_verifier(task);
switch (error) {
case -EPROTONOSUPPORT:
goto out_err;
case -EACCES:
/* Re-encode with a fresh cred */
fallthrough;
default:
goto out_garbage;
}
out_msg_denied:
error = -EACCES;
......
......@@ -2672,6 +2672,10 @@ static void xs_tcp_tls_setup_socket(struct work_struct *work)
rcu_read_lock();
lower_xprt = rcu_dereference(lower_clnt->cl_xprt);
rcu_read_unlock();
if (wait_on_bit_lock(&lower_xprt->state, XPRT_LOCKED, TASK_KILLABLE))
goto out_unlock;
status = xs_tls_handshake_sync(lower_xprt, &upper_xprt->xprtsec);
if (status) {
trace_rpc_tls_not_started(upper_clnt, upper_xprt);
......@@ -2681,6 +2685,7 @@ static void xs_tcp_tls_setup_socket(struct work_struct *work)
status = xs_tcp_tls_finish_connecting(lower_xprt, upper_transport);
if (status)
goto out_close;
xprt_release_write(lower_xprt, NULL);
trace_rpc_socket_connect(upper_xprt, upper_transport->sock, 0);
if (!xprt_test_and_set_connected(upper_xprt)) {
......@@ -2702,6 +2707,7 @@ static void xs_tcp_tls_setup_socket(struct work_struct *work)
return;
out_close:
xprt_release_write(lower_xprt, NULL);
rpc_shutdown_client(lower_clnt);
/* xprt_force_disconnect() wakes tasks with a fixed tk_status code.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment