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_GPL(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 locks_end_grace(&lockd_manager); 185 if (nlmsvc_ops) 186 nlmsvc_invalidate_all(); 187 nlm_shutdown_hosts(); 188 unlock_kernel(); 189 return 0; 190 } 191 192 /* 193 * Ensure there are active UDP and TCP listeners for lockd. 194 * 195 * Even if we have only TCP NFS mounts and/or TCP NFSDs, some 196 * local services (such as rpc.statd) still require UDP, and 197 * some NFS servers do not yet support NLM over TCP. 198 * 199 * Returns zero if all listeners are available; otherwise a 200 * negative errno value is returned. 201 */ 202 static int make_socks(struct svc_serv *serv) 203 { 204 static int warned; 205 struct svc_xprt *xprt; 206 int err = 0; 207 208 xprt = svc_find_xprt(serv, "udp", 0, 0); 209 if (!xprt) 210 err = svc_create_xprt(serv, "udp", nlm_udpport, 211 SVC_SOCK_DEFAULTS); 212 else 213 svc_xprt_put(xprt); 214 if (err >= 0) { 215 xprt = svc_find_xprt(serv, "tcp", 0, 0); 216 if (!xprt) 217 err = svc_create_xprt(serv, "tcp", nlm_tcpport, 218 SVC_SOCK_DEFAULTS); 219 else 220 svc_xprt_put(xprt); 221 } 222 if (err >= 0) { 223 warned = 0; 224 err = 0; 225 } else if (warned++ == 0) 226 printk(KERN_WARNING 227 "lockd_up: makesock failed, error=%d\n", err); 228 return err; 229 } 230 231 /* 232 * Bring up the lockd process if it's not already up. 233 */ 234 int lockd_up(void) 235 { 236 struct svc_serv *serv; 237 int error = 0; 238 239 mutex_lock(&nlmsvc_mutex); 240 /* 241 * Check whether we're already up and running. 242 */ 243 if (nlmsvc_rqst) 244 goto out; 245 246 /* 247 * Sanity check: if there's no pid, 248 * we should be the first user ... 249 */ 250 if (nlmsvc_users) 251 printk(KERN_WARNING 252 "lockd_up: no pid, %d users??\n", nlmsvc_users); 253 254 error = -ENOMEM; 255 serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, AF_INET, NULL); 256 if (!serv) { 257 printk(KERN_WARNING "lockd_up: create service failed\n"); 258 goto out; 259 } 260 261 error = make_socks(serv); 262 if (error < 0) 263 goto destroy_and_out; 264 265 /* 266 * Create the kernel thread and wait for it to start. 267 */ 268 nlmsvc_rqst = svc_prepare_thread(serv, &serv->sv_pools[0]); 269 if (IS_ERR(nlmsvc_rqst)) { 270 error = PTR_ERR(nlmsvc_rqst); 271 nlmsvc_rqst = NULL; 272 printk(KERN_WARNING 273 "lockd_up: svc_rqst allocation failed, error=%d\n", 274 error); 275 goto destroy_and_out; 276 } 277 278 svc_sock_update_bufs(serv); 279 280 nlmsvc_task = kthread_run(lockd, nlmsvc_rqst, serv->sv_name); 281 if (IS_ERR(nlmsvc_task)) { 282 error = PTR_ERR(nlmsvc_task); 283 svc_exit_thread(nlmsvc_rqst); 284 nlmsvc_task = NULL; 285 nlmsvc_rqst = NULL; 286 printk(KERN_WARNING 287 "lockd_up: kthread_run failed, error=%d\n", error); 288 goto destroy_and_out; 289 } 290 291 /* 292 * Note: svc_serv structures have an initial use count of 1, 293 * so we exit through here on both success and failure. 294 */ 295 destroy_and_out: 296 svc_destroy(serv); 297 out: 298 if (!error) 299 nlmsvc_users++; 300 mutex_unlock(&nlmsvc_mutex); 301 return error; 302 } 303 EXPORT_SYMBOL_GPL(lockd_up); 304 305 /* 306 * Decrement the user count and bring down lockd if we're the last. 307 */ 308 void 309 lockd_down(void) 310 { 311 mutex_lock(&nlmsvc_mutex); 312 if (nlmsvc_users) { 313 if (--nlmsvc_users) 314 goto out; 315 } else { 316 printk(KERN_ERR "lockd_down: no users! task=%p\n", 317 nlmsvc_task); 318 BUG(); 319 } 320 321 if (!nlmsvc_task) { 322 printk(KERN_ERR "lockd_down: no lockd running.\n"); 323 BUG(); 324 } 325 kthread_stop(nlmsvc_task); 326 svc_exit_thread(nlmsvc_rqst); 327 nlmsvc_task = NULL; 328 nlmsvc_rqst = NULL; 329 out: 330 mutex_unlock(&nlmsvc_mutex); 331 } 332 EXPORT_SYMBOL_GPL(lockd_down); 333 334 #ifdef CONFIG_SYSCTL 335 336 /* 337 * Sysctl parameters (same as module parameters, different interface). 338 */ 339 340 static ctl_table nlm_sysctls[] = { 341 { 342 .ctl_name = CTL_UNNUMBERED, 343 .procname = "nlm_grace_period", 344 .data = &nlm_grace_period, 345 .maxlen = sizeof(unsigned long), 346 .mode = 0644, 347 .proc_handler = &proc_doulongvec_minmax, 348 .extra1 = (unsigned long *) &nlm_grace_period_min, 349 .extra2 = (unsigned long *) &nlm_grace_period_max, 350 }, 351 { 352 .ctl_name = CTL_UNNUMBERED, 353 .procname = "nlm_timeout", 354 .data = &nlm_timeout, 355 .maxlen = sizeof(unsigned long), 356 .mode = 0644, 357 .proc_handler = &proc_doulongvec_minmax, 358 .extra1 = (unsigned long *) &nlm_timeout_min, 359 .extra2 = (unsigned long *) &nlm_timeout_max, 360 }, 361 { 362 .ctl_name = CTL_UNNUMBERED, 363 .procname = "nlm_udpport", 364 .data = &nlm_udpport, 365 .maxlen = sizeof(int), 366 .mode = 0644, 367 .proc_handler = &proc_dointvec_minmax, 368 .extra1 = (int *) &nlm_port_min, 369 .extra2 = (int *) &nlm_port_max, 370 }, 371 { 372 .ctl_name = CTL_UNNUMBERED, 373 .procname = "nlm_tcpport", 374 .data = &nlm_tcpport, 375 .maxlen = sizeof(int), 376 .mode = 0644, 377 .proc_handler = &proc_dointvec_minmax, 378 .extra1 = (int *) &nlm_port_min, 379 .extra2 = (int *) &nlm_port_max, 380 }, 381 { 382 .ctl_name = CTL_UNNUMBERED, 383 .procname = "nsm_use_hostnames", 384 .data = &nsm_use_hostnames, 385 .maxlen = sizeof(int), 386 .mode = 0644, 387 .proc_handler = &proc_dointvec, 388 }, 389 { 390 .ctl_name = CTL_UNNUMBERED, 391 .procname = "nsm_local_state", 392 .data = &nsm_local_state, 393 .maxlen = sizeof(int), 394 .mode = 0644, 395 .proc_handler = &proc_dointvec, 396 }, 397 { .ctl_name = 0 } 398 }; 399 400 static ctl_table nlm_sysctl_dir[] = { 401 { 402 .ctl_name = CTL_UNNUMBERED, 403 .procname = "nfs", 404 .mode = 0555, 405 .child = nlm_sysctls, 406 }, 407 { .ctl_name = 0 } 408 }; 409 410 static ctl_table nlm_sysctl_root[] = { 411 { 412 .ctl_name = CTL_FS, 413 .procname = "fs", 414 .mode = 0555, 415 .child = nlm_sysctl_dir, 416 }, 417 { .ctl_name = 0 } 418 }; 419 420 #endif /* CONFIG_SYSCTL */ 421 422 /* 423 * Module (and sysfs) parameters. 424 */ 425 426 #define param_set_min_max(name, type, which_strtol, min, max) \ 427 static int param_set_##name(const char *val, struct kernel_param *kp) \ 428 { \ 429 char *endp; \ 430 __typeof__(type) num = which_strtol(val, &endp, 0); \ 431 if (endp == val || *endp || num < (min) || num > (max)) \ 432 return -EINVAL; \ 433 *((int *) kp->arg) = num; \ 434 return 0; \ 435 } 436 437 static inline int is_callback(u32 proc) 438 { 439 return proc == NLMPROC_GRANTED 440 || proc == NLMPROC_GRANTED_MSG 441 || proc == NLMPROC_TEST_RES 442 || proc == NLMPROC_LOCK_RES 443 || proc == NLMPROC_CANCEL_RES 444 || proc == NLMPROC_UNLOCK_RES 445 || proc == NLMPROC_NSM_NOTIFY; 446 } 447 448 449 static int lockd_authenticate(struct svc_rqst *rqstp) 450 { 451 rqstp->rq_client = NULL; 452 switch (rqstp->rq_authop->flavour) { 453 case RPC_AUTH_NULL: 454 case RPC_AUTH_UNIX: 455 if (rqstp->rq_proc == 0) 456 return SVC_OK; 457 if (is_callback(rqstp->rq_proc)) { 458 /* Leave it to individual procedures to 459 * call nlmsvc_lookup_host(rqstp) 460 */ 461 return SVC_OK; 462 } 463 return svc_set_client(rqstp); 464 } 465 return SVC_DENIED; 466 } 467 468 469 param_set_min_max(port, int, simple_strtol, 0, 65535) 470 param_set_min_max(grace_period, unsigned long, simple_strtoul, 471 nlm_grace_period_min, nlm_grace_period_max) 472 param_set_min_max(timeout, unsigned long, simple_strtoul, 473 nlm_timeout_min, nlm_timeout_max) 474 475 MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>"); 476 MODULE_DESCRIPTION("NFS file locking service version " LOCKD_VERSION "."); 477 MODULE_LICENSE("GPL"); 478 479 module_param_call(nlm_grace_period, param_set_grace_period, param_get_ulong, 480 &nlm_grace_period, 0644); 481 module_param_call(nlm_timeout, param_set_timeout, param_get_ulong, 482 &nlm_timeout, 0644); 483 module_param_call(nlm_udpport, param_set_port, param_get_int, 484 &nlm_udpport, 0644); 485 module_param_call(nlm_tcpport, param_set_port, param_get_int, 486 &nlm_tcpport, 0644); 487 module_param(nsm_use_hostnames, bool, 0644); 488 489 /* 490 * Initialising and terminating the module. 491 */ 492 493 static int __init init_nlm(void) 494 { 495 #ifdef CONFIG_SYSCTL 496 nlm_sysctl_table = register_sysctl_table(nlm_sysctl_root); 497 return nlm_sysctl_table ? 0 : -ENOMEM; 498 #else 499 return 0; 500 #endif 501 } 502 503 static void __exit exit_nlm(void) 504 { 505 /* FIXME: delete all NLM clients */ 506 nlm_shutdown_hosts(); 507 #ifdef CONFIG_SYSCTL 508 unregister_sysctl_table(nlm_sysctl_table); 509 #endif 510 } 511 512 module_init(init_nlm); 513 module_exit(exit_nlm); 514 515 /* 516 * Define NLM program and procedures 517 */ 518 static struct svc_version nlmsvc_version1 = { 519 .vs_vers = 1, 520 .vs_nproc = 17, 521 .vs_proc = nlmsvc_procedures, 522 .vs_xdrsize = NLMSVC_XDRSIZE, 523 }; 524 static struct svc_version nlmsvc_version3 = { 525 .vs_vers = 3, 526 .vs_nproc = 24, 527 .vs_proc = nlmsvc_procedures, 528 .vs_xdrsize = NLMSVC_XDRSIZE, 529 }; 530 #ifdef CONFIG_LOCKD_V4 531 static struct svc_version nlmsvc_version4 = { 532 .vs_vers = 4, 533 .vs_nproc = 24, 534 .vs_proc = nlmsvc_procedures4, 535 .vs_xdrsize = NLMSVC_XDRSIZE, 536 }; 537 #endif 538 static struct svc_version * nlmsvc_version[] = { 539 [1] = &nlmsvc_version1, 540 [3] = &nlmsvc_version3, 541 #ifdef CONFIG_LOCKD_V4 542 [4] = &nlmsvc_version4, 543 #endif 544 }; 545 546 static struct svc_stat nlmsvc_stats; 547 548 #define NLM_NRVERS ARRAY_SIZE(nlmsvc_version) 549 static struct svc_program nlmsvc_program = { 550 .pg_prog = NLM_PROGRAM, /* program number */ 551 .pg_nvers = NLM_NRVERS, /* number of entries in nlmsvc_version */ 552 .pg_vers = nlmsvc_version, /* version table */ 553 .pg_name = "lockd", /* service name */ 554 .pg_class = "nfsd", /* share authentication with nfsd */ 555 .pg_stats = &nlmsvc_stats, /* stats table */ 556 .pg_authenticate = &lockd_authenticate /* export authentication */ 557 }; 558