callback.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  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. static int param_set_port(const char *val, struct kernel_param *kp)
  36. {
  37. char *endp;
  38. int num = simple_strtol(val, &endp, 0);
  39. if (endp == val || *endp || num < nfs_set_port_min || num > nfs_set_port_max)
  40. return -EINVAL;
  41. *((int *)kp->arg) = num;
  42. return 0;
  43. }
  44. module_param_call(callback_tcpport, param_set_port, param_get_int,
  45. &nfs_callback_set_tcpport, 0644);
  46. /*
  47. * This is the callback kernel thread.
  48. */
  49. static int
  50. nfs_callback_svc(void *vrqstp)
  51. {
  52. int err, preverr = 0;
  53. struct svc_rqst *rqstp = vrqstp;
  54. set_freezable();
  55. /*
  56. * FIXME: do we really need to run this under the BKL? If so, please
  57. * add a comment about what it's intended to protect.
  58. */
  59. lock_kernel();
  60. while (!kthread_should_stop()) {
  61. /*
  62. * Listen for a request on the socket
  63. */
  64. err = svc_recv(rqstp, MAX_SCHEDULE_TIMEOUT);
  65. if (err == -EAGAIN || err == -EINTR) {
  66. preverr = err;
  67. continue;
  68. }
  69. if (err < 0) {
  70. if (err != preverr) {
  71. printk(KERN_WARNING "%s: unexpected error "
  72. "from svc_recv (%d)\n", __func__, err);
  73. preverr = err;
  74. }
  75. schedule_timeout_uninterruptible(HZ);
  76. continue;
  77. }
  78. preverr = err;
  79. svc_process(rqstp);
  80. }
  81. unlock_kernel();
  82. return 0;
  83. }
  84. /*
  85. * Bring up the callback thread if it is not already up.
  86. */
  87. int nfs_callback_up(void)
  88. {
  89. struct svc_serv *serv = NULL;
  90. int ret = 0;
  91. mutex_lock(&nfs_callback_mutex);
  92. if (nfs_callback_info.users++ || nfs_callback_info.task != NULL)
  93. goto out;
  94. serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL);
  95. ret = -ENOMEM;
  96. if (!serv)
  97. goto out_err;
  98. ret = svc_create_xprt(serv, "tcp", nfs_callback_set_tcpport,
  99. SVC_SOCK_ANONYMOUS);
  100. if (ret <= 0)
  101. goto out_err;
  102. nfs_callback_tcpport = ret;
  103. dprintk("Callback port = 0x%x\n", nfs_callback_tcpport);
  104. nfs_callback_info.rqst = svc_prepare_thread(serv, &serv->sv_pools[0]);
  105. if (IS_ERR(nfs_callback_info.rqst)) {
  106. ret = PTR_ERR(nfs_callback_info.rqst);
  107. nfs_callback_info.rqst = NULL;
  108. goto out_err;
  109. }
  110. svc_sock_update_bufs(serv);
  111. nfs_callback_info.task = kthread_run(nfs_callback_svc,
  112. nfs_callback_info.rqst,
  113. "nfsv4-svc");
  114. if (IS_ERR(nfs_callback_info.task)) {
  115. ret = PTR_ERR(nfs_callback_info.task);
  116. svc_exit_thread(nfs_callback_info.rqst);
  117. nfs_callback_info.rqst = NULL;
  118. nfs_callback_info.task = NULL;
  119. goto out_err;
  120. }
  121. out:
  122. /*
  123. * svc_create creates the svc_serv with sv_nrthreads == 1, and then
  124. * svc_prepare_thread increments that. So we need to call svc_destroy
  125. * on both success and failure so that the refcount is 1 when the
  126. * thread exits.
  127. */
  128. if (serv)
  129. svc_destroy(serv);
  130. mutex_unlock(&nfs_callback_mutex);
  131. return ret;
  132. out_err:
  133. dprintk("Couldn't create callback socket or server thread; err = %d\n",
  134. ret);
  135. nfs_callback_info.users--;
  136. goto out;
  137. }
  138. /*
  139. * Kill the callback thread if it's no longer being used.
  140. */
  141. void nfs_callback_down(void)
  142. {
  143. mutex_lock(&nfs_callback_mutex);
  144. nfs_callback_info.users--;
  145. if (nfs_callback_info.users == 0 && nfs_callback_info.task != NULL) {
  146. kthread_stop(nfs_callback_info.task);
  147. svc_exit_thread(nfs_callback_info.rqst);
  148. nfs_callback_info.rqst = NULL;
  149. nfs_callback_info.task = NULL;
  150. }
  151. mutex_unlock(&nfs_callback_mutex);
  152. }
  153. static int nfs_callback_authenticate(struct svc_rqst *rqstp)
  154. {
  155. struct nfs_client *clp;
  156. RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
  157. /* Don't talk to strangers */
  158. clp = nfs_find_client(svc_addr(rqstp), 4);
  159. if (clp == NULL)
  160. return SVC_DROP;
  161. dprintk("%s: %s NFSv4 callback!\n", __func__,
  162. svc_print_addr(rqstp, buf, sizeof(buf)));
  163. nfs_put_client(clp);
  164. switch (rqstp->rq_authop->flavour) {
  165. case RPC_AUTH_NULL:
  166. if (rqstp->rq_proc != CB_NULL)
  167. return SVC_DENIED;
  168. break;
  169. case RPC_AUTH_UNIX:
  170. break;
  171. case RPC_AUTH_GSS:
  172. /* FIXME: RPCSEC_GSS handling? */
  173. default:
  174. return SVC_DENIED;
  175. }
  176. return SVC_OK;
  177. }
  178. /*
  179. * Define NFS4 callback program
  180. */
  181. static struct svc_version *nfs4_callback_version[] = {
  182. [1] = &nfs4_callback_version1,
  183. };
  184. static struct svc_stat nfs4_callback_stats;
  185. static struct svc_program nfs4_callback_program = {
  186. .pg_prog = NFS4_CALLBACK, /* RPC service number */
  187. .pg_nvers = ARRAY_SIZE(nfs4_callback_version), /* Number of entries */
  188. .pg_vers = nfs4_callback_version, /* version table */
  189. .pg_name = "NFSv4 callback", /* service name */
  190. .pg_class = "nfs", /* authentication class */
  191. .pg_stats = &nfs4_callback_stats,
  192. .pg_authenticate = nfs_callback_authenticate,
  193. };