callback.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. /*
  2. * linux/fs/nfs/callback.c
  3. *
  4. * Copyright (C) 2004 Trond Myklebust
  5. *
  6. * NFSv4 callback handling
  7. */
  8. #include <linux/completion.h>
  9. #include <linux/ip.h>
  10. #include <linux/module.h>
  11. #include <linux/smp_lock.h>
  12. #include <linux/sunrpc/svc.h>
  13. #include <linux/sunrpc/svcsock.h>
  14. #include <linux/nfs_fs.h>
  15. #include <linux/mutex.h>
  16. #include <linux/freezer.h>
  17. #include <linux/kthread.h>
  18. #include <net/inet_sock.h>
  19. #include "nfs4_fs.h"
  20. #include "callback.h"
  21. #include "internal.h"
  22. #define NFSDBG_FACILITY NFSDBG_CALLBACK
  23. struct nfs_callback_data {
  24. unsigned int users;
  25. struct svc_rqst *rqst;
  26. struct task_struct *task;
  27. };
  28. static struct nfs_callback_data nfs_callback_info;
  29. static DEFINE_MUTEX(nfs_callback_mutex);
  30. static struct svc_program nfs4_callback_program;
  31. unsigned int nfs_callback_set_tcpport;
  32. unsigned short nfs_callback_tcpport;
  33. static const int nfs_set_port_min = 0;
  34. static const int nfs_set_port_max = 65535;
  35. /*
  36. * If the kernel has IPv6 support available, always listen for
  37. * both AF_INET and AF_INET6 requests.
  38. */
  39. #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
  40. static const sa_family_t nfs_callback_family = AF_INET6;
  41. #else
  42. static const sa_family_t nfs_callback_family = AF_INET;
  43. #endif
  44. static int param_set_port(const char *val, struct kernel_param *kp)
  45. {
  46. char *endp;
  47. int num = simple_strtol(val, &endp, 0);
  48. if (endp == val || *endp || num < nfs_set_port_min || num > nfs_set_port_max)
  49. return -EINVAL;
  50. *((int *)kp->arg) = num;
  51. return 0;
  52. }
  53. module_param_call(callback_tcpport, param_set_port, param_get_int,
  54. &nfs_callback_set_tcpport, 0644);
  55. /*
  56. * This is the callback kernel thread.
  57. */
  58. static int
  59. nfs_callback_svc(void *vrqstp)
  60. {
  61. int err, preverr = 0;
  62. struct svc_rqst *rqstp = vrqstp;
  63. set_freezable();
  64. /*
  65. * FIXME: do we really need to run this under the BKL? If so, please
  66. * add a comment about what it's intended to protect.
  67. */
  68. lock_kernel();
  69. while (!kthread_should_stop()) {
  70. /*
  71. * Listen for a request on the socket
  72. */
  73. err = svc_recv(rqstp, MAX_SCHEDULE_TIMEOUT);
  74. if (err == -EAGAIN || err == -EINTR) {
  75. preverr = err;
  76. continue;
  77. }
  78. if (err < 0) {
  79. if (err != preverr) {
  80. printk(KERN_WARNING "%s: unexpected error "
  81. "from svc_recv (%d)\n", __func__, err);
  82. preverr = err;
  83. }
  84. schedule_timeout_uninterruptible(HZ);
  85. continue;
  86. }
  87. preverr = err;
  88. svc_process(rqstp);
  89. }
  90. unlock_kernel();
  91. return 0;
  92. }
  93. /*
  94. * Bring up the callback thread if it is not already up.
  95. */
  96. int nfs_callback_up(void)
  97. {
  98. struct svc_serv *serv = NULL;
  99. int ret = 0;
  100. mutex_lock(&nfs_callback_mutex);
  101. if (nfs_callback_info.users++ || nfs_callback_info.task != NULL)
  102. goto out;
  103. serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE,
  104. nfs_callback_family, NULL);
  105. ret = -ENOMEM;
  106. if (!serv)
  107. goto out_err;
  108. ret = svc_create_xprt(serv, "tcp", nfs_callback_set_tcpport,
  109. SVC_SOCK_ANONYMOUS);
  110. if (ret <= 0)
  111. goto out_err;
  112. nfs_callback_tcpport = ret;
  113. dprintk("NFS: Callback listener port = %u (af %u)\n",
  114. nfs_callback_tcpport, nfs_callback_family);
  115. nfs_callback_info.rqst = svc_prepare_thread(serv, &serv->sv_pools[0]);
  116. if (IS_ERR(nfs_callback_info.rqst)) {
  117. ret = PTR_ERR(nfs_callback_info.rqst);
  118. nfs_callback_info.rqst = NULL;
  119. goto out_err;
  120. }
  121. svc_sock_update_bufs(serv);
  122. nfs_callback_info.task = kthread_run(nfs_callback_svc,
  123. nfs_callback_info.rqst,
  124. "nfsv4-svc");
  125. if (IS_ERR(nfs_callback_info.task)) {
  126. ret = PTR_ERR(nfs_callback_info.task);
  127. svc_exit_thread(nfs_callback_info.rqst);
  128. nfs_callback_info.rqst = NULL;
  129. nfs_callback_info.task = NULL;
  130. goto out_err;
  131. }
  132. out:
  133. /*
  134. * svc_create creates the svc_serv with sv_nrthreads == 1, and then
  135. * svc_prepare_thread increments that. So we need to call svc_destroy
  136. * on both success and failure so that the refcount is 1 when the
  137. * thread exits.
  138. */
  139. if (serv)
  140. svc_destroy(serv);
  141. mutex_unlock(&nfs_callback_mutex);
  142. return ret;
  143. out_err:
  144. dprintk("NFS: Couldn't create callback socket or server thread; "
  145. "err = %d\n", ret);
  146. nfs_callback_info.users--;
  147. goto out;
  148. }
  149. /*
  150. * Kill the callback thread if it's no longer being used.
  151. */
  152. void nfs_callback_down(void)
  153. {
  154. mutex_lock(&nfs_callback_mutex);
  155. nfs_callback_info.users--;
  156. if (nfs_callback_info.users == 0 && nfs_callback_info.task != NULL) {
  157. kthread_stop(nfs_callback_info.task);
  158. svc_exit_thread(nfs_callback_info.rqst);
  159. nfs_callback_info.rqst = NULL;
  160. nfs_callback_info.task = NULL;
  161. }
  162. mutex_unlock(&nfs_callback_mutex);
  163. }
  164. static int nfs_callback_authenticate(struct svc_rqst *rqstp)
  165. {
  166. struct nfs_client *clp;
  167. RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
  168. /* Don't talk to strangers */
  169. clp = nfs_find_client(svc_addr(rqstp), 4);
  170. if (clp == NULL)
  171. return SVC_DROP;
  172. dprintk("%s: %s NFSv4 callback!\n", __func__,
  173. svc_print_addr(rqstp, buf, sizeof(buf)));
  174. nfs_put_client(clp);
  175. switch (rqstp->rq_authop->flavour) {
  176. case RPC_AUTH_NULL:
  177. if (rqstp->rq_proc != CB_NULL)
  178. return SVC_DENIED;
  179. break;
  180. case RPC_AUTH_UNIX:
  181. break;
  182. case RPC_AUTH_GSS:
  183. /* FIXME: RPCSEC_GSS handling? */
  184. default:
  185. return SVC_DENIED;
  186. }
  187. return SVC_OK;
  188. }
  189. /*
  190. * Define NFS4 callback program
  191. */
  192. static struct svc_version *nfs4_callback_version[] = {
  193. [1] = &nfs4_callback_version1,
  194. };
  195. static struct svc_stat nfs4_callback_stats;
  196. static struct svc_program nfs4_callback_program = {
  197. .pg_prog = NFS4_CALLBACK, /* RPC service number */
  198. .pg_nvers = ARRAY_SIZE(nfs4_callback_version), /* Number of entries */
  199. .pg_vers = nfs4_callback_version, /* version table */
  200. .pg_name = "NFSv4 callback", /* service name */
  201. .pg_class = "nfs", /* authentication class */
  202. .pg_stats = &nfs4_callback_stats,
  203. .pg_authenticate = nfs_callback_authenticate,
  204. };