diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index a886e692ddd006359aa8b021f053e3b7f9904567..4b1313eda6f5c1dcc08cd782fa236a14e807d84c 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c @@ -59,7 +59,7 @@ module_param_call(callback_tcpport, param_set_port, param_get_int, * This is the callback kernel thread. */ static int -nfs_callback_svc(void *vrqstp) +nfs4_callback_svc(void *vrqstp) { int err, preverr = 0; struct svc_rqst *rqstp = vrqstp; @@ -97,20 +97,12 @@ nfs_callback_svc(void *vrqstp) } /* - * Bring up the callback thread if it is not already up. + * Prepare to bring up the NFSv4 callback service */ -int nfs_callback_up(void) +struct svc_rqst * +nfs4_callback_up(struct svc_serv *serv) { - struct svc_serv *serv = NULL; - int ret = 0; - - mutex_lock(&nfs_callback_mutex); - if (nfs_callback_info.users++ || nfs_callback_info.task != NULL) - goto out; - serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL); - ret = -ENOMEM; - if (!serv) - goto out_err; + int ret; ret = svc_create_xprt(serv, "tcp", PF_INET, nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS); @@ -131,18 +123,53 @@ int nfs_callback_up(void) goto out_err; #endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ - nfs_callback_info.rqst = svc_prepare_thread(serv, &serv->sv_pools[0]); - if (IS_ERR(nfs_callback_info.rqst)) { - ret = PTR_ERR(nfs_callback_info.rqst); - nfs_callback_info.rqst = NULL; + return svc_prepare_thread(serv, &serv->sv_pools[0]); + +out_err: + if (ret == 0) + ret = -ENOMEM; + return ERR_PTR(ret); +} + +/* + * Bring up the callback thread if it is not already up. + */ +int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt) +{ + struct svc_serv *serv = NULL; + struct svc_rqst *rqstp; + int (*callback_svc)(void *vrqstp); + char svc_name[12]; + int ret = 0; + + mutex_lock(&nfs_callback_mutex); + if (nfs_callback_info.users++ || nfs_callback_info.task != NULL) + goto out; + serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL); + if (!serv) { + ret = -ENOMEM; + goto out_err; + } + + if (!minorversion) { + rqstp = nfs4_callback_up(serv); + callback_svc = nfs4_callback_svc; + } else { + BUG(); /* for now */ + } + + if (IS_ERR(rqstp)) { + ret = PTR_ERR(rqstp); goto out_err; } svc_sock_update_bufs(serv); - nfs_callback_info.task = kthread_run(nfs_callback_svc, + sprintf(svc_name, "nfsv4.%u-svc", minorversion); + nfs_callback_info.rqst = rqstp; + nfs_callback_info.task = kthread_run(callback_svc, nfs_callback_info.rqst, - "nfsv4-svc"); + svc_name); if (IS_ERR(nfs_callback_info.task)) { ret = PTR_ERR(nfs_callback_info.task); svc_exit_thread(nfs_callback_info.rqst); diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h index e110e286a26217d681b8a26e4165d5fff3a7b75d..9b907f408b8dbf7e3f9914c9b679b99b209bf448 100644 --- a/fs/nfs/callback.h +++ b/fs/nfs/callback.h @@ -63,7 +63,7 @@ extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getat extern __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy); #ifdef CONFIG_NFS_V4 -extern int nfs_callback_up(void); +extern int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt); extern void nfs_callback_down(void); #else #define nfs_callback_up() (0) diff --git a/fs/nfs/client.c b/fs/nfs/client.c index d9657d455730f9ec02bee0a31b40855bfb7a70cd..df2b40d1883d803e8fa5c1bddb588a1d39f20c87 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -47,9 +47,6 @@ #include "internal.h" #include "fscache.h" -static int nfs4_init_callback(struct nfs_client *); -static void nfs4_destroy_callback(struct nfs_client *); - #define NFSDBG_FACILITY NFSDBG_CLIENT static DEFINE_SPINLOCK(nfs_client_lock); @@ -124,9 +121,6 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ clp->rpc_ops = cl_init->rpc_ops; - if (nfs4_init_callback(clp) < 0) - goto error_2; - atomic_set(&clp->cl_count, 1); clp->cl_cons_state = NFS_CS_INITING; @@ -136,7 +130,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ if (cl_init->hostname) { clp->cl_hostname = kstrdup(cl_init->hostname, GFP_KERNEL); if (!clp->cl_hostname) - goto error_3; + goto error_cleanup; } INIT_LIST_HEAD(&clp->cl_superblocks); @@ -161,9 +155,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ return clp; -error_3: - nfs4_destroy_callback(clp); -error_2: +error_cleanup: kfree(clp); error_0: return NULL; @@ -207,6 +199,8 @@ static void nfs4_clear_client_minor_version(struct nfs_client *clp) clp->cl_call_sync = _nfs4_call_sync; #endif /* CONFIG_NFS_V4_1 */ + + nfs4_destroy_callback(clp); } /* @@ -225,8 +219,6 @@ static void nfs_free_client(struct nfs_client *clp) if (!IS_ERR(clp->cl_rpcclient)) rpc_shutdown_client(clp->cl_rpcclient); - nfs4_destroy_callback(clp); - if (clp->cl_machine_cred != NULL) put_rpccred(clp->cl_machine_cred); @@ -1104,7 +1096,8 @@ static int nfs4_init_callback(struct nfs_client *clp) int error; if (clp->rpc_ops->version == 4) { - error = nfs_callback_up(); + error = nfs_callback_up(clp->cl_minorversion, + clp->cl_rpcclient->cl_xprt); if (error < 0) { dprintk("%s: failed to start callback. Error = %d\n", __func__, error); @@ -1139,7 +1132,7 @@ static int nfs4_init_client_minor_version(struct nfs_client *clp) } #endif /* CONFIG_NFS_V4_1 */ - return 0; + return nfs4_init_callback(clp); } /*