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 /* 182 * Check whether there's a new lockd process before 183 * shutting down the hosts and clearing the slot. 184 */ 185 if (!nlmsvc_pid || current->pid == nlmsvc_pid) { 186 if (nlmsvc_ops) 187 nlmsvc_invalidate_all(); 188 nlm_shutdown_hosts(); 189 nlmsvc_pid = 0; 190 } else 191 printk(KERN_DEBUG 192 "lockd: new process, skipping host shutdown\n"); 193 wake_up(&lockd_exit); 194 195 /* Exit the RPC thread */ 196 svc_exit_thread(rqstp); 197 198 /* release rpciod */ 199 rpciod_down(); 200 201 /* Release module */ 202 unlock_kernel(); 203 module_put_and_exit(0); 204 } 205 206 /* 207 * Bring up the lockd process if it's not already up. 208 */ 209 int 210 lockd_up(void) 211 { 212 static int warned; 213 struct svc_serv * serv; 214 int error = 0; 215 216 down(&nlmsvc_sema); 217 /* 218 * Unconditionally increment the user count ... this is 219 * the number of clients who _want_ a lockd process. 220 */ 221 nlmsvc_users++; 222 /* 223 * Check whether we're already up and running. 224 */ 225 if (nlmsvc_pid) 226 goto out; 227 228 /* 229 * Sanity check: if there's no pid, 230 * we should be the first user ... 231 */ 232 if (nlmsvc_users > 1) 233 printk(KERN_WARNING 234 "lockd_up: no pid, %d users??\n", nlmsvc_users); 235 236 error = -ENOMEM; 237 serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE); 238 if (!serv) { 239 printk(KERN_WARNING "lockd_up: create service failed\n"); 240 goto out; 241 } 242 243 if ((error = svc_makesock(serv, IPPROTO_UDP, nlm_udpport)) < 0 244 #ifdef CONFIG_NFSD_TCP 245 || (error = svc_makesock(serv, IPPROTO_TCP, nlm_tcpport)) < 0 246 #endif 247 ) { 248 if (warned++ == 0) 249 printk(KERN_WARNING 250 "lockd_up: makesock failed, error=%d\n", error); 251 goto destroy_and_out; 252 } 253 warned = 0; 254 255 /* 256 * Create the kernel thread and wait for it to start. 257 */ 258 error = svc_create_thread(lockd, serv); 259 if (error) { 260 printk(KERN_WARNING 261 "lockd_up: create thread failed, error=%d\n", error); 262 goto destroy_and_out; 263 } 264 down(&lockd_start); 265 266 /* 267 * Note: svc_serv structures have an initial use count of 1, 268 * so we exit through here on both success and failure. 269 */ 270 destroy_and_out: 271 svc_destroy(serv); 272 out: 273 up(&nlmsvc_sema); 274 return error; 275 } 276 EXPORT_SYMBOL(lockd_up); 277 278 /* 279 * Decrement the user count and bring down lockd if we're the last. 280 */ 281 void 282 lockd_down(void) 283 { 284 static int warned; 285 286 down(&nlmsvc_sema); 287 if (nlmsvc_users) { 288 if (--nlmsvc_users) 289 goto out; 290 } else 291 printk(KERN_WARNING "lockd_down: no users! pid=%d\n", nlmsvc_pid); 292 293 if (!nlmsvc_pid) { 294 if (warned++ == 0) 295 printk(KERN_WARNING "lockd_down: no lockd running.\n"); 296 goto out; 297 } 298 warned = 0; 299 300 kill_proc(nlmsvc_pid, SIGKILL, 1); 301 /* 302 * Wait for the lockd process to exit, but since we're holding 303 * the lockd semaphore, we can't wait around forever ... 304 */ 305 clear_thread_flag(TIF_SIGPENDING); 306 interruptible_sleep_on_timeout(&lockd_exit, HZ); 307 if (nlmsvc_pid) { 308 printk(KERN_WARNING 309 "lockd_down: lockd failed to exit, clearing pid\n"); 310 nlmsvc_pid = 0; 311 } 312 spin_lock_irq(¤t->sighand->siglock); 313 recalc_sigpending(); 314 spin_unlock_irq(¤t->sighand->siglock); 315 out: 316 up(&nlmsvc_sema); 317 } 318 EXPORT_SYMBOL(lockd_down); 319 320 /* 321 * Sysctl parameters (same as module parameters, different interface). 322 */ 323 324 /* Something that isn't CTL_ANY, CTL_NONE or a value that may clash. */ 325 #define CTL_UNNUMBERED -2 326 327 static ctl_table nlm_sysctls[] = { 328 { 329 .ctl_name = CTL_UNNUMBERED, 330 .procname = "nlm_grace_period", 331 .data = &nlm_grace_period, 332 .maxlen = sizeof(int), 333 .mode = 0644, 334 .proc_handler = &proc_doulongvec_minmax, 335 .extra1 = (unsigned long *) &nlm_grace_period_min, 336 .extra2 = (unsigned long *) &nlm_grace_period_max, 337 }, 338 { 339 .ctl_name = CTL_UNNUMBERED, 340 .procname = "nlm_timeout", 341 .data = &nlm_timeout, 342 .maxlen = sizeof(int), 343 .mode = 0644, 344 .proc_handler = &proc_doulongvec_minmax, 345 .extra1 = (unsigned long *) &nlm_timeout_min, 346 .extra2 = (unsigned long *) &nlm_timeout_max, 347 }, 348 { 349 .ctl_name = CTL_UNNUMBERED, 350 .procname = "nlm_udpport", 351 .data = &nlm_udpport, 352 .maxlen = sizeof(int), 353 .mode = 0644, 354 .proc_handler = &proc_dointvec_minmax, 355 .extra1 = (int *) &nlm_port_min, 356 .extra2 = (int *) &nlm_port_max, 357 }, 358 { 359 .ctl_name = CTL_UNNUMBERED, 360 .procname = "nlm_tcpport", 361 .data = &nlm_tcpport, 362 .maxlen = sizeof(int), 363 .mode = 0644, 364 .proc_handler = &proc_dointvec_minmax, 365 .extra1 = (int *) &nlm_port_min, 366 .extra2 = (int *) &nlm_port_max, 367 }, 368 { .ctl_name = 0 } 369 }; 370 371 static ctl_table nlm_sysctl_dir[] = { 372 { 373 .ctl_name = CTL_UNNUMBERED, 374 .procname = "nfs", 375 .mode = 0555, 376 .child = nlm_sysctls, 377 }, 378 { .ctl_name = 0 } 379 }; 380 381 static ctl_table nlm_sysctl_root[] = { 382 { 383 .ctl_name = CTL_FS, 384 .procname = "fs", 385 .mode = 0555, 386 .child = nlm_sysctl_dir, 387 }, 388 { .ctl_name = 0 } 389 }; 390 391 /* 392 * Module (and driverfs) parameters. 393 */ 394 395 #define param_set_min_max(name, type, which_strtol, min, max) \ 396 static int param_set_##name(const char *val, struct kernel_param *kp) \ 397 { \ 398 char *endp; \ 399 __typeof__(type) num = which_strtol(val, &endp, 0); \ 400 if (endp == val || *endp || num < (min) || num > (max)) \ 401 return -EINVAL; \ 402 *((int *) kp->arg) = num; \ 403 return 0; \ 404 } 405 406 static inline int is_callback(u32 proc) 407 { 408 return proc == NLMPROC_GRANTED 409 || proc == NLMPROC_GRANTED_MSG 410 || proc == NLMPROC_TEST_RES 411 || proc == NLMPROC_LOCK_RES 412 || proc == NLMPROC_CANCEL_RES 413 || proc == NLMPROC_UNLOCK_RES 414 || proc == NLMPROC_NSM_NOTIFY; 415 } 416 417 418 static int lockd_authenticate(struct svc_rqst *rqstp) 419 { 420 rqstp->rq_client = NULL; 421 switch (rqstp->rq_authop->flavour) { 422 case RPC_AUTH_NULL: 423 case RPC_AUTH_UNIX: 424 if (rqstp->rq_proc == 0) 425 return SVC_OK; 426 if (is_callback(rqstp->rq_proc)) { 427 /* Leave it to individual procedures to 428 * call nlmsvc_lookup_host(rqstp) 429 */ 430 return SVC_OK; 431 } 432 return svc_set_client(rqstp); 433 } 434 return SVC_DENIED; 435 } 436 437 438 param_set_min_max(port, int, simple_strtol, 0, 65535) 439 param_set_min_max(grace_period, unsigned long, simple_strtoul, 440 nlm_grace_period_min, nlm_grace_period_max) 441 param_set_min_max(timeout, unsigned long, simple_strtoul, 442 nlm_timeout_min, nlm_timeout_max) 443 444 MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>"); 445 MODULE_DESCRIPTION("NFS file locking service version " LOCKD_VERSION "."); 446 MODULE_LICENSE("GPL"); 447 448 module_param_call(nlm_grace_period, param_set_grace_period, param_get_ulong, 449 &nlm_grace_period, 0644); 450 module_param_call(nlm_timeout, param_set_timeout, param_get_ulong, 451 &nlm_timeout, 0644); 452 module_param_call(nlm_udpport, param_set_port, param_get_int, 453 &nlm_udpport, 0644); 454 module_param_call(nlm_tcpport, param_set_port, param_get_int, 455 &nlm_tcpport, 0644); 456 457 /* 458 * Initialising and terminating the module. 459 */ 460 461 static int __init init_nlm(void) 462 { 463 nlm_sysctl_table = register_sysctl_table(nlm_sysctl_root, 0); 464 return nlm_sysctl_table ? 0 : -ENOMEM; 465 } 466 467 static void __exit exit_nlm(void) 468 { 469 /* FIXME: delete all NLM clients */ 470 nlm_shutdown_hosts(); 471 unregister_sysctl_table(nlm_sysctl_table); 472 } 473 474 module_init(init_nlm); 475 module_exit(exit_nlm); 476 477 /* 478 * Define NLM program and procedures 479 */ 480 static struct svc_version nlmsvc_version1 = { 481 .vs_vers = 1, 482 .vs_nproc = 17, 483 .vs_proc = nlmsvc_procedures, 484 .vs_xdrsize = NLMSVC_XDRSIZE, 485 }; 486 static struct svc_version nlmsvc_version3 = { 487 .vs_vers = 3, 488 .vs_nproc = 24, 489 .vs_proc = nlmsvc_procedures, 490 .vs_xdrsize = NLMSVC_XDRSIZE, 491 }; 492 #ifdef CONFIG_LOCKD_V4 493 static struct svc_version nlmsvc_version4 = { 494 .vs_vers = 4, 495 .vs_nproc = 24, 496 .vs_proc = nlmsvc_procedures4, 497 .vs_xdrsize = NLMSVC_XDRSIZE, 498 }; 499 #endif 500 static struct svc_version * nlmsvc_version[] = { 501 [1] = &nlmsvc_version1, 502 [3] = &nlmsvc_version3, 503 #ifdef CONFIG_LOCKD_V4 504 [4] = &nlmsvc_version4, 505 #endif 506 }; 507 508 static struct svc_stat nlmsvc_stats; 509 510 #define NLM_NRVERS (sizeof(nlmsvc_version)/sizeof(nlmsvc_version[0])) 511 static struct svc_program nlmsvc_program = { 512 .pg_prog = NLM_PROGRAM, /* program number */ 513 .pg_nvers = NLM_NRVERS, /* number of entries in nlmsvc_version */ 514 .pg_vers = nlmsvc_version, /* version table */ 515 .pg_name = "lockd", /* service name */ 516 .pg_class = "nfsd", /* share authentication with nfsd */ 517 .pg_stats = &nlmsvc_stats, /* stats table */ 518 .pg_authenticate = &lockd_authenticate /* export authentication */ 519 }; 520