> -----Original Message----- > From: Myklebust, Trond > Sent: Thursday, June 04, 2009 1:18 PM > To: Benny Halevy > Cc: linux-nfs@xxxxxxxxxxxxxxx; pnfs@xxxxxxxxxxxxx > Subject: Re: [pnfs] [RFC 14/39] nfs41: Implement NFSv4.1 callback service > process. > > On Fri, 2009-05-01 at 02:21 +0300, Benny Halevy wrote: > > From: Ricardo Labiaga <Ricardo.Labiaga@xxxxxxxxxx> > > > > nfs41_callback_up() initializes the necessary queues and creates the new > > nfs41_callback_svc thread. This thread executes the callback service > which > > waits for requests to arrive on the svc_serv->sv_cb_list. > > > > NFS41_BC_MIN_CALLBACKS is set to 1 because we expect callbacks to not > > cause substantial latency. > > > > The actual processing of the callback will be implemented as a separate > patch. > > > > There is only one NFSv4.1 callback service. The first caller of > > nfs4_callback_up() creates the service, subsequent callers increment a > > reference count on the service. The service is destroyed when the last > > caller invokes nfs_callback_down(). > > > > The transport needs to hold a reference to the callback service in order > > to invoke it during callback processing. Currently this reference is > only > > obtained when the service is first created. This is incorrect, since > > subsequent registrations for other transports will leave the xprt->serv > > pointer uninitialized, leading to an oops when a callback arrives on > > the "unreferenced" transport. > > > > This patch fixes the problem by ensuring that a reference to the service > > is saved in xprt->serv, either because the service is created by this > > invocation to nfs4_callback_up() or by a prior invocation. > > > > Signed-off-by: Ricardo Labiaga <Ricardo.Labiaga@xxxxxxxxxx> > > Signed-off-by: Benny Halevy <bhalevy@xxxxxxxxxxx> > > [nfs41: Add a reference to svc_serv during callback service bring up] > > Signed-off-by: Ricardo Labiaga <Ricardo.Labiaga@xxxxxxxxxx> > > Signed-off-by: Benny Halevy <bhalevy@xxxxxxxxxxx> > > --- > > fs/nfs/callback.c | 83 > ++++++++++++++++++++++++++++++++++++++++++- > > fs/nfs/callback.h | 7 ++++ > > include/linux/sunrpc/svc.h | 2 + > > 3 files changed, 90 insertions(+), 2 deletions(-) > > > > diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c > > index 3926046..9ee174c 100644 > > --- a/fs/nfs/callback.c > > +++ b/fs/nfs/callback.c > > @@ -17,6 +17,9 @@ > > #include <linux/freezer.h> > > #include <linux/kthread.h> > > #include <linux/sunrpc/svcauth_gss.h> > > +#if defined(CONFIG_NFS_V4_1) > > +#include <linux/sunrpc/bc_xprt.h> > > +#endif > > > > #include <net/inet_sock.h> > > > > @@ -131,6 +134,69 @@ out_err: > > return ERR_PTR(ret); > > } > > > > +#if defined(CONFIG_NFS_V4_1) > > +/* > > + * The callback service for NFSv4.1 callbacks > > + */ > > +static int > > +nfs41_callback_svc(void *vrqstp) > > +{ > > + struct svc_rqst *rqstp = vrqstp; > > + struct svc_serv *serv = rqstp->rq_server; > > + struct rpc_rqst *req; > > + int error; > > + DEFINE_WAIT(wq); > > + > > + set_freezable(); > > + > > + /* > > + * FIXME: do we really need to run this under the BKL? If so, please > > + * add a comment about what it's intended to protect. > > + */ > > + lock_kernel(); > > + while (!kthread_should_stop()) { > > + prepare_to_wait(&serv->sv_cb_waitq, &wq, TASK_INTERRUPTIBLE); > > + spin_lock_bh(&serv->sv_cb_lock); > > + if (!list_empty(&serv->sv_cb_list)) { > > + req = list_first_entry(&serv->sv_cb_list, > > + struct rpc_rqst, rq_bc_list); > > + list_del(&req->rq_bc_list); > > + spin_unlock_bh(&serv->sv_cb_lock); > > + dprintk("Invoking bc_svc_process()\n"); > > + error = bc_svc_process(serv, req, rqstp); > > + dprintk("bc_svc_process() returned w/ error code= %d\n", > > + error); > > + } else { > > + spin_unlock_bh(&serv->sv_cb_lock); > > + schedule(); > > + } > > + finish_wait(&serv->sv_cb_waitq, &wq); > > + } > > + unlock_kernel(); > > + nfs_callback_info.task = NULL; > > + svc_exit_thread(rqstp); > > + return 0; > > +} > > + > > +/* > > + * Bring up the NFSv4.1 callback service > > + */ > > +struct svc_rqst * > > +nfs41_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt) > > +{ > > + /* > > + * Save the svc_serv in the transport so that it can > > + * be referenced when the session backchannel is initialized > > + */ > > + xprt->bc_serv = serv; > > + > > + INIT_LIST_HEAD(&serv->sv_cb_list); > > + spin_lock_init(&serv->sv_cb_lock); > > + init_waitqueue_head(&serv->sv_cb_waitq); > > + return svc_prepare_thread(serv, &serv->sv_pools[0]); > > +} > > +#endif /* CONFIG_NFS_V4_1 */ > > + > > /* > > * Bring up the callback thread if it is not already up. > > */ > > @@ -141,10 +207,18 @@ int nfs_callback_up(u32 minorversion, void *args) > > int (*callback_svc)(void *vrqstp); > > char svc_name[12]; > > int ret = 0; > > +#if defined(CONFIG_NFS_V4_1) > > + struct rpc_xprt *xprt = (struct rpc_xprt *)args; > > +#endif /* CONFIG_NFS_V4_1 */ > > More ugly embedded ifdefs... > > > > > mutex_lock(&nfs_callback_mutex); > > - if (nfs_callback_info.users++ || nfs_callback_info.task != NULL) > > + if (nfs_callback_info.users++ || nfs_callback_info.task != NULL) { > > +#if defined(CONFIG_NFS_V4_1) > > + if (minorversion) > > + xprt->bc_serv = nfs_callback_info.serv; > > +#endif /* CONFIG_NFS_V4_1 */ > > Ditto > > > goto out; > > + } > > serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, > NULL); > > if (!serv) { > > ret = -ENOMEM; > > @@ -157,7 +231,12 @@ int nfs_callback_up(u32 minorversion, void *args) > > rqstp = nfs4_callback_up(serv); > > callback_svc = nfs4_callback_svc; > > } else { > > - BUG(); /* for now */ > > +#if defined(CONFIG_NFS_V4_1) > > + rqstp = nfs41_callback_up(serv, xprt); > > + callback_svc = nfs41_callback_svc; > > +#else /* CONFIG_NFS_V4_1 */ > > + BUG(); > > +#endif /* CONFIG_NFS_V4_1 */ > > Ditto > > > } > > > > if (IS_ERR(rqstp)) { > > diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h > > index 7f12e65..f2696ba 100644 > > --- a/fs/nfs/callback.h > > +++ b/fs/nfs/callback.h > > @@ -70,6 +70,13 @@ extern void nfs_callback_down(void); > > #define nfs_callback_down() do {} while(0) > > #endif > > > > +/* > > + * nfs41: Callbacks are expected to not cause substantial latency, > > + * so we limit their concurrency to 1 by setting up the maximum number > > + * of slots for the backchannel. > > + */ > > +#define NFS41_BC_MIN_CALLBACKS 1 > > + > > extern unsigned int nfs_callback_set_tcpport; > > extern unsigned short nfs_callback_tcpport; > > extern unsigned short nfs_callback_tcpport6; > > diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h > > index 4a8afbd..16043c4 100644 > > --- a/include/linux/sunrpc/svc.h > > +++ b/include/linux/sunrpc/svc.h > > @@ -419,6 +419,8 @@ int svc_set_num_threads(struct svc_serv > *, struct svc_pool *, int); > > int svc_pool_stats_open(struct svc_serv *serv, struct file > *file); > > void svc_destroy(struct svc_serv *); > > int svc_process(struct svc_rqst *); > > +int bc_svc_process(struct svc_serv *, struct rpc_rqst *, > > + struct svc_rqst *); > > OK, I give up. Why is the function text and export declaration in one > patch, while the declaration is in this patch? > Will move this declaration to patch 13 along with the function and export declaration. Will also address the ifdefs. - ricardo > > int svc_register(const struct svc_serv *, const int, > > const unsigned short, const unsigned short); > > > > -- > Trond Myklebust > Linux NFS client maintainer > > NetApp > Trond.Myklebust@xxxxxxxxxx > www.netapp.com > _______________________________________________ > pNFS mailing list > pNFS@xxxxxxxxxxxxx > http://linux-nfs.org/cgi-bin/mailman/listinfo/pnfs -- To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html