nfs: fix race between renewd, umount, and the state manager in V4.1
Subsystems (2)
PATCH 1/1 nfs: fix race between renewd, umount, and the state manager in V4.1
Signed-off-by Alexandros Batsakis <[email protected]>
--- fs/nfs/client.c | 27 +++++++++++++-------------- fs/nfs/nfs4_fs.h | 1 + fs/nfs/nfs4proc.c | 4 ++++ fs/nfs/nfs4state.c | 8 ++++++-- 4 files changed, 24 insertions(+), 16 deletions(-)
fs/nfs/client.c +13 -14
@@ -164,19 +164,6 @@ error_0:return ERR_PTR (err); } -static void nfs4_shutdown_client (struct nfs_client *clp) -{ -#ifdef CONFIG_NFS_V4 -if (__test_and_clear_bit (NFS_CS_RENEWD , &clp->cl_res_state)) -nfs4_kill_renewd (clp); -BUG_ON (!RB_EMPTY_ROOT (&clp->cl_state_owners)); -if (__test_and_clear_bit (NFS_CS_IDMAP , &clp->cl_res_state)) -nfs_idmap_delete (clp); - -rpc_destroy_wait_queue (&clp->cl_rpcwaitq); -#endif -} -/* * Destroy the NFS4 callback service */
@@ -206,6 +193,19 @@ static void nfs4_clear_client_minor_version(struct nfs_client *clp)nfs4_destroy_callback (clp); } +static void nfs4_shutdown_client (struct nfs_client *clp) +{ +#ifdef CONFIG_NFS_V4 +if (__test_and_clear_bit (NFS_CS_RENEWD , &clp->cl_res_state)) +nfs4_kill_renewd (clp); +nfs4_clear_client_minor_version (clp); +if (__test_and_clear_bit (NFS_CS_IDMAP , &clp->cl_res_state)) +nfs_idmap_delete (clp); + +rpc_destroy_wait_queue (&clp->cl_rpcwaitq); +#endif +} +/* * Destroy a shared client record */
@@ -213,7 +213,6 @@ static void nfs_free_client(struct nfs_client *clp) {dprintk ("--> nfs_free_client(%u)\n" , clp->rpc_ops->version); -nfs4_clear_client_minor_version (clp);nfs4_shutdown_client (clp);nfs_fscache_release_client_cookie (clp);
fs/nfs/nfs4_fs.h +1 -0
@@ -262,6 +262,7 @@ extern void nfs4_renew_state(struct work_struct *);/* nfs4state.c */ struct rpc_cred *nfs4_get_setclientid_cred (struct nfs_client *clp);struct rpc_cred *nfs4_get_renew_cred_locked (struct nfs_client *clp); +int nfs4_begin_drain_session (struct nfs_client *clp);#if defined(CONFIG_NFS_V4_1 )struct rpc_cred *nfs4_get_machine_cred_locked (struct nfs_client *clp);struct rpc_cred *nfs4_get_exchange_id_cred (struct nfs_client *clp);
fs/nfs/nfs4proc.c +4 -0
@@ -4728,6 +4728,7 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp)void nfs4_destroy_session (struct nfs4_session *session) { +nfs4_begin_drain_session (session->clp);nfs4_proc_destroy_session (session);dprintk ("%s Destroy backchannel for xprt %p\n" , __func__, session->clp->cl_rpcclient->cl_xprt);
@@ -4996,6 +4997,9 @@ static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred)void nfs41_sequence_call_done (struct rpc_task *task,void *data) {struct nfs_client *clp = (struct nfs_client *)data; + +if (!nfs4_has_session (clp)) +return ;nfs41_sequence_done (clp, task->tk_msg.rpc_resp, task->tk_status);
fs/nfs/nfs4state.c +6 -2
@@ -156,7 +156,7 @@ static void nfs4_end_drain_session(struct nfs_client *clp) } } -static int nfs4_begin_drain_session (struct nfs_client *clp) +int nfs4_begin_drain_session (struct nfs_client *clp) {struct nfs4_session *ses = clp->cl_session;struct nfs4_slot_table *tbl = &ses->fc_slot_table;
@@ -878,7 +878,11 @@ void nfs4_schedule_state_manager(struct nfs_client *clp)if (test_and_set_bit (NFS4CLNT_MANAGER_RUNNING , &clp->cl_state) !=0 )return ;__module_get (THIS_MODULE ); -atomic_inc (&clp->cl_count); +if (!atomic_inc_not_zero (&clp->cl_count)) { +nfs4_clear_state_manager_bit (clp); +module_put (THIS_MODULE ); +return ; + } task =kthread_run (nfs4_run_state_manager, clp,"%s-manager" ,rpc_peeraddr2str (clp->cl_rpcclient,RPC_DISPLAY_ADDR ));
Signature · 1 line
1.6.2.5