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/config.h> 16 #include <linux/module.h> 17 #include <linux/init.h> 18 #include <linux/sysctl.h> 19 #include <linux/moduleparam.h> 20 21 #include <linux/sched.h> 22 #include <linux/errno.h> 23 #include <linux/in.h> 24 #include <linux/uio.h> 25 #include <linux/slab.h> 26 #include <linux/smp.h> 27 #include <linux/smp_lock.h> 28 29 #include <linux/sunrpc/types.h> 30 #include <linux/sunrpc/stats.h> 31 #include <linux/sunrpc/clnt.h> 32 #include <linux/sunrpc/svc.h> 33 #include <linux/sunrpc/svcsock.h> 34 #include <linux/lockd/lockd.h> 35 #include <linux/nfs.h> 36 37 #define NLMDBG_FACILITY NLMDBG_SVC 38 #define LOCKD_BUFSIZE (1024 + NLMSVC_XDRSIZE) 39 #define ALLOWED_SIGS (sigmask(SIGKILL)) 40 41 static struct svc_program nlmsvc_program; 42 43 struct nlmsvc_binding * nlmsvc_ops; 44 EXPORT_SYMBOL(nlmsvc_ops); 45 46 static DECLARE_MUTEX(nlmsvc_sema); 47 static unsigned int nlmsvc_users; 48 static pid_t nlmsvc_pid; 49 int nlmsvc_grace_period; 50 unsigned long nlmsvc_timeout; 51 52 static DECLARE_MUTEX_LOCKED(lockd_start); 53 static DECLARE_WAIT_QUEUE_HEAD(lockd_exit); 54 55 /* 56 * These can be set at insmod time (useful for NFS as root filesystem), 57 * and also changed through the sysctl interface. -- Jamie Lokier, Aug 2003 58 */ 59 static unsigned long nlm_grace_period; 60 static unsigned long nlm_timeout = LOCKD_DFLT_TIMEO; 61 static int nlm_udpport, nlm_tcpport; 62 63 /* 64 * Constants needed for the sysctl interface. 65 */ 66 static const unsigned long nlm_grace_period_min = 0; 67 static const unsigned long nlm_grace_period_max = 240; 68 static const unsigned long nlm_timeout_min = 3; 69 static const unsigned long nlm_timeout_max = 20; 70 static const int nlm_port_min = 0, nlm_port_max = 65535; 71 72 static struct ctl_table_header * nlm_sysctl_table; 73 74 static unsigned long set_grace_period(void) 75 { 76 unsigned long grace_period; 77 78 /* Note: nlm_timeout should always be nonzero */ 79 if (nlm_grace_period) 80 grace_period = ((nlm_grace_period + nlm_timeout - 1) 81 / nlm_timeout) * nlm_timeout * HZ; 82 else 83 grace_period = nlm_timeout * 5 * HZ; 84 nlmsvc_grace_period = 1; 85 return grace_period + jiffies; 86 } 87 88 static inline void clear_grace_period(void) 89 { 90 nlmsvc_grace_period = 0; 91 } 92 93 /* 94 * This is the lockd kernel thread 95 */ 96 static void 97 lockd(struct svc_rqst *rqstp) 98 { 99 struct svc_serv *serv = rqstp->rq_server; 100 int err = 0; 101 unsigned long grace_period_expire; 102 103 /* Lock module and set up kernel thread */ 104 /* lockd_up is waiting for us to startup, so will 105 * be holding a reference to this module, so it 106 * is safe to just claim another reference 107 */ 108 __module_get(THIS_MODULE); 109 lock_kernel(); 110 111 /* 112 * Let our maker know we're running. 113 */ 114 nlmsvc_pid = current->pid; 115 up(&lockd_start); 116 117 daemonize("lockd"); 118 119 /* Process request with signals blocked, but allow SIGKILL. */ 120 allow_signal(SIGKILL); 121 122 /* kick rpciod */ 123 rpciod_up(); 124 125 dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n"); 126 127 if (!nlm_timeout) 128 nlm_timeout = LOCKD_DFLT_TIMEO; 129 nlmsvc_timeout = nlm_timeout * HZ; 130 131 grace_period_expire = set_grace_period(); 132 133 /* 134 * The main request loop. We don't terminate until the last 135 * NFS mount or NFS daemon has gone away, and we've been sent a 136 * signal, or else another process has taken over our job. 137 */ 138 while ((nlmsvc_users || !signalled()) && nlmsvc_pid == current->pid) { 139 long timeout = MAX_SCHEDULE_TIMEOUT; 140 141 if (signalled()) { 142 flush_signals(current); 143 if (nlmsvc_ops) { 144 nlmsvc_invalidate_all(); 145 grace_period_expire = set_grace_period(); 146 } 147 } 148 149 /* 150 * Retry any blocked locks that have been notified by 151 * the VFS. Don't do this during grace period. 152 * (Theoretically, there shouldn't even be blocked locks 153 * during grace period). 154 */ 155 if (!nlmsvc_grace_period) { 156 timeout = nlmsvc_retry_blocked(); 157 } else if (time_before(grace_period_expire, jiffies)) 158 clear_grace_period(); 159 160 /* 161 * Find a socket with data available and call its 162 * recvfrom routine. 163 */ 164 err = svc_recv(serv, rqstp, timeout); 165 if (err == -EAGAIN || err == -EINTR) 166 continue; 167 if (err < 0) { 168 printk(KERN_WARNING 169 "lockd: terminating on error %d\n", 170 -err); 171 break; 172 } 173 174 dprintk("lockd: request from %08x\n", 175 (unsigned)ntohl(rqstp->rq_addr.sin_addr.s_addr)); 176 177 svc_process(serv, rqstp); 178 179 } 180 181 flush_signals(current); 182 183 /* 184 * Check whether there's a new lockd process before 185 * shutting down the hosts and clearing the slot. 186 */ 187 if (!nlmsvc_pid || current->pid == nlmsvc_pid) { 188 if (nlmsvc_ops) 189 nlmsvc_invalidate_all(); 190 nlm_shutdown_hosts(); 191 nlmsvc_pid = 0; 192 } else 193 printk(KERN_DEBUG 194 "lockd: new process, skipping host shutdown\n"); 195 wake_up(&lockd_exit); 196 197 /* Exit the RPC thread */ 198 svc_exit_thread(rqstp); 199 200 /* release rpciod */ 201 rpciod_down(); 202 203 /* Release module */ 204 unlock_kernel(); 205 module_put_and_exit(0); 206 } 207 208 /* 209 * Bring up the lockd process if it's not already up. 210 */ 211 int 212 lockd_up(void) 213 { 214 static int warned; 215 struct svc_serv * serv; 216 int error = 0; 217 218 down(&nlmsvc_sema); 219 /* 220 * Unconditionally increment the user count ... this is 221 * the number of clients who _want_ a lockd process. 222 */ 223 nlmsvc_users++; 224 /* 225 * Check whether we're already up and running. 226 */ 227 if (nlmsvc_pid) 228 goto out; 229 230 /* 231 * Sanity check: if there's no pid, 232 * we should be the first user ... 233 */ 234 if (nlmsvc_users > 1) 235 printk(KERN_WARNING 236 "lockd_up: no pid, %d users??\n", nlmsvc_users); 237 238 error = -ENOMEM; 239 serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE); 240 if (!serv) { 241 printk(KERN_WARNING "lockd_up: create service failed\n"); 242 goto out; 243 } 244 245 if ((error = svc_makesock(serv, IPPROTO_UDP, nlm_udpport)) < 0 246 #ifdef CONFIG_NFSD_TCP 247 || (error = svc_makesock(serv, IPPROTO_TCP, nlm_tcpport)) < 0 248 #endif 249 ) { 250 if (warned++ == 0) 251 printk(KERN_WARNING 252 "lockd_up: makesock failed, error=%d\n", error); 253 goto destroy_and_out; 254 } 255 warned = 0; 256 257 /* 258 * Create the kernel thread and wait for it to start. 259 */ 260 error = svc_create_thread(lockd, serv); 261 if (error) { 262 printk(KERN_WARNING 263 "lockd_up: create thread failed, error=%d\n", error); 264 goto destroy_and_out; 265 } 266 down(&lockd_start); 267 268 /* 269 * Note: svc_serv structures have an initial use count of 1, 270 * so we exit through here on both success and failure. 271 */ 272 destroy_and_out: 273 svc_destroy(serv); 274 out: 275 up(&nlmsvc_sema); 276 return error; 277 } 278 EXPORT_SYMBOL(lockd_up); 279 280 /* 281 * Decrement the user count and bring down lockd if we're the last. 282 */ 283 void 284 lockd_down(void) 285 { 286 static int warned; 287 288 down(&nlmsvc_sema); 289 if (nlmsvc_users) { 290 if (--nlmsvc_users) 291 goto out; 292 } else 293 printk(KERN_WARNING "lockd_down: no users! pid=%d\n", nlmsvc_pid); 294 295 if (!nlmsvc_pid) { 296 if (warned++ == 0) 297 printk(KERN_WARNING "lockd_down: no lockd running.\n"); 298 goto out; 299 } 300 warned = 0; 301 302 kill_proc(nlmsvc_pid, SIGKILL, 1); 303 /* 304 * Wait for the lockd process to exit, but since we're holding 305 * the lockd semaphore, we can't wait around forever ... 306 */ 307 clear_thread_flag(TIF_SIGPENDING); 308 interruptible_sleep_on_timeout(&lockd_exit, HZ); 309 if (nlmsvc_pid) { 310 printk(KERN_WARNING 311 "lockd_down: lockd failed to exit, clearing pid\n"); 312 nlmsvc_pid = 0; 313 } 314 spin_lock_irq(¤t->sighand->siglock); 315 recalc_sigpending(); 316 spin_unlock_irq(¤t->sighand->siglock); 317 out: 318 up(&nlmsvc_sema); 319 } 320 EXPORT_SYMBOL(lockd_down); 321 322 /* 323 * Sysctl parameters (same as module parameters, different interface). 324 */ 325 326 /* Something that isn't CTL_ANY, CTL_NONE or a value that may clash. */ 327 #define CTL_UNNUMBERED -2 328 329 static ctl_table nlm_sysctls[] = { 330 { 331 .ctl_name = CTL_UNNUMBERED, 332 .procname = "nlm_grace_period", 333 .data = &nlm_grace_period, 334 .maxlen = sizeof(unsigned long), 335 .mode = 0644, 336 .proc_handler = &proc_doulongvec_minmax, 337 .extra1 = (unsigned long *) &nlm_grace_period_min, 338 .extra2 = (unsigned long *) &nlm_grace_period_max, 339 }, 340 { 341 .ctl_name = CTL_UNNUMBERED, 342 .procname = "nlm_timeout", 343 .data = &nlm_timeout, 344 .maxlen = sizeof(unsigned long), 345 .mode = 0644, 346 .proc_handler = &proc_doulongvec_minmax, 347 .extra1 = (unsigned long *) &nlm_timeout_min, 348 .extra2 = (unsigned long *) &nlm_timeout_max, 349 }, 350 { 351 .ctl_name = CTL_UNNUMBERED, 352 .procname = "nlm_udpport", 353 .data = &nlm_udpport, 354 .maxlen = sizeof(int), 355 .mode = 0644, 356 .proc_handler = &proc_dointvec_minmax, 357 .extra1 = (int *) &nlm_port_min, 358 .extra2 = (int *) &nlm_port_max, 359 }, 360 { 361 .ctl_name = CTL_UNNUMBERED, 362 .procname = "nlm_tcpport", 363 .data = &nlm_tcpport, 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 { .ctl_name = 0 } 371 }; 372 373 static ctl_table nlm_sysctl_dir[] = { 374 { 375 .ctl_name = CTL_UNNUMBERED, 376 .procname = "nfs", 377 .mode = 0555, 378 .child = nlm_sysctls, 379 }, 380 { .ctl_name = 0 } 381 }; 382 383 static ctl_table nlm_sysctl_root[] = { 384 { 385 .ctl_name = CTL_FS, 386 .procname = "fs", 387 .mode = 0555, 388 .child = nlm_sysctl_dir, 389 }, 390 { .ctl_name = 0 } 391 }; 392 393 /* 394 * Module (and driverfs) parameters. 395 */ 396 397 #define param_set_min_max(name, type, which_strtol, min, max) \ 398 static int param_set_##name(const char *val, struct kernel_param *kp) \ 399 { \ 400 char *endp; \ 401 __typeof__(type) num = which_strtol(val, &endp, 0); \ 402 if (endp == val || *endp || num < (min) || num > (max)) \ 403 return -EINVAL; \ 404 *((int *) kp->arg) = num; \ 405 return 0; \ 406 } 407 408 static inline int is_callback(u32 proc) 409 { 410 return proc == NLMPROC_GRANTED 411 || proc == NLMPROC_GRANTED_MSG 412 || proc == NLMPROC_TEST_RES 413 || proc == NLMPROC_LOCK_RES 414 || proc == NLMPROC_CANCEL_RES 415 || proc == NLMPROC_UNLOCK_RES 416 || proc == NLMPROC_NSM_NOTIFY; 417 } 418 419 420 static int lockd_authenticate(struct svc_rqst *rqstp) 421 { 422 rqstp->rq_client = NULL; 423 switch (rqstp->rq_authop->flavour) { 424 case RPC_AUTH_NULL: 425 case RPC_AUTH_UNIX: 426 if (rqstp->rq_proc == 0) 427 return SVC_OK; 428 if (is_callback(rqstp->rq_proc)) { 429 /* Leave it to individual procedures to 430 * call nlmsvc_lookup_host(rqstp) 431 */ 432 return SVC_OK; 433 } 434 return svc_set_client(rqstp); 435 } 436 return SVC_DENIED; 437 } 438 439 440 param_set_min_max(port, int, simple_strtol, 0, 65535) 441 param_set_min_max(grace_period, unsigned long, simple_strtoul, 442 nlm_grace_period_min, nlm_grace_period_max) 443 param_set_min_max(timeout, unsigned long, simple_strtoul, 444 nlm_timeout_min, nlm_timeout_max) 445 446 MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>"); 447 MODULE_DESCRIPTION("NFS file locking service version " LOCKD_VERSION "."); 448 MODULE_LICENSE("GPL"); 449 450 module_param_call(nlm_grace_period, param_set_grace_period, param_get_ulong, 451 &nlm_grace_period, 0644); 452 module_param_call(nlm_timeout, param_set_timeout, param_get_ulong, 453 &nlm_timeout, 0644); 454 module_param_call(nlm_udpport, param_set_port, param_get_int, 455 &nlm_udpport, 0644); 456 module_param_call(nlm_tcpport, param_set_port, param_get_int, 457 &nlm_tcpport, 0644); 458 459 /* 460 * Initialising and terminating the module. 461 */ 462 463 static int __init init_nlm(void) 464 { 465 nlm_sysctl_table = register_sysctl_table(nlm_sysctl_root, 0); 466 return nlm_sysctl_table ? 0 : -ENOMEM; 467 } 468 469 static void __exit exit_nlm(void) 470 { 471 /* FIXME: delete all NLM clients */ 472 nlm_shutdown_hosts(); 473 unregister_sysctl_table(nlm_sysctl_table); 474 } 475 476 module_init(init_nlm); 477 module_exit(exit_nlm); 478 479 /* 480 * Define NLM program and procedures 481 */ 482 static struct svc_version nlmsvc_version1 = { 483 .vs_vers = 1, 484 .vs_nproc = 17, 485 .vs_proc = nlmsvc_procedures, 486 .vs_xdrsize = NLMSVC_XDRSIZE, 487 }; 488 static struct svc_version nlmsvc_version3 = { 489 .vs_vers = 3, 490 .vs_nproc = 24, 491 .vs_proc = nlmsvc_procedures, 492 .vs_xdrsize = NLMSVC_XDRSIZE, 493 }; 494 #ifdef CONFIG_LOCKD_V4 495 static struct svc_version nlmsvc_version4 = { 496 .vs_vers = 4, 497 .vs_nproc = 24, 498 .vs_proc = nlmsvc_procedures4, 499 .vs_xdrsize = NLMSVC_XDRSIZE, 500 }; 501 #endif 502 static struct svc_version * nlmsvc_version[] = { 503 [1] = &nlmsvc_version1, 504 [3] = &nlmsvc_version3, 505 #ifdef CONFIG_LOCKD_V4 506 [4] = &nlmsvc_version4, 507 #endif 508 }; 509 510 static struct svc_stat nlmsvc_stats; 511 512 #define NLM_NRVERS (sizeof(nlmsvc_version)/sizeof(nlmsvc_version[0])) 513 static struct svc_program nlmsvc_program = { 514 .pg_prog = NLM_PROGRAM, /* program number */ 515 .pg_nvers = NLM_NRVERS, /* number of entries in nlmsvc_version */ 516 .pg_vers = nlmsvc_version, /* version table */ 517 .pg_name = "lockd", /* service name */ 518 .pg_class = "nfsd", /* share authentication with nfsd */ 519 .pg_stats = &nlmsvc_stats, /* stats table */ 520 .pg_authenticate = &lockd_authenticate /* export authentication */ 521 }; 522