1 /* 2 * linux/fs/lockd/svc.c 3 * 4 * This is the central lockd service. 5 * 6 * FIXME: Separate the lockd NFS server functionality from the lockd NFS 7 * client functionality. Oh why didn't Sun create two separate 8 * services in the first place? 9 * 10 * Authors: Olaf Kirch (okir@monad.swb.de) 11 * 12 * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> 13 */ 14 15 #include <linux/module.h> 16 #include <linux/init.h> 17 #include <linux/sysctl.h> 18 #include <linux/moduleparam.h> 19 20 #include <linux/sched.h> 21 #include <linux/errno.h> 22 #include <linux/in.h> 23 #include <linux/uio.h> 24 #include <linux/slab.h> 25 #include <linux/smp.h> 26 #include <linux/smp_lock.h> 27 #include <linux/mutex.h> 28 #include <linux/kthread.h> 29 #include <linux/freezer.h> 30 31 #include <linux/sunrpc/types.h> 32 #include <linux/sunrpc/stats.h> 33 #include <linux/sunrpc/clnt.h> 34 #include <linux/sunrpc/svc.h> 35 #include <linux/sunrpc/svcsock.h> 36 #include <net/ip.h> 37 #include <linux/lockd/lockd.h> 38 #include <linux/lockd/sm_inter.h> 39 #include <linux/nfs.h> 40 41 #define NLMDBG_FACILITY NLMDBG_SVC 42 #define LOCKD_BUFSIZE (1024 + NLMSVC_XDRSIZE) 43 #define ALLOWED_SIGS (sigmask(SIGKILL)) 44 45 static struct svc_program nlmsvc_program; 46 47 struct nlmsvc_binding * nlmsvc_ops; 48 EXPORT_SYMBOL(nlmsvc_ops); 49 50 static DEFINE_MUTEX(nlmsvc_mutex); 51 static unsigned int nlmsvc_users; 52 static struct task_struct *nlmsvc_task; 53 static struct svc_rqst *nlmsvc_rqst; 54 unsigned long nlmsvc_timeout; 55 56 /* 57 * These can be set at insmod time (useful for NFS as root filesystem), 58 * and also changed through the sysctl interface. -- Jamie Lokier, Aug 2003 59 */ 60 static unsigned long nlm_grace_period; 61 static unsigned long nlm_timeout = LOCKD_DFLT_TIMEO; 62 static int nlm_udpport, nlm_tcpport; 63 int nsm_use_hostnames = 0; 64 65 /* 66 * Constants needed for the sysctl interface. 67 */ 68 static const unsigned long nlm_grace_period_min = 0; 69 static const unsigned long nlm_grace_period_max = 240; 70 static const unsigned long nlm_timeout_min = 3; 71 static const unsigned long nlm_timeout_max = 20; 72 static const int nlm_port_min = 0, nlm_port_max = 65535; 73 74 #ifdef CONFIG_SYSCTL 75 static struct ctl_table_header * nlm_sysctl_table; 76 #endif 77 78 static unsigned long get_lockd_grace_period(void) 79 { 80 /* Note: nlm_timeout should always be nonzero */ 81 if (nlm_grace_period) 82 return roundup(nlm_grace_period, nlm_timeout) * HZ; 83 else 84 return nlm_timeout * 5 * HZ; 85 } 86 87 static struct lock_manager lockd_manager = { 88 }; 89 90 static void grace_ender(struct work_struct *not_used) 91 { 92 locks_end_grace(&lockd_manager); 93 } 94 95 static DECLARE_DELAYED_WORK(grace_period_end, grace_ender); 96 97 static void set_grace_period(void) 98 { 99 unsigned long grace_period = get_lockd_grace_period(); 100 101 locks_start_grace(&lockd_manager); 102 cancel_delayed_work_sync(&grace_period_end); 103 schedule_delayed_work(&grace_period_end, grace_period); 104 } 105 106 /* 107 * This is the lockd kernel thread 108 */ 109 static int 110 lockd(void *vrqstp) 111 { 112 int err = 0, preverr = 0; 113 struct svc_rqst *rqstp = vrqstp; 114 115 /* try_to_freeze() is called from svc_recv() */ 116 set_freezable(); 117 118 /* Allow SIGKILL to tell lockd to drop all of its locks */ 119 allow_signal(SIGKILL); 120 121 dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n"); 122 123 /* 124 * FIXME: it would be nice if lockd didn't spend its entire life 125 * running under the BKL. At the very least, it would be good to 126 * have someone clarify what it's intended to protect here. I've 127 * seen some handwavy posts about posix locking needing to be 128 * done under the BKL, but it's far from clear. 129 */ 130 lock_kernel(); 131 132 if (!nlm_timeout) 133 nlm_timeout = LOCKD_DFLT_TIMEO; 134 nlmsvc_timeout = nlm_timeout * HZ; 135 136 set_grace_period(); 137 138 /* 139 * The main request loop. We don't terminate until the last 140 * NFS mount or NFS daemon has gone away. 141 */ 142 while (!kthread_should_stop()) { 143 long timeout = MAX_SCHEDULE_TIMEOUT; 144 RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]); 145 146 if (signalled()) { 147 flush_signals(current); 148 if (nlmsvc_ops) { 149 nlmsvc_invalidate_all(); 150 set_grace_period(); 151 } 152 continue; 153 } 154 155 timeout = nlmsvc_retry_blocked(); 156 157 /* 158 * Find a socket with data available and call its 159 * recvfrom routine. 160 */ 161 err = svc_recv(rqstp, timeout); 162 if (err == -EAGAIN || err == -EINTR) { 163 preverr = err; 164 continue; 165 } 166 if (err < 0) { 167 if (err != preverr) { 168 printk(KERN_WARNING "%s: unexpected error " 169 "from svc_recv (%d)\n", __func__, err); 170 preverr = err; 171 } 172 schedule_timeout_interruptible(HZ); 173 continue; 174 } 175 preverr = err; 176 177 dprintk("lockd: request from %s\n", 178 svc_print_addr(rqstp, buf, sizeof(buf))); 179 180 svc_process(rqstp); 181 } 182 flush_signals(current); 183 cancel_delayed_work_sync(&grace_period_end); 184 if (nlmsvc_ops) 185 nlmsvc_invalidate_all(); 186 nlm_shutdown_hosts(); 187 unlock_kernel(); 188 return 0; 189 } 190 191 /* 192 * Ensure there are active UDP and TCP listeners for lockd. 193 * 194 * Even if we have only TCP NFS mounts and/or TCP NFSDs, some 195 * local services (such as rpc.statd) still require UDP, and 196 * some NFS servers do not yet support NLM over TCP. 197 * 198 * Returns zero if all listeners are available; otherwise a 199 * negative errno value is returned. 200 */ 201 static int make_socks(struct svc_serv *serv) 202 { 203 static int warned; 204 struct svc_xprt *xprt; 205 int err = 0; 206 207 xprt = svc_find_xprt(serv, "udp", 0, 0); 208 if (!xprt) 209 err = svc_create_xprt(serv, "udp", nlm_udpport, 210 SVC_SOCK_DEFAULTS); 211 else 212 svc_xprt_put(xprt); 213 if (err >= 0) { 214 xprt = svc_find_xprt(serv, "tcp", 0, 0); 215 if (!xprt) 216 err = svc_create_xprt(serv, "tcp", nlm_tcpport, 217 SVC_SOCK_DEFAULTS); 218 else 219 svc_xprt_put(xprt); 220 } 221 if (err >= 0) { 222 warned = 0; 223 err = 0; 224 } else if (warned++ == 0) 225 printk(KERN_WARNING 226 "lockd_up: makesock failed, error=%d\n", err); 227 return err; 228 } 229 230 /* 231 * Bring up the lockd process if it's not already up. 232 */ 233 int lockd_up(void) 234 { 235 struct svc_serv *serv; 236 int error = 0; 237 238 mutex_lock(&nlmsvc_mutex); 239 /* 240 * Check whether we're already up and running. 241 */ 242 if (nlmsvc_rqst) 243 goto out; 244 245 /* 246 * Sanity check: if there's no pid, 247 * we should be the first user ... 248 */ 249 if (nlmsvc_users) 250 printk(KERN_WARNING 251 "lockd_up: no pid, %d users??\n", nlmsvc_users); 252 253 error = -ENOMEM; 254 serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, AF_INET, NULL); 255 if (!serv) { 256 printk(KERN_WARNING "lockd_up: create service failed\n"); 257 goto out; 258 } 259 260 error = make_socks(serv); 261 if (error < 0) 262 goto destroy_and_out; 263 264 /* 265 * Create the kernel thread and wait for it to start. 266 */ 267 nlmsvc_rqst = svc_prepare_thread(serv, &serv->sv_pools[0]); 268 if (IS_ERR(nlmsvc_rqst)) { 269 error = PTR_ERR(nlmsvc_rqst); 270 nlmsvc_rqst = NULL; 271 printk(KERN_WARNING 272 "lockd_up: svc_rqst allocation failed, error=%d\n", 273 error); 274 goto destroy_and_out; 275 } 276 277 svc_sock_update_bufs(serv); 278 279 nlmsvc_task = kthread_run(lockd, nlmsvc_rqst, serv->sv_name); 280 if (IS_ERR(nlmsvc_task)) { 281 error = PTR_ERR(nlmsvc_task); 282 svc_exit_thread(nlmsvc_rqst); 283 nlmsvc_task = NULL; 284 nlmsvc_rqst = NULL; 285 printk(KERN_WARNING 286 "lockd_up: kthread_run failed, error=%d\n", error); 287 goto destroy_and_out; 288 } 289 290 /* 291 * Note: svc_serv structures have an initial use count of 1, 292 * so we exit through here on both success and failure. 293 */ 294 destroy_and_out: 295 svc_destroy(serv); 296 out: 297 if (!error) 298 nlmsvc_users++; 299 mutex_unlock(&nlmsvc_mutex); 300 return error; 301 } 302 EXPORT_SYMBOL(lockd_up); 303 304 /* 305 * Decrement the user count and bring down lockd if we're the last. 306 */ 307 void 308 lockd_down(void) 309 { 310 mutex_lock(&nlmsvc_mutex); 311 if (nlmsvc_users) { 312 if (--nlmsvc_users) 313 goto out; 314 } else { 315 printk(KERN_ERR "lockd_down: no users! task=%p\n", 316 nlmsvc_task); 317 BUG(); 318 } 319 320 if (!nlmsvc_task) { 321 printk(KERN_ERR "lockd_down: no lockd running.\n"); 322 BUG(); 323 } 324 kthread_stop(nlmsvc_task); 325 svc_exit_thread(nlmsvc_rqst); 326 nlmsvc_task = NULL; 327 nlmsvc_rqst = NULL; 328 out: 329 mutex_unlock(&nlmsvc_mutex); 330 } 331 EXPORT_SYMBOL(lockd_down); 332 333 #ifdef CONFIG_SYSCTL 334 335 /* 336 * Sysctl parameters (same as module parameters, different interface). 337 */ 338 339 static ctl_table nlm_sysctls[] = { 340 { 341 .ctl_name = CTL_UNNUMBERED, 342 .procname = "nlm_grace_period", 343 .data = &nlm_grace_period, 344 .maxlen = sizeof(unsigned long), 345 .mode = 0644, 346 .proc_handler = &proc_doulongvec_minmax, 347 .extra1 = (unsigned long *) &nlm_grace_period_min, 348 .extra2 = (unsigned long *) &nlm_grace_period_max, 349 }, 350 { 351 .ctl_name = CTL_UNNUMBERED, 352 .procname = "nlm_timeout", 353 .data = &nlm_timeout, 354 .maxlen = sizeof(unsigned long), 355 .mode = 0644, 356 .proc_handler = &proc_doulongvec_minmax, 357 .extra1 = (unsigned long *) &nlm_timeout_min, 358 .extra2 = (unsigned long *) &nlm_timeout_max, 359 }, 360 { 361 .ctl_name = CTL_UNNUMBERED, 362 .procname = "nlm_udpport", 363 .data = &nlm_udpport, 364 .maxlen = sizeof(int), 365 .mode = 0644, 366 .proc_handler = &proc_dointvec_minmax, 367 .extra1 = (int *) &nlm_port_min, 368 .extra2 = (int *) &nlm_port_max, 369 }, 370 { 371 .ctl_name = CTL_UNNUMBERED, 372 .procname = "nlm_tcpport", 373 .data = &nlm_tcpport, 374 .maxlen = sizeof(int), 375 .mode = 0644, 376 .proc_handler = &proc_dointvec_minmax, 377 .extra1 = (int *) &nlm_port_min, 378 .extra2 = (int *) &nlm_port_max, 379 }, 380 { 381 .ctl_name = CTL_UNNUMBERED, 382 .procname = "nsm_use_hostnames", 383 .data = &nsm_use_hostnames, 384 .maxlen = sizeof(int), 385 .mode = 0644, 386 .proc_handler = &proc_dointvec, 387 }, 388 { 389 .ctl_name = CTL_UNNUMBERED, 390 .procname = "nsm_local_state", 391 .data = &nsm_local_state, 392 .maxlen = sizeof(int), 393 .mode = 0644, 394 .proc_handler = &proc_dointvec, 395 }, 396 { .ctl_name = 0 } 397 }; 398 399 static ctl_table nlm_sysctl_dir[] = { 400 { 401 .ctl_name = CTL_UNNUMBERED, 402 .procname = "nfs", 403 .mode = 0555, 404 .child = nlm_sysctls, 405 }, 406 { .ctl_name = 0 } 407 }; 408 409 static ctl_table nlm_sysctl_root[] = { 410 { 411 .ctl_name = CTL_FS, 412 .procname = "fs", 413 .mode = 0555, 414 .child = nlm_sysctl_dir, 415 }, 416 { .ctl_name = 0 } 417 }; 418 419 #endif /* CONFIG_SYSCTL */ 420 421 /* 422 * Module (and sysfs) parameters. 423 */ 424 425 #define param_set_min_max(name, type, which_strtol, min, max) \ 426 static int param_set_##name(const char *val, struct kernel_param *kp) \ 427 { \ 428 char *endp; \ 429 __typeof__(type) num = which_strtol(val, &endp, 0); \ 430 if (endp == val || *endp || num < (min) || num > (max)) \ 431 return -EINVAL; \ 432 *((int *) kp->arg) = num; \ 433 return 0; \ 434 } 435 436 static inline int is_callback(u32 proc) 437 { 438 return proc == NLMPROC_GRANTED 439 || proc == NLMPROC_GRANTED_MSG 440 || proc == NLMPROC_TEST_RES 441 || proc == NLMPROC_LOCK_RES 442 || proc == NLMPROC_CANCEL_RES 443 || proc == NLMPROC_UNLOCK_RES 444 || proc == NLMPROC_NSM_NOTIFY; 445 } 446 447 448 static int lockd_authenticate(struct svc_rqst *rqstp) 449 { 450 rqstp->rq_client = NULL; 451 switch (rqstp->rq_authop->flavour) { 452 case RPC_AUTH_NULL: 453 case RPC_AUTH_UNIX: 454 if (rqstp->rq_proc == 0) 455 return SVC_OK; 456 if (is_callback(rqstp->rq_proc)) { 457 /* Leave it to individual procedures to 458 * call nlmsvc_lookup_host(rqstp) 459 */ 460 return SVC_OK; 461 } 462 return svc_set_client(rqstp); 463 } 464 return SVC_DENIED; 465 } 466 467 468 param_set_min_max(port, int, simple_strtol, 0, 65535) 469 param_set_min_max(grace_period, unsigned long, simple_strtoul, 470 nlm_grace_period_min, nlm_grace_period_max) 471 param_set_min_max(timeout, unsigned long, simple_strtoul, 472 nlm_timeout_min, nlm_timeout_max) 473 474 MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>"); 475 MODULE_DESCRIPTION("NFS file locking service version " LOCKD_VERSION "."); 476 MODULE_LICENSE("GPL"); 477 478 module_param_call(nlm_grace_period, param_set_grace_period, param_get_ulong, 479 &nlm_grace_period, 0644); 480 module_param_call(nlm_timeout, param_set_timeout, param_get_ulong, 481 &nlm_timeout, 0644); 482 module_param_call(nlm_udpport, param_set_port, param_get_int, 483 &nlm_udpport, 0644); 484 module_param_call(nlm_tcpport, param_set_port, param_get_int, 485 &nlm_tcpport, 0644); 486 module_param(nsm_use_hostnames, bool, 0644); 487 488 /* 489 * Initialising and terminating the module. 490 */ 491 492 static int __init init_nlm(void) 493 { 494 #ifdef CONFIG_SYSCTL 495 nlm_sysctl_table = register_sysctl_table(nlm_sysctl_root); 496 return nlm_sysctl_table ? 0 : -ENOMEM; 497 #else 498 return 0; 499 #endif 500 } 501 502 static void __exit exit_nlm(void) 503 { 504 /* FIXME: delete all NLM clients */ 505 nlm_shutdown_hosts(); 506 #ifdef CONFIG_SYSCTL 507 unregister_sysctl_table(nlm_sysctl_table); 508 #endif 509 } 510 511 module_init(init_nlm); 512 module_exit(exit_nlm); 513 514 /* 515 * Define NLM program and procedures 516 */ 517 static struct svc_version nlmsvc_version1 = { 518 .vs_vers = 1, 519 .vs_nproc = 17, 520 .vs_proc = nlmsvc_procedures, 521 .vs_xdrsize = NLMSVC_XDRSIZE, 522 }; 523 static struct svc_version nlmsvc_version3 = { 524 .vs_vers = 3, 525 .vs_nproc = 24, 526 .vs_proc = nlmsvc_procedures, 527 .vs_xdrsize = NLMSVC_XDRSIZE, 528 }; 529 #ifdef CONFIG_LOCKD_V4 530 static struct svc_version nlmsvc_version4 = { 531 .vs_vers = 4, 532 .vs_nproc = 24, 533 .vs_proc = nlmsvc_procedures4, 534 .vs_xdrsize = NLMSVC_XDRSIZE, 535 }; 536 #endif 537 static struct svc_version * nlmsvc_version[] = { 538 [1] = &nlmsvc_version1, 539 [3] = &nlmsvc_version3, 540 #ifdef CONFIG_LOCKD_V4 541 [4] = &nlmsvc_version4, 542 #endif 543 }; 544 545 static struct svc_stat nlmsvc_stats; 546 547 #define NLM_NRVERS ARRAY_SIZE(nlmsvc_version) 548 static struct svc_program nlmsvc_program = { 549 .pg_prog = NLM_PROGRAM, /* program number */ 550 .pg_nvers = NLM_NRVERS, /* number of entries in nlmsvc_version */ 551 .pg_vers = nlmsvc_version, /* version table */ 552 .pg_name = "lockd", /* service name */ 553 .pg_class = "nfsd", /* share authentication with nfsd */ 554 .pg_stats = &nlmsvc_stats, /* stats table */ 555 .pg_authenticate = &lockd_authenticate /* export authentication */ 556 }; 557