Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

NFS: Use nlmclnt_shutdown_rpc_clnt() to safely shut down NLM

A race condition exists in shutdown_store() when writing to the sysfs
"shutdown" file concurrently with nlm_shutdown_hosts_net(). Without
synchronization, the following sequence can occur:

1. shutdown_store() reads server->nlm_host (non-NULL)
2. nlm_shutdown_hosts_net() acquires nlm_host_mutex, calls
rpc_shutdown_client(), sets h_rpcclnt to NULL, and potentially
frees the host via nlm_gc_hosts()
3. shutdown_store() dereferences the now-stale or freed host

Introduce nlmclnt_shutdown_rpc_clnt(), which acquires nlm_host_mutex
before accessing h_rpcclnt. This synchronizes with
nlm_shutdown_hosts_net() and ensures the rpc_clnt pointer remains
valid during the shutdown operation.

This change also improves API layering: NFS client code no longer
needs to include the internal lockd header to access nlm_host fields.
The new helper resides in bind.h alongside other public lockd
interfaces.

Reported-by: Jeff Layton <jlayton@kernel.org>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>

+32 -2
+29
fs/lockd/host.c
··· 306 306 } 307 307 } 308 308 309 + /* Callback for rpc_cancel_tasks() - matches all tasks for cancellation */ 310 + static bool nlmclnt_match_all(const struct rpc_task *task, const void *data) 311 + { 312 + return true; 313 + } 314 + 315 + /** 316 + * nlmclnt_shutdown_rpc_clnt - safely shut down NLM client RPC operations 317 + * @host: nlm_host to shut down 318 + * 319 + * Cancels outstanding RPC tasks and marks the client as shut down. 320 + * Synchronizes with nlmclnt_release_host() via nlm_host_mutex to prevent 321 + * races between shutdown and host destruction. Safe to call if h_rpcclnt 322 + * is NULL or already shut down. 323 + */ 324 + void nlmclnt_shutdown_rpc_clnt(struct nlm_host *host) 325 + { 326 + struct rpc_clnt *clnt; 327 + 328 + mutex_lock(&nlm_host_mutex); 329 + clnt = host->h_rpcclnt; 330 + if (clnt) { 331 + clnt->cl_shutdown = 1; 332 + rpc_cancel_tasks(clnt, -EIO, nlmclnt_match_all, NULL); 333 + } 334 + mutex_unlock(&nlm_host_mutex); 335 + } 336 + EXPORT_SYMBOL_GPL(nlmclnt_shutdown_rpc_clnt); 337 + 309 338 /** 310 339 * nlmsvc_lookup_host - Find an NLM host handle matching a remote client 311 340 * @rqstp: incoming NLM request
+2 -2
fs/nfs/sysfs.c
··· 12 12 #include <linux/string.h> 13 13 #include <linux/nfs_fs.h> 14 14 #include <linux/rcupdate.h> 15 - #include <linux/lockd/lockd.h> 15 + #include <linux/lockd/bind.h> 16 16 17 17 #include "internal.h" 18 18 #include "nfs4_fs.h" ··· 285 285 shutdown_client(server->client_acl); 286 286 287 287 if (server->nlm_host) 288 - shutdown_client(server->nlm_host->h_rpcclnt); 288 + nlmclnt_shutdown_rpc_clnt(server->nlm_host); 289 289 out: 290 290 shutdown_nfs_client(server->nfs_client); 291 291 return count;
+1
include/linux/lockd/bind.h
··· 57 57 extern struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init); 58 58 extern void nlmclnt_done(struct nlm_host *host); 59 59 extern struct rpc_clnt *nlmclnt_rpc_clnt(struct nlm_host *host); 60 + extern void nlmclnt_shutdown_rpc_clnt(struct nlm_host *host); 60 61 61 62 /* 62 63 * NLM client operations provide a means to modify RPC processing of NLM