1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy is of the CDDL is also available via the Internet 9 * at http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 14 * Copyright (c) 2012 by Delphix. All rights reserved. 15 */ 16 17 /* 18 * NFS Lock Manager, server-side and common. 19 * 20 * This file contains all the external entry points of klmmod. 21 * Basically, this is the "glue" to the BSD nlm code. 22 */ 23 24 #include <sys/types.h> 25 #include <sys/errno.h> 26 #include <sys/modctl.h> 27 #include <sys/flock.h> 28 29 #include <nfs/nfs.h> 30 #include <nfs/nfssys.h> 31 #include <nfs/lm.h> 32 #include <rpcsvc/nlm_prot.h> 33 #include "nlm_impl.h" 34 35 static struct modlmisc modlmisc = { 36 &mod_miscops, "lock mgr common module" 37 }; 38 39 static struct modlinkage modlinkage = { 40 MODREV_1, &modlmisc, NULL 41 }; 42 43 /* 44 * Cluster node ID. Zero unless we're part of a cluster. 45 * Set by lm_set_nlmid_flk. Pass to lm_set_nlm_status. 46 * We're not yet doing "clustered" NLM stuff. 47 */ 48 int lm_global_nlmid = 0; 49 50 /* 51 * Call-back hook for clusters: Set lock manager status. 52 * If this hook is set, call this instead of the ususal 53 * flk_set_lockmgr_status(FLK_LOCKMGR_UP / DOWN); 54 */ 55 void (*lm_set_nlm_status)(int nlm_id, flk_nlm_status_t) = NULL; 56 57 /* 58 * Call-back hook for clusters: Delete all locks held by sysid. 59 * Call from code that drops all client locks (for which we're 60 * the server) i.e. after the SM tells us a client has crashed. 61 */ 62 void (*lm_remove_file_locks)(int) = NULL; 63 64 krwlock_t lm_lck; 65 zone_key_t nlm_zone_key; 66 67 /* 68 * Init/fini per-zone stuff for klm 69 */ 70 /* ARGSUSED */ 71 void * 72 lm_zone_init(zoneid_t zoneid) 73 { 74 struct nlm_globals *g; 75 76 g = kmem_zalloc(sizeof (*g), KM_SLEEP); 77 78 avl_create(&g->nlm_hosts_tree, nlm_host_cmp, 79 sizeof (struct nlm_host), 80 offsetof(struct nlm_host, nh_by_addr)); 81 82 g->nlm_hosts_hash = mod_hash_create_idhash("nlm_host_by_sysid", 83 64, mod_hash_null_valdtor); 84 85 TAILQ_INIT(&g->nlm_idle_hosts); 86 TAILQ_INIT(&g->nlm_slocks); 87 88 mutex_init(&g->lock, NULL, MUTEX_DEFAULT, NULL); 89 cv_init(&g->nlm_gc_sched_cv, NULL, CV_DEFAULT, NULL); 90 cv_init(&g->nlm_gc_finish_cv, NULL, CV_DEFAULT, NULL); 91 mutex_init(&g->clean_lock, NULL, MUTEX_DEFAULT, NULL); 92 93 g->lockd_pid = 0; 94 g->run_status = NLM_ST_DOWN; 95 96 nlm_globals_register(g); 97 return (g); 98 } 99 100 /* ARGSUSED */ 101 void 102 lm_zone_fini(zoneid_t zoneid, void *data) 103 { 104 struct nlm_globals *g = data; 105 106 ASSERT(avl_is_empty(&g->nlm_hosts_tree)); 107 avl_destroy(&g->nlm_hosts_tree); 108 mod_hash_destroy_idhash(g->nlm_hosts_hash); 109 110 ASSERT(g->nlm_gc_thread == NULL); 111 mutex_destroy(&g->lock); 112 cv_destroy(&g->nlm_gc_sched_cv); 113 cv_destroy(&g->nlm_gc_finish_cv); 114 mutex_destroy(&g->clean_lock); 115 116 nlm_globals_unregister(g); 117 kmem_free(g, sizeof (*g)); 118 } 119 120 121 122 /* 123 * **************************************************************** 124 * module init, fini, info 125 */ 126 int 127 _init() 128 { 129 int retval; 130 131 rw_init(&lm_lck, NULL, RW_DEFAULT, NULL); 132 nlm_init(); 133 134 zone_key_create(&nlm_zone_key, lm_zone_init, NULL, lm_zone_fini); 135 /* Per-zone lockmgr data. See: os/flock.c */ 136 zone_key_create(&flock_zone_key, flk_zone_init, NULL, flk_zone_fini); 137 138 retval = mod_install(&modlinkage); 139 if (retval == 0) 140 return (0); 141 142 /* 143 * mod_install failed! undo above, reverse order 144 */ 145 146 (void) zone_key_delete(flock_zone_key); 147 flock_zone_key = ZONE_KEY_UNINITIALIZED; 148 (void) zone_key_delete(nlm_zone_key); 149 rw_destroy(&lm_lck); 150 151 return (retval); 152 } 153 154 int 155 _fini() 156 { 157 /* Don't unload. */ 158 return (EBUSY); 159 } 160 161 int 162 _info(struct modinfo *modinfop) 163 { 164 return (mod_info(&modlinkage, modinfop)); 165 } 166 167 168 169 /* 170 * **************************************************************** 171 * Stubs listed in modstubs.s 172 */ 173 174 /* 175 * klm system calls. Start service on some endpoint. 176 * Called by nfssys() LM_SVC, from lockd. 177 */ 178 int 179 lm_svc(struct lm_svc_args *args) 180 { 181 struct knetconfig knc; 182 const char *netid; 183 struct nlm_globals *g; 184 struct file *fp = NULL; 185 int err = 0; 186 187 /* Get our "globals" */ 188 g = zone_getspecific(nlm_zone_key, curzone); 189 190 /* 191 * Check version of lockd calling. 192 */ 193 if (args->version != LM_SVC_CUR_VERS) { 194 NLM_ERR("lm_svc: Version mismatch " 195 "(given 0x%x, expected 0x%x)\n", 196 args->version, LM_SVC_CUR_VERS); 197 return (EINVAL); 198 } 199 200 /* 201 * Build knetconfig, checking arg values. 202 * Also come up with the "netid" string. 203 * (With some knowledge of /etc/netconfig) 204 */ 205 bzero(&knc, sizeof (knc)); 206 switch (args->n_proto) { 207 case LM_TCP: 208 knc.knc_semantics = NC_TPI_COTS_ORD; 209 knc.knc_proto = NC_TCP; 210 break; 211 case LM_UDP: 212 knc.knc_semantics = NC_TPI_CLTS; 213 knc.knc_proto = NC_UDP; 214 break; 215 default: 216 NLM_ERR("nlm_build_knetconfig: Unknown " 217 "lm_proto=0x%x\n", args->n_proto); 218 return (EINVAL); 219 } 220 221 switch (args->n_fmly) { 222 case LM_INET: 223 knc.knc_protofmly = NC_INET; 224 break; 225 case LM_INET6: 226 knc.knc_protofmly = NC_INET6; 227 break; 228 case LM_LOOPBACK: 229 knc.knc_protofmly = NC_LOOPBACK; 230 /* Override what we set above. */ 231 knc.knc_proto = NC_NOPROTO; 232 break; 233 default: 234 NLM_ERR("nlm_build_knetconfig: Unknown " 235 "lm_fmly=0x%x\n", args->n_fmly); 236 return (EINVAL); 237 } 238 239 knc.knc_rdev = args->n_rdev; 240 netid = nlm_knc_to_netid(&knc); 241 if (!netid) 242 return (EINVAL); 243 244 /* 245 * Setup service on the passed transport. 246 * NB: must releasef(fp) after this. 247 */ 248 if ((fp = getf(args->fd)) == NULL) 249 return (EBADF); 250 251 mutex_enter(&g->lock); 252 /* 253 * Don't try to start while still shutting down, 254 * or lots of things will fail... 255 */ 256 if (g->run_status == NLM_ST_STOPPING) { 257 err = EAGAIN; 258 goto out; 259 } 260 261 /* 262 * There is no separate "initialize" sub-call for nfssys, 263 * and we want to do some one-time work when the first 264 * binding comes in from lockd. 265 */ 266 if (g->run_status == NLM_ST_DOWN) { 267 g->run_status = NLM_ST_STARTING; 268 g->lockd_pid = curproc->p_pid; 269 270 /* Save the options. */ 271 g->cn_idle_tmo = args->timout; 272 g->grace_period = args->grace; 273 g->retrans_tmo = args->retransmittimeout; 274 275 /* See nfs_sys.c (not yet per-zone) */ 276 if (INGLOBALZONE(curproc)) { 277 rfs4_grace_period = args->grace; 278 rfs4_lease_time = args->grace; 279 } 280 281 mutex_exit(&g->lock); 282 err = nlm_svc_starting(g, fp, netid, &knc); 283 mutex_enter(&g->lock); 284 } else { 285 /* 286 * If KLM is not started and the very first endpoint lockd 287 * tries to add is not a loopback device, report an error. 288 */ 289 if (g->run_status != NLM_ST_UP) { 290 err = ENOTACTIVE; 291 goto out; 292 } 293 if (g->lockd_pid != curproc->p_pid) { 294 /* Check if caller has the same PID lockd does */ 295 err = EPERM; 296 goto out; 297 } 298 299 err = nlm_svc_add_ep(fp, netid, &knc); 300 } 301 302 out: 303 mutex_exit(&g->lock); 304 if (fp != NULL) 305 releasef(args->fd); 306 307 return (err); 308 } 309 310 /* 311 * klm system calls. Kill the lock manager. 312 * Called by nfssys() KILL_LOCKMGR, 313 * liblm:lm_shutdown() <- unused? 314 */ 315 int 316 lm_shutdown(void) 317 { 318 struct nlm_globals *g; 319 proc_t *p; 320 pid_t pid; 321 322 /* Get our "globals" */ 323 g = zone_getspecific(nlm_zone_key, curzone); 324 325 mutex_enter(&g->lock); 326 if (g->run_status != NLM_ST_UP) { 327 mutex_exit(&g->lock); 328 return (EBUSY); 329 } 330 331 g->run_status = NLM_ST_STOPPING; 332 pid = g->lockd_pid; 333 mutex_exit(&g->lock); 334 nlm_svc_stopping(g); 335 336 mutex_enter(&pidlock); 337 p = prfind(pid); 338 if (p != NULL) 339 psignal(p, SIGTERM); 340 341 mutex_exit(&pidlock); 342 return (0); 343 } 344 345 /* 346 * Cleanup remote locks on FS un-export. 347 * 348 * NOTE: called from nfs_export.c:unexport() 349 * right before the share is going to 350 * be unexported. 351 */ 352 void 353 lm_unexport(struct exportinfo *exi) 354 { 355 nlm_unexport(exi); 356 } 357 358 /* 359 * CPR suspend/resume hooks. 360 * See:cpr_suspend, cpr_resume 361 * 362 * Before suspend, get current state from "statd" on 363 * all remote systems for which we have locks. 364 * 365 * After resume, check with those systems again, 366 * and either reclaim locks, or do SIGLOST. 367 */ 368 void 369 lm_cprsuspend(void) 370 { 371 nlm_cprsuspend(); 372 } 373 374 void 375 lm_cprresume(void) 376 { 377 nlm_cprresume(); 378 } 379 380 /* 381 * Add the nlm_id bits to the sysid (by ref). 382 */ 383 void 384 lm_set_nlmid_flk(int *new_sysid) 385 { 386 if (lm_global_nlmid != 0) 387 *new_sysid |= (lm_global_nlmid << BITS_IN_SYSID); 388 } 389 390 /* 391 * It seems that closed source klmmod used 392 * this function to release knetconfig stored 393 * in mntinfo structure (see mntinfo's mi_klmconfig 394 * field). 395 * We store knetconfigs differently, thus we don't 396 * need this function. 397 */ 398 void 399 lm_free_config(struct knetconfig *knc) 400 { 401 _NOTE(ARGUNUSED(knc)); 402 } 403 404 /* 405 * Called by NFS4 delegation code to check if there are any 406 * NFSv2/v3 locks for the file, so it should not delegate. 407 * 408 * NOTE: called from NFSv4 code 409 * (see nfs4_srv_deleg.c:rfs4_bgrant_delegation()) 410 */ 411 int 412 lm_vp_active(const vnode_t *vp) 413 { 414 return (nlm_vp_active(vp)); 415 } 416 417 /* 418 * Find or create a "sysid" for given knc+addr. 419 * name is optional. Sets nc_changed if the 420 * found knc_proto is different from passed. 421 * Increments the reference count. 422 * 423 * Called internally, and in nfs4_find_sysid() 424 */ 425 struct lm_sysid * 426 lm_get_sysid(struct knetconfig *knc, struct netbuf *addr, 427 char *name, bool_t *nc_changed) 428 { 429 struct nlm_globals *g; 430 const char *netid; 431 struct nlm_host *hostp; 432 433 _NOTE(ARGUNUSED(nc_changed)); 434 netid = nlm_knc_to_netid(knc); 435 if (netid == NULL) 436 return (NULL); 437 438 g = zone_getspecific(nlm_zone_key, curzone); 439 440 hostp = nlm_host_findcreate(g, name, netid, addr); 441 if (hostp == NULL) 442 return (NULL); 443 444 return ((struct lm_sysid *)hostp); 445 } 446 447 /* 448 * Release a reference on a "sysid". 449 */ 450 void 451 lm_rel_sysid(struct lm_sysid *sysid) 452 { 453 struct nlm_globals *g; 454 455 g = zone_getspecific(nlm_zone_key, curzone); 456 nlm_host_release(g, (struct nlm_host *)sysid); 457 } 458 459 /* 460 * Alloc/free a sysid_t (a unique number between 461 * LM_SYSID and LM_SYSID_MAX). 462 * 463 * Used by NFSv4 rfs4_op_lockt and smbsrv/smb_fsop_frlock, 464 * both to represent non-local locks outside of klm. 465 * 466 * NOTE: called from NFSv4 and SMBFS to allocate unique 467 * sysid. 468 */ 469 sysid_t 470 lm_alloc_sysidt(void) 471 { 472 return (nlm_sysid_alloc()); 473 } 474 475 void 476 lm_free_sysidt(sysid_t sysid) 477 { 478 nlm_sysid_free(sysid); 479 } 480 481 /* Access private member lms->sysid */ 482 sysid_t 483 lm_sysidt(struct lm_sysid *lms) 484 { 485 return (((struct nlm_host *)lms)->nh_sysid); 486 } 487 488 /* 489 * Called by nfs_frlock to check lock constraints. 490 * Return non-zero if the lock request is "safe", i.e. 491 * the range is not mapped, not MANDLOCK, etc. 492 * 493 * NOTE: callde from NFSv3/NFSv2 frlock() functions to 494 * determine whether it's safe to add new lock. 495 */ 496 int 497 lm_safelock(vnode_t *vp, const struct flock64 *fl, cred_t *cr) 498 { 499 return (nlm_safelock(vp, fl, cr)); 500 } 501 502 /* 503 * Called by nfs_lockcompletion to check whether it's "safe" 504 * to map the file (and cache it's data). Walks the list of 505 * file locks looking for any that are not "whole file". 506 * 507 * NOTE: called from nfs_client.c:nfs_lockcompletion() 508 */ 509 int 510 lm_safemap(const vnode_t *vp) 511 { 512 return (nlm_safemap(vp)); 513 } 514 515 /* 516 * Called by nfs_map() for the MANDLOCK case. 517 * Return non-zero if the file has any locks with a 518 * blocked request (sleep). 519 * 520 * NOTE: called from NFSv3/NFSv2 map() functions in 521 * order to determine whether it's safe to add new 522 * mapping. 523 */ 524 int 525 lm_has_sleep(const vnode_t *vp) 526 { 527 return (nlm_has_sleep(vp)); 528 } 529 530 /* 531 * **************************************************************** 532 * Stuff needed by klmops? 533 */