aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/callback.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/callback.c')
-rw-r--r--fs/nfs/callback.c112
1 files changed, 108 insertions, 4 deletions
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
index 4b1313eda6f5..470928898063 100644
--- a/fs/nfs/callback.c
+++ b/fs/nfs/callback.c
@@ -17,6 +17,9 @@
17#include <linux/freezer.h> 17#include <linux/freezer.h>
18#include <linux/kthread.h> 18#include <linux/kthread.h>
19#include <linux/sunrpc/svcauth_gss.h> 19#include <linux/sunrpc/svcauth_gss.h>
20#if defined(CONFIG_NFS_V4_1)
21#include <linux/sunrpc/bc_xprt.h>
22#endif
20 23
21#include <net/inet_sock.h> 24#include <net/inet_sock.h>
22 25
@@ -28,6 +31,7 @@
28 31
29struct nfs_callback_data { 32struct nfs_callback_data {
30 unsigned int users; 33 unsigned int users;
34 struct svc_serv *serv;
31 struct svc_rqst *rqst; 35 struct svc_rqst *rqst;
32 struct task_struct *task; 36 struct task_struct *task;
33}; 37};
@@ -131,6 +135,99 @@ out_err:
131 return ERR_PTR(ret); 135 return ERR_PTR(ret);
132} 136}
133 137
138#if defined(CONFIG_NFS_V4_1)
139/*
140 * The callback service for NFSv4.1 callbacks
141 */
142static int
143nfs41_callback_svc(void *vrqstp)
144{
145 struct svc_rqst *rqstp = vrqstp;
146 struct svc_serv *serv = rqstp->rq_server;
147 struct rpc_rqst *req;
148 int error;
149 DEFINE_WAIT(wq);
150
151 set_freezable();
152
153 /*
154 * FIXME: do we really need to run this under the BKL? If so, please
155 * add a comment about what it's intended to protect.
156 */
157 lock_kernel();
158 while (!kthread_should_stop()) {
159 prepare_to_wait(&serv->sv_cb_waitq, &wq, TASK_INTERRUPTIBLE);
160 spin_lock_bh(&serv->sv_cb_lock);
161 if (!list_empty(&serv->sv_cb_list)) {
162 req = list_first_entry(&serv->sv_cb_list,
163 struct rpc_rqst, rq_bc_list);
164 list_del(&req->rq_bc_list);
165 spin_unlock_bh(&serv->sv_cb_lock);
166 dprintk("Invoking bc_svc_process()\n");
167 error = bc_svc_process(serv, req, rqstp);
168 dprintk("bc_svc_process() returned w/ error code= %d\n",
169 error);
170 } else {
171 spin_unlock_bh(&serv->sv_cb_lock);
172 schedule();
173 }
174 finish_wait(&serv->sv_cb_waitq, &wq);
175 }
176 unlock_kernel();
177 nfs_callback_info.task = NULL;
178 svc_exit_thread(rqstp);
179 return 0;
180}
181
182/*
183 * Bring up the NFSv4.1 callback service
184 */
185struct svc_rqst *
186nfs41_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt)
187{
188 /*
189 * Save the svc_serv in the transport so that it can
190 * be referenced when the session backchannel is initialized
191 */
192 xprt->bc_serv = serv;
193
194 INIT_LIST_HEAD(&serv->sv_cb_list);
195 spin_lock_init(&serv->sv_cb_lock);
196 init_waitqueue_head(&serv->sv_cb_waitq);
197 return svc_prepare_thread(serv, &serv->sv_pools[0]);
198}
199
200static inline int nfs_minorversion_callback_svc_setup(u32 minorversion,
201 struct svc_serv *serv, struct rpc_xprt *xprt,
202 struct svc_rqst **rqstpp, int (**callback_svc)(void *vrqstp))
203{
204 if (minorversion) {
205 *rqstpp = nfs41_callback_up(serv, xprt);
206 *callback_svc = nfs41_callback_svc;
207 }
208 return minorversion;
209}
210
211static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt,
212 struct nfs_callback_data *cb_info)
213{
214 if (minorversion)
215 xprt->bc_serv = cb_info->serv;
216}
217#else
218static inline int nfs_minorversion_callback_svc_setup(u32 minorversion,
219 struct svc_serv *serv, struct rpc_xprt *xprt,
220 struct svc_rqst **rqstpp, int (**callback_svc)(void *vrqstp))
221{
222 return 0;
223}
224
225static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt,
226 struct nfs_callback_data *cb_info)
227{
228}
229#endif /* CONFIG_NFS_V4_1 */
230
134/* 231/*
135 * Bring up the callback thread if it is not already up. 232 * Bring up the callback thread if it is not already up.
136 */ 233 */
@@ -141,21 +238,25 @@ int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt)
141 int (*callback_svc)(void *vrqstp); 238 int (*callback_svc)(void *vrqstp);
142 char svc_name[12]; 239 char svc_name[12];
143 int ret = 0; 240 int ret = 0;
241 int minorversion_setup;
144 242
145 mutex_lock(&nfs_callback_mutex); 243 mutex_lock(&nfs_callback_mutex);
146 if (nfs_callback_info.users++ || nfs_callback_info.task != NULL) 244 if (nfs_callback_info.users++ || nfs_callback_info.task != NULL) {
245 nfs_callback_bc_serv(minorversion, xprt, &nfs_callback_info);
147 goto out; 246 goto out;
247 }
148 serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL); 248 serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL);
149 if (!serv) { 249 if (!serv) {
150 ret = -ENOMEM; 250 ret = -ENOMEM;
151 goto out_err; 251 goto out_err;
152 } 252 }
153 253
154 if (!minorversion) { 254 minorversion_setup = nfs_minorversion_callback_svc_setup(minorversion,
255 serv, xprt, &rqstp, &callback_svc);
256 if (!minorversion_setup) {
257 /* v4.0 callback setup */
155 rqstp = nfs4_callback_up(serv); 258 rqstp = nfs4_callback_up(serv);
156 callback_svc = nfs4_callback_svc; 259 callback_svc = nfs4_callback_svc;
157 } else {
158 BUG(); /* for now */
159 } 260 }
160 261
161 if (IS_ERR(rqstp)) { 262 if (IS_ERR(rqstp)) {
@@ -166,6 +267,7 @@ int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt)
166 svc_sock_update_bufs(serv); 267 svc_sock_update_bufs(serv);
167 268
168 sprintf(svc_name, "nfsv4.%u-svc", minorversion); 269 sprintf(svc_name, "nfsv4.%u-svc", minorversion);
270 nfs_callback_info.serv = serv;
169 nfs_callback_info.rqst = rqstp; 271 nfs_callback_info.rqst = rqstp;
170 nfs_callback_info.task = kthread_run(callback_svc, 272 nfs_callback_info.task = kthread_run(callback_svc,
171 nfs_callback_info.rqst, 273 nfs_callback_info.rqst,
@@ -173,6 +275,7 @@ int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt)
173 if (IS_ERR(nfs_callback_info.task)) { 275 if (IS_ERR(nfs_callback_info.task)) {
174 ret = PTR_ERR(nfs_callback_info.task); 276 ret = PTR_ERR(nfs_callback_info.task);
175 svc_exit_thread(nfs_callback_info.rqst); 277 svc_exit_thread(nfs_callback_info.rqst);
278 nfs_callback_info.serv = NULL;
176 nfs_callback_info.rqst = NULL; 279 nfs_callback_info.rqst = NULL;
177 nfs_callback_info.task = NULL; 280 nfs_callback_info.task = NULL;
178 goto out_err; 281 goto out_err;
@@ -205,6 +308,7 @@ void nfs_callback_down(void)
205 if (nfs_callback_info.users == 0 && nfs_callback_info.task != NULL) { 308 if (nfs_callback_info.users == 0 && nfs_callback_info.task != NULL) {
206 kthread_stop(nfs_callback_info.task); 309 kthread_stop(nfs_callback_info.task);
207 svc_exit_thread(nfs_callback_info.rqst); 310 svc_exit_thread(nfs_callback_info.rqst);
311 nfs_callback_info.serv = NULL;
208 nfs_callback_info.rqst = NULL; 312 nfs_callback_info.rqst = NULL;
209 nfs_callback_info.task = NULL; 313 nfs_callback_info.task = NULL;
210 } 314 }