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/smp_lock.h> 13 #include <linux/sunrpc/svc.h> 14 #include <linux/sunrpc/svcsock.h> 15 #include <linux/nfs_fs.h> 16 #include <linux/mutex.h> 17 #include <linux/freezer.h> 18 #include <linux/kthread.h> 19 #include <linux/sunrpc/svcauth_gss.h> 20 #if defined(CONFIG_NFS_V4_1) 21 #include <linux/sunrpc/bc_xprt.h> 22 #endif 23 24 #include <net/inet_sock.h> 25 26 #include "nfs4_fs.h" 27 #include "callback.h" 28 #include "internal.h" 29 30 #define NFSDBG_FACILITY NFSDBG_CALLBACK 31 32 struct nfs_callback_data { 33 unsigned int users; 34 struct svc_serv *serv; 35 struct svc_rqst *rqst; 36 struct task_struct *task; 37 }; 38 39 static struct nfs_callback_data nfs_callback_info[NFS4_MAX_MINOR_VERSION + 1]; 40 static DEFINE_MUTEX(nfs_callback_mutex); 41 static struct svc_program nfs4_callback_program; 42 43 unsigned int nfs_callback_set_tcpport; 44 unsigned short nfs_callback_tcpport; 45 unsigned short nfs_callback_tcpport6; 46 static const int nfs_set_port_min = 0; 47 static const int nfs_set_port_max = 65535; 48 49 static int param_set_port(const char *val, struct kernel_param *kp) 50 { 51 char *endp; 52 int num = simple_strtol(val, &endp, 0); 53 if (endp == val || *endp || num < nfs_set_port_min || num > nfs_set_port_max) 54 return -EINVAL; 55 *((int *)kp->arg) = num; 56 return 0; 57 } 58 59 module_param_call(callback_tcpport, param_set_port, param_get_int, 60 &nfs_callback_set_tcpport, 0644); 61 62 /* 63 * This is the NFSv4 callback kernel thread. 64 */ 65 static int 66 nfs4_callback_svc(void *vrqstp) 67 { 68 int err, preverr = 0; 69 struct svc_rqst *rqstp = vrqstp; 70 71 set_freezable(); 72 73 /* 74 * FIXME: do we really need to run this under the BKL? If so, please 75 * add a comment about what it's intended to protect. 76 */ 77 lock_kernel(); 78 while (!kthread_should_stop()) { 79 /* 80 * Listen for a request on the socket 81 */ 82 err = svc_recv(rqstp, MAX_SCHEDULE_TIMEOUT); 83 if (err == -EAGAIN || err == -EINTR) { 84 preverr = err; 85 continue; 86 } 87 if (err < 0) { 88 if (err != preverr) { 89 printk(KERN_WARNING "%s: unexpected error " 90 "from svc_recv (%d)\n", __func__, err); 91 preverr = err; 92 } 93 schedule_timeout_uninterruptible(HZ); 94 continue; 95 } 96 preverr = err; 97 svc_process(rqstp); 98 } 99 unlock_kernel(); 100 return 0; 101 } 102 103 /* 104 * Prepare to bring up the NFSv4 callback service 105 */ 106 struct svc_rqst * 107 nfs4_callback_up(struct svc_serv *serv) 108 { 109 int ret; 110 111 ret = svc_create_xprt(serv, "tcp", PF_INET, 112 nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS); 113 if (ret <= 0) 114 goto out_err; 115 nfs_callback_tcpport = ret; 116 dprintk("NFS: Callback listener port = %u (af %u)\n", 117 nfs_callback_tcpport, PF_INET); 118 119 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 120 ret = svc_create_xprt(serv, "tcp", PF_INET6, 121 nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS); 122 if (ret > 0) { 123 nfs_callback_tcpport6 = ret; 124 dprintk("NFS: Callback listener port = %u (af %u)\n", 125 nfs_callback_tcpport6, PF_INET6); 126 } else if (ret == -EAFNOSUPPORT) 127 ret = 0; 128 else 129 goto out_err; 130 #endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ 131 132 return svc_prepare_thread(serv, &serv->sv_pools[0]); 133 134 out_err: 135 if (ret == 0) 136 ret = -ENOMEM; 137 return ERR_PTR(ret); 138 } 139 140 #if defined(CONFIG_NFS_V4_1) 141 /* 142 * The callback service for NFSv4.1 callbacks 143 */ 144 static int 145 nfs41_callback_svc(void *vrqstp) 146 { 147 struct svc_rqst *rqstp = vrqstp; 148 struct svc_serv *serv = rqstp->rq_server; 149 struct rpc_rqst *req; 150 int error; 151 DEFINE_WAIT(wq); 152 153 set_freezable(); 154 155 /* 156 * FIXME: do we really need to run this under the BKL? If so, please 157 * add a comment about what it's intended to protect. 158 */ 159 lock_kernel(); 160 while (!kthread_should_stop()) { 161 prepare_to_wait(&serv->sv_cb_waitq, &wq, TASK_INTERRUPTIBLE); 162 spin_lock_bh(&serv->sv_cb_lock); 163 if (!list_empty(&serv->sv_cb_list)) { 164 req = list_first_entry(&serv->sv_cb_list, 165 struct rpc_rqst, rq_bc_list); 166 list_del(&req->rq_bc_list); 167 spin_unlock_bh(&serv->sv_cb_lock); 168 dprintk("Invoking bc_svc_process()\n"); 169 error = bc_svc_process(serv, req, rqstp); 170 dprintk("bc_svc_process() returned w/ error code= %d\n", 171 error); 172 } else { 173 spin_unlock_bh(&serv->sv_cb_lock); 174 schedule(); 175 } 176 finish_wait(&serv->sv_cb_waitq, &wq); 177 } 178 unlock_kernel(); 179 return 0; 180 } 181 182 /* 183 * Bring up the NFSv4.1 callback service 184 */ 185 struct svc_rqst * 186 nfs41_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt) 187 { 188 struct svc_xprt *bc_xprt; 189 struct svc_rqst *rqstp = ERR_PTR(-ENOMEM); 190 191 dprintk("--> %s\n", __func__); 192 /* Create a svc_sock for the service */ 193 bc_xprt = svc_sock_create(serv, xprt->prot); 194 if (!bc_xprt) 195 goto out; 196 197 /* 198 * Save the svc_serv in the transport so that it can 199 * be referenced when the session backchannel is initialized 200 */ 201 serv->bc_xprt = bc_xprt; 202 xprt->bc_serv = serv; 203 204 INIT_LIST_HEAD(&serv->sv_cb_list); 205 spin_lock_init(&serv->sv_cb_lock); 206 init_waitqueue_head(&serv->sv_cb_waitq); 207 rqstp = svc_prepare_thread(serv, &serv->sv_pools[0]); 208 if (IS_ERR(rqstp)) 209 svc_sock_destroy(bc_xprt); 210 out: 211 dprintk("--> %s return %p\n", __func__, rqstp); 212 return rqstp; 213 } 214 215 static inline int nfs_minorversion_callback_svc_setup(u32 minorversion, 216 struct svc_serv *serv, struct rpc_xprt *xprt, 217 struct svc_rqst **rqstpp, int (**callback_svc)(void *vrqstp)) 218 { 219 if (minorversion) { 220 *rqstpp = nfs41_callback_up(serv, xprt); 221 *callback_svc = nfs41_callback_svc; 222 } 223 return minorversion; 224 } 225 226 static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt, 227 struct nfs_callback_data *cb_info) 228 { 229 if (minorversion) 230 xprt->bc_serv = cb_info->serv; 231 } 232 #else 233 static inline int nfs_minorversion_callback_svc_setup(u32 minorversion, 234 struct svc_serv *serv, struct rpc_xprt *xprt, 235 struct svc_rqst **rqstpp, int (**callback_svc)(void *vrqstp)) 236 { 237 return 0; 238 } 239 240 static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt, 241 struct nfs_callback_data *cb_info) 242 { 243 } 244 #endif /* CONFIG_NFS_V4_1 */ 245 246 /* 247 * Bring up the callback thread if it is not already up. 248 */ 249 int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt) 250 { 251 struct svc_serv *serv = NULL; 252 struct svc_rqst *rqstp; 253 int (*callback_svc)(void *vrqstp); 254 struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion]; 255 char svc_name[12]; 256 int ret = 0; 257 int minorversion_setup; 258 259 mutex_lock(&nfs_callback_mutex); 260 if (cb_info->users++ || cb_info->task != NULL) { 261 nfs_callback_bc_serv(minorversion, xprt, cb_info); 262 goto out; 263 } 264 serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL); 265 if (!serv) { 266 ret = -ENOMEM; 267 goto out_err; 268 } 269 270 minorversion_setup = nfs_minorversion_callback_svc_setup(minorversion, 271 serv, xprt, &rqstp, &callback_svc); 272 if (!minorversion_setup) { 273 /* v4.0 callback setup */ 274 rqstp = nfs4_callback_up(serv); 275 callback_svc = nfs4_callback_svc; 276 } 277 278 if (IS_ERR(rqstp)) { 279 ret = PTR_ERR(rqstp); 280 goto out_err; 281 } 282 283 svc_sock_update_bufs(serv); 284 285 sprintf(svc_name, "nfsv4.%u-svc", minorversion); 286 cb_info->serv = serv; 287 cb_info->rqst = rqstp; 288 cb_info->task = kthread_run(callback_svc, cb_info->rqst, svc_name); 289 if (IS_ERR(cb_info->task)) { 290 ret = PTR_ERR(cb_info->task); 291 svc_exit_thread(cb_info->rqst); 292 cb_info->rqst = NULL; 293 cb_info->task = NULL; 294 goto out_err; 295 } 296 out: 297 /* 298 * svc_create creates the svc_serv with sv_nrthreads == 1, and then 299 * svc_prepare_thread increments that. So we need to call svc_destroy 300 * on both success and failure so that the refcount is 1 when the 301 * thread exits. 302 */ 303 if (serv) 304 svc_destroy(serv); 305 mutex_unlock(&nfs_callback_mutex); 306 return ret; 307 out_err: 308 dprintk("NFS: Couldn't create callback socket or server thread; " 309 "err = %d\n", ret); 310 cb_info->users--; 311 goto out; 312 } 313 314 /* 315 * Kill the callback thread if it's no longer being used. 316 */ 317 void nfs_callback_down(int minorversion) 318 { 319 struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion]; 320 321 mutex_lock(&nfs_callback_mutex); 322 cb_info->users--; 323 if (cb_info->users == 0 && cb_info->task != NULL) { 324 kthread_stop(cb_info->task); 325 svc_exit_thread(cb_info->rqst); 326 cb_info->serv = NULL; 327 cb_info->rqst = NULL; 328 cb_info->task = NULL; 329 } 330 mutex_unlock(&nfs_callback_mutex); 331 } 332 333 static int check_gss_callback_principal(struct nfs_client *clp, 334 struct svc_rqst *rqstp) 335 { 336 struct rpc_clnt *r = clp->cl_rpcclient; 337 char *p = svc_gss_principal(rqstp); 338 339 /* 340 * It might just be a normal user principal, in which case 341 * userspace won't bother to tell us the name at all. 342 */ 343 if (p == NULL) 344 return SVC_DENIED; 345 346 /* Expect a GSS_C_NT_HOSTBASED_NAME like "nfs@serverhostname" */ 347 348 if (memcmp(p, "nfs@", 4) != 0) 349 return SVC_DENIED; 350 p += 4; 351 if (strcmp(p, r->cl_server) != 0) 352 return SVC_DENIED; 353 return SVC_OK; 354 } 355 356 static int nfs_callback_authenticate(struct svc_rqst *rqstp) 357 { 358 struct nfs_client *clp; 359 RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]); 360 int ret = SVC_OK; 361 362 /* Don't talk to strangers */ 363 clp = nfs_find_client(svc_addr(rqstp), 4); 364 if (clp == NULL) 365 return SVC_DROP; 366 367 dprintk("%s: %s NFSv4 callback!\n", __func__, 368 svc_print_addr(rqstp, buf, sizeof(buf))); 369 370 switch (rqstp->rq_authop->flavour) { 371 case RPC_AUTH_NULL: 372 if (rqstp->rq_proc != CB_NULL) 373 ret = SVC_DENIED; 374 break; 375 case RPC_AUTH_UNIX: 376 break; 377 case RPC_AUTH_GSS: 378 ret = check_gss_callback_principal(clp, rqstp); 379 break; 380 default: 381 ret = SVC_DENIED; 382 } 383 nfs_put_client(clp); 384 return ret; 385 } 386 387 /* 388 * Define NFS4 callback program 389 */ 390 static struct svc_version *nfs4_callback_version[] = { 391 [1] = &nfs4_callback_version1, 392 }; 393 394 static struct svc_stat nfs4_callback_stats; 395 396 static struct svc_program nfs4_callback_program = { 397 .pg_prog = NFS4_CALLBACK, /* RPC service number */ 398 .pg_nvers = ARRAY_SIZE(nfs4_callback_version), /* Number of entries */ 399 .pg_vers = nfs4_callback_version, /* version table */ 400 .pg_name = "NFSv4 callback", /* service name */ 401 .pg_class = "nfs", /* authentication class */ 402 .pg_stats = &nfs4_callback_stats, 403 .pg_authenticate = nfs_callback_authenticate, 404 }; 405