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