Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
callback.c
Go to the documentation of this file.
1 /*
2  * linux/fs/nfs/callback.c
3  *
4  * Copyright (C) 2004 Trond Myklebust
5  *
6  * NFSv4 callback handling
7  */
8 
9 #include <linux/completion.h>
10 #include <linux/ip.h>
11 #include <linux/module.h>
12 #include <linux/sunrpc/svc.h>
13 #include <linux/sunrpc/svcsock.h>
14 #include <linux/nfs_fs.h>
15 #include <linux/errno.h>
16 #include <linux/mutex.h>
17 #include <linux/freezer.h>
18 #include <linux/kthread.h>
20 #include <linux/sunrpc/bc_xprt.h>
21 
22 #include <net/inet_sock.h>
23 
24 #include "nfs4_fs.h"
25 #include "callback.h"
26 #include "internal.h"
27 #include "netns.h"
28 
29 #define NFSDBG_FACILITY NFSDBG_CALLBACK
30 
32  unsigned int users;
33  struct svc_serv *serv;
34  struct svc_rqst *rqst;
35  struct task_struct *task;
36 };
37 
38 static struct nfs_callback_data nfs_callback_info[NFS4_MAX_MINOR_VERSION + 1];
39 static DEFINE_MUTEX(nfs_callback_mutex);
40 static struct svc_program nfs4_callback_program;
41 
42 static int nfs4_callback_up_net(struct svc_serv *serv, struct net *net)
43 {
44  int ret;
45  struct nfs_net *nn = net_generic(net, nfs_net_id);
46 
47  ret = svc_create_xprt(serv, "tcp", net, PF_INET,
48  nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
49  if (ret <= 0)
50  goto out_err;
51  nn->nfs_callback_tcpport = ret;
52  dprintk("NFS: Callback listener port = %u (af %u, net %p)\n",
53  nn->nfs_callback_tcpport, PF_INET, net);
54 
55  ret = svc_create_xprt(serv, "tcp", net, PF_INET6,
56  nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
57  if (ret > 0) {
58  nn->nfs_callback_tcpport6 = ret;
59  dprintk("NFS: Callback listener port = %u (af %u, net %p)\n",
60  nn->nfs_callback_tcpport6, PF_INET6, net);
61  } else if (ret != -EAFNOSUPPORT)
62  goto out_err;
63  return 0;
64 
65 out_err:
66  return (ret) ? ret : -ENOMEM;
67 }
68 
69 /*
70  * This is the NFSv4 callback kernel thread.
71  */
72 static int
73 nfs4_callback_svc(void *vrqstp)
74 {
75  int err;
76  struct svc_rqst *rqstp = vrqstp;
77 
78  set_freezable();
79 
80  while (!kthread_should_stop()) {
81  /*
82  * Listen for a request on the socket
83  */
84  err = svc_recv(rqstp, MAX_SCHEDULE_TIMEOUT);
85  if (err == -EAGAIN || err == -EINTR)
86  continue;
87  svc_process(rqstp);
88  }
89  return 0;
90 }
91 
92 /*
93  * Prepare to bring up the NFSv4 callback service
94  */
95 static struct svc_rqst *
96 nfs4_callback_up(struct svc_serv *serv)
97 {
98  return svc_prepare_thread(serv, &serv->sv_pools[0], NUMA_NO_NODE);
99 }
100 
101 #if defined(CONFIG_NFS_V4_1)
102 static int nfs41_callback_up_net(struct svc_serv *serv, struct net *net)
103 {
104  /*
105  * Create an svc_sock for the back channel service that shares the
106  * fore channel connection.
107  * Returns the input port (0) and sets the svc_serv bc_xprt on success
108  */
109  return svc_create_xprt(serv, "tcp-bc", net, PF_INET, 0,
111 }
112 
113 /*
114  * The callback service for NFSv4.1 callbacks
115  */
116 static int
117 nfs41_callback_svc(void *vrqstp)
118 {
119  struct svc_rqst *rqstp = vrqstp;
120  struct svc_serv *serv = rqstp->rq_server;
121  struct rpc_rqst *req;
122  int error;
123  DEFINE_WAIT(wq);
124 
125  set_freezable();
126 
127  while (!kthread_should_stop()) {
128  prepare_to_wait(&serv->sv_cb_waitq, &wq, TASK_INTERRUPTIBLE);
129  spin_lock_bh(&serv->sv_cb_lock);
130  if (!list_empty(&serv->sv_cb_list)) {
131  req = list_first_entry(&serv->sv_cb_list,
132  struct rpc_rqst, rq_bc_list);
133  list_del(&req->rq_bc_list);
134  spin_unlock_bh(&serv->sv_cb_lock);
135  dprintk("Invoking bc_svc_process()\n");
136  error = bc_svc_process(serv, req, rqstp);
137  dprintk("bc_svc_process() returned w/ error code= %d\n",
138  error);
139  } else {
140  spin_unlock_bh(&serv->sv_cb_lock);
141  schedule();
142  }
143  finish_wait(&serv->sv_cb_waitq, &wq);
144  }
145  return 0;
146 }
147 
148 /*
149  * Bring up the NFSv4.1 callback service
150  */
151 static struct svc_rqst *
152 nfs41_callback_up(struct svc_serv *serv)
153 {
154  struct svc_rqst *rqstp;
155 
156  INIT_LIST_HEAD(&serv->sv_cb_list);
157  spin_lock_init(&serv->sv_cb_lock);
158  init_waitqueue_head(&serv->sv_cb_waitq);
159  rqstp = svc_prepare_thread(serv, &serv->sv_pools[0], NUMA_NO_NODE);
160  if (IS_ERR(rqstp)) {
161  svc_xprt_put(serv->sv_bc_xprt);
162  serv->sv_bc_xprt = NULL;
163  }
164  dprintk("--> %s return %ld\n", __func__,
165  IS_ERR(rqstp) ? PTR_ERR(rqstp) : 0);
166  return rqstp;
167 }
168 
169 static void nfs_minorversion_callback_svc_setup(struct svc_serv *serv,
170  struct svc_rqst **rqstpp, int (**callback_svc)(void *vrqstp))
171 {
172  *rqstpp = nfs41_callback_up(serv);
173  *callback_svc = nfs41_callback_svc;
174 }
175 
176 static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt,
177  struct svc_serv *serv)
178 {
179  if (minorversion)
180  /*
181  * Save the svc_serv in the transport so that it can
182  * be referenced when the session backchannel is initialized
183  */
184  xprt->bc_serv = serv;
185 }
186 #else
187 static int nfs41_callback_up_net(struct svc_serv *serv, struct net *net)
188 {
189  return 0;
190 }
191 
192 static void nfs_minorversion_callback_svc_setup(struct svc_serv *serv,
193  struct svc_rqst **rqstpp, int (**callback_svc)(void *vrqstp))
194 {
195  *rqstpp = ERR_PTR(-ENOTSUPP);
196  *callback_svc = ERR_PTR(-ENOTSUPP);
197 }
198 
199 static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt,
200  struct svc_serv *serv)
201 {
202 }
203 #endif /* CONFIG_NFS_V4_1 */
204 
205 static int nfs_callback_start_svc(int minorversion, struct rpc_xprt *xprt,
206  struct svc_serv *serv)
207 {
208  struct svc_rqst *rqstp;
209  int (*callback_svc)(void *vrqstp);
210  struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion];
211  char svc_name[12];
212  int ret;
213 
214  nfs_callback_bc_serv(minorversion, xprt, serv);
215 
216  if (cb_info->task)
217  return 0;
218 
219  switch (minorversion) {
220  case 0:
221  /* v4.0 callback setup */
222  rqstp = nfs4_callback_up(serv);
223  callback_svc = nfs4_callback_svc;
224  break;
225  default:
226  nfs_minorversion_callback_svc_setup(serv,
227  &rqstp, &callback_svc);
228  }
229 
230  if (IS_ERR(rqstp))
231  return PTR_ERR(rqstp);
232 
233  svc_sock_update_bufs(serv);
234 
235  sprintf(svc_name, "nfsv4.%u-svc", minorversion);
236  cb_info->serv = serv;
237  cb_info->rqst = rqstp;
238  cb_info->task = kthread_run(callback_svc, cb_info->rqst, svc_name);
239  if (IS_ERR(cb_info->task)) {
240  ret = PTR_ERR(cb_info->task);
241  svc_exit_thread(cb_info->rqst);
242  cb_info->rqst = NULL;
243  cb_info->task = NULL;
244  return ret;
245  }
246  dprintk("nfs_callback_up: service started\n");
247  return 0;
248 }
249 
250 static void nfs_callback_down_net(u32 minorversion, struct svc_serv *serv, struct net *net)
251 {
252  struct nfs_net *nn = net_generic(net, nfs_net_id);
253 
254  if (--nn->cb_users[minorversion])
255  return;
256 
257  dprintk("NFS: destroy per-net callback data; net=%p\n", net);
258  svc_shutdown_net(serv, net);
259 }
260 
261 static int nfs_callback_up_net(int minorversion, struct svc_serv *serv, struct net *net)
262 {
263  struct nfs_net *nn = net_generic(net, nfs_net_id);
264  int ret;
265 
266  if (nn->cb_users[minorversion]++)
267  return 0;
268 
269  dprintk("NFS: create per-net callback data; net=%p\n", net);
270 
271  ret = svc_bind(serv, net);
272  if (ret < 0) {
273  printk(KERN_WARNING "NFS: bind callback service failed\n");
274  goto err_bind;
275  }
276 
277  switch (minorversion) {
278  case 0:
279  ret = nfs4_callback_up_net(serv, net);
280  break;
281  case 1:
282  ret = nfs41_callback_up_net(serv, net);
283  break;
284  default:
285  printk(KERN_ERR "NFS: unknown callback version: %d\n",
286  minorversion);
287  ret = -EINVAL;
288  break;
289  }
290 
291  if (ret < 0) {
292  printk(KERN_ERR "NFS: callback service start failed\n");
293  goto err_socks;
294  }
295  return 0;
296 
297 err_socks:
298  svc_rpcb_cleanup(serv, net);
299 err_bind:
300  dprintk("NFS: Couldn't create callback socket: err = %d; "
301  "net = %p\n", ret, net);
302  return ret;
303 }
304 
305 static struct svc_serv *nfs_callback_create_svc(int minorversion)
306 {
307  struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion];
308  struct svc_serv *serv;
309 
310  /*
311  * Check whether we're already up and running.
312  */
313  if (cb_info->task) {
314  /*
315  * Note: increase service usage, because later in case of error
316  * svc_destroy() will be called.
317  */
318  svc_get(cb_info->serv);
319  return cb_info->serv;
320  }
321 
322  /*
323  * Sanity check: if there's no task,
324  * we should be the first user ...
325  */
326  if (cb_info->users)
327  printk(KERN_WARNING "nfs_callback_create_svc: no kthread, %d users??\n",
328  cb_info->users);
329 
330  serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL);
331  if (!serv) {
332  printk(KERN_ERR "nfs_callback_create_svc: create service failed\n");
333  return ERR_PTR(-ENOMEM);
334  }
335  /* As there is only one thread we need to over-ride the
336  * default maximum of 80 connections
337  */
338  serv->sv_maxconn = 1024;
339  dprintk("nfs_callback_create_svc: service created\n");
340  return serv;
341 }
342 
343 /*
344  * Bring up the callback thread if it is not already up.
345  */
346 int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt)
347 {
348  struct svc_serv *serv;
349  struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion];
350  int ret;
351  struct net *net = xprt->xprt_net;
352 
353  mutex_lock(&nfs_callback_mutex);
354 
355  serv = nfs_callback_create_svc(minorversion);
356  if (IS_ERR(serv)) {
357  ret = PTR_ERR(serv);
358  goto err_create;
359  }
360 
361  ret = nfs_callback_up_net(minorversion, serv, net);
362  if (ret < 0)
363  goto err_net;
364 
365  ret = nfs_callback_start_svc(minorversion, xprt, serv);
366  if (ret < 0)
367  goto err_start;
368 
369  cb_info->users++;
370  /*
371  * svc_create creates the svc_serv with sv_nrthreads == 1, and then
372  * svc_prepare_thread increments that. So we need to call svc_destroy
373  * on both success and failure so that the refcount is 1 when the
374  * thread exits.
375  */
376 err_net:
377  svc_destroy(serv);
378 err_create:
379  mutex_unlock(&nfs_callback_mutex);
380  return ret;
381 
382 err_start:
383  nfs_callback_down_net(minorversion, serv, net);
384  dprintk("NFS: Couldn't create server thread; err = %d\n", ret);
385  goto err_net;
386 }
387 
388 /*
389  * Kill the callback thread if it's no longer being used.
390  */
391 void nfs_callback_down(int minorversion, struct net *net)
392 {
393  struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion];
394 
395  mutex_lock(&nfs_callback_mutex);
396  nfs_callback_down_net(minorversion, cb_info->serv, net);
397  cb_info->users--;
398  if (cb_info->users == 0 && cb_info->task != NULL) {
399  kthread_stop(cb_info->task);
400  dprintk("nfs_callback_down: service stopped\n");
401  svc_exit_thread(cb_info->rqst);
402  dprintk("nfs_callback_down: service destroyed\n");
403  cb_info->serv = NULL;
404  cb_info->rqst = NULL;
405  cb_info->task = NULL;
406  }
407  mutex_unlock(&nfs_callback_mutex);
408 }
409 
410 /* Boolean check of RPC_AUTH_GSS principal */
411 int
413 {
414  char *p = rqstp->rq_cred.cr_principal;
415 
416  if (rqstp->rq_authop->flavour != RPC_AUTH_GSS)
417  return 1;
418 
419  /* No RPC_AUTH_GSS on NFSv4.1 back channel yet */
420  if (clp->cl_minorversion != 0)
421  return 0;
422  /*
423  * It might just be a normal user principal, in which case
424  * userspace won't bother to tell us the name at all.
425  */
426  if (p == NULL)
427  return 0;
428 
429  /* Expect a GSS_C_NT_HOSTBASED_NAME like "nfs@serverhostname" */
430 
431  if (memcmp(p, "nfs@", 4) != 0)
432  return 0;
433  p += 4;
434  if (strcmp(p, clp->cl_hostname) != 0)
435  return 0;
436  return 1;
437 }
438 
439 /*
440  * pg_authenticate method for nfsv4 callback threads.
441  *
442  * The authflavor has been negotiated, so an incorrect flavor is a server
443  * bug. Drop packets with incorrect authflavor.
444  *
445  * All other checking done after NFS decoding where the nfs_client can be
446  * found in nfs4_callback_compound
447  */
448 static int nfs_callback_authenticate(struct svc_rqst *rqstp)
449 {
450  switch (rqstp->rq_authop->flavour) {
451  case RPC_AUTH_NULL:
452  if (rqstp->rq_proc != CB_NULL)
453  return SVC_DROP;
454  break;
455  case RPC_AUTH_GSS:
456  /* No RPC_AUTH_GSS support yet in NFSv4.1 */
457  if (svc_is_backchannel(rqstp))
458  return SVC_DROP;
459  }
460  return SVC_OK;
461 }
462 
463 /*
464  * Define NFS4 callback program
465  */
466 static struct svc_version *nfs4_callback_version[] = {
467  [1] = &nfs4_callback_version1,
468  [4] = &nfs4_callback_version4,
469 };
470 
471 static struct svc_stat nfs4_callback_stats;
472 
473 static struct svc_program nfs4_callback_program = {
474  .pg_prog = NFS4_CALLBACK, /* RPC service number */
475  .pg_nvers = ARRAY_SIZE(nfs4_callback_version), /* Number of entries */
476  .pg_vers = nfs4_callback_version, /* version table */
477  .pg_name = "NFSv4 callback", /* service name */
478  .pg_class = "nfs", /* authentication class */
479  .pg_stats = &nfs4_callback_stats,
480  .pg_authenticate = nfs_callback_authenticate,
481 };