1 /* 2 * Copyright (c) 2008 Isilon Inc http://www.isilon.com/ 3 * Authors: Doug Rabson <dfr@rabson.org> 4 * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 /* 29 * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 30 * Copyright (c) 2012 by Delphix. All rights reserved. 31 */ 32 33 /* 34 * NFS Lock Manager service functions (nlm_do_...) 35 * Called from nlm_rpc_svc.c wrappers. 36 * 37 * Source code derived from FreeBSD nlm_prot_impl.c 38 */ 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/thread.h> 43 #include <sys/fcntl.h> 44 #include <sys/flock.h> 45 #include <sys/mount.h> 46 #include <sys/priv.h> 47 #include <sys/proc.h> 48 #include <sys/share.h> 49 #include <sys/socket.h> 50 #include <sys/syscall.h> 51 #include <sys/syslog.h> 52 #include <sys/systm.h> 53 #include <sys/taskq.h> 54 #include <sys/unistd.h> 55 #include <sys/vnode.h> 56 #include <sys/vfs.h> 57 #include <sys/queue.h> 58 #include <sys/sdt.h> 59 #include <netinet/in.h> 60 61 #include <rpc/rpc.h> 62 #include <rpc/xdr.h> 63 #include <rpc/pmap_prot.h> 64 #include <rpc/pmap_clnt.h> 65 #include <rpc/rpcb_prot.h> 66 67 #include <rpcsvc/nlm_prot.h> 68 #include <rpcsvc/sm_inter.h> 69 70 #include <nfs/nfs.h> 71 #include <nfs/nfs_clnt.h> 72 #include <nfs/export.h> 73 #include <nfs/rnode.h> 74 75 #include "nlm_impl.h" 76 77 #define NLM_IN_GRACE(g) (ddi_get_lbolt() < (g)->grace_threshold) 78 79 struct nlm_block_cb_data { 80 struct nlm_host *hostp; 81 struct nlm_vhold *nvp; 82 struct flock64 *flp; 83 }; 84 85 /* 86 * Invoke an asyncronous RPC callbeck 87 * (used when NLM server needs to reply to MSG NLM procedure). 88 */ 89 #define NLM_INVOKE_CALLBACK(descr, rpcp, resp, callb) \ 90 do { \ 91 enum clnt_stat _stat; \ 92 \ 93 _stat = (*(callb))(resp, NULL, (rpcp)->nr_handle); \ 94 if (_stat != RPC_SUCCESS && _stat != RPC_TIMEDOUT) { \ 95 struct rpc_err _err; \ 96 \ 97 CLNT_GETERR((rpcp)->nr_handle, &_err); \ 98 NLM_ERR("NLM: %s callback failed: " \ 99 "stat %d, err %d\n", descr, _stat, \ 100 _err.re_errno); \ 101 } \ 102 \ 103 _NOTE(CONSTCOND) } while (0) 104 105 static void nlm_block( 106 nlm4_lockargs *lockargs, 107 struct nlm_host *host, 108 struct nlm_vhold *nvp, 109 nlm_rpc_t *rpcp, 110 struct flock64 *fl, 111 nlm_testargs_cb grant_cb); 112 113 static vnode_t *nlm_fh_to_vp(struct netobj *); 114 static struct nlm_vhold *nlm_fh_to_vhold(struct nlm_host *, struct netobj *); 115 static void nlm_init_shrlock(struct shrlock *, nlm4_share *, struct nlm_host *); 116 static callb_cpr_t *nlm_block_callback(flk_cb_when_t, void *); 117 static int nlm_vop_frlock(vnode_t *, int, flock64_t *, int, offset_t, 118 struct flk_callback *, cred_t *, caller_context_t *); 119 120 /* 121 * Convert a lock from network to local form, and 122 * check for valid range (no overflow). 123 */ 124 static int 125 nlm_init_flock(struct flock64 *fl, struct nlm4_lock *nl, 126 struct nlm_host *host, rpcvers_t vers, short type) 127 { 128 uint64_t off, len; 129 130 bzero(fl, sizeof (*fl)); 131 off = nl->l_offset; 132 len = nl->l_len; 133 134 if (vers < NLM4_VERS) { 135 /* 136 * Make sure range is valid for 32-bit client. 137 * Also allow len == ~0 to mean lock to EOF, 138 * which is supposed to be l_len == 0. 139 */ 140 if (len == MAX_UOFF32) 141 len = 0; 142 if (off > MAX_UOFF32 || len > MAX_UOFF32) 143 return (EINVAL); 144 if (off + len > MAX_UOFF32 + 1) 145 return (EINVAL); 146 } else { 147 /* 148 * Check range for 64-bit client (no overflow). 149 * Again allow len == ~0 to mean lock to EOF. 150 */ 151 if (len == MAX_U_OFFSET_T) 152 len = 0; 153 if (len != 0 && off + (len - 1) < off) 154 return (EINVAL); 155 } 156 157 fl->l_type = type; 158 fl->l_whence = SEEK_SET; 159 fl->l_start = off; 160 fl->l_len = len; 161 fl->l_sysid = host->nh_sysid; 162 fl->l_pid = nl->svid; 163 /* l_pad */ 164 165 return (0); 166 } 167 168 /* 169 * Gets vnode from client's filehandle 170 * NOTE: Holds vnode, it _must_ be explicitly 171 * released by VN_RELE(). 172 */ 173 static vnode_t * 174 nlm_fh_to_vp(struct netobj *fh) 175 { 176 fhandle_t *fhp; 177 178 /* 179 * Get a vnode pointer for the given NFS file handle. 180 * Note that it could be an NFSv2 for NFSv3 handle, 181 * which means the size might vary. (don't copy) 182 */ 183 if (fh->n_len < sizeof (*fhp)) 184 return (NULL); 185 186 /* We know this is aligned (kmem_alloc) */ 187 /* LINTED E_BAD_PTR_CAST_ALIGN */ 188 fhp = (fhandle_t *)fh->n_bytes; 189 return (lm_fhtovp(fhp)); 190 } 191 192 /* 193 * Get vhold from client's filehandle, but in contrast to 194 * The function tries to check some access rights as well. 195 * 196 * NOTE: vhold object _must_ be explicitly released by 197 * nlm_vhold_release(). 198 */ 199 static struct nlm_vhold * 200 nlm_fh_to_vhold(struct nlm_host *hostp, struct netobj *fh) 201 { 202 vnode_t *vp; 203 struct nlm_vhold *nvp; 204 205 vp = nlm_fh_to_vp(fh); 206 if (vp == NULL) 207 return (NULL); 208 209 210 nvp = nlm_vhold_get(hostp, vp); 211 212 /* 213 * Both nlm_fh_to_vp() and nlm_vhold_get() 214 * do VN_HOLD(), so we need to drop one 215 * reference on vnode. 216 */ 217 VN_RELE(vp); 218 return (nvp); 219 } 220 221 /* ******************************************************************* */ 222 223 /* 224 * NLM implementation details, called from the RPC svc code. 225 */ 226 227 /* 228 * Call-back from NFS statd, used to notify that one of our 229 * hosts had a status change. The host can be either an 230 * NFS client, NFS server or both. 231 * According to NSM protocol description, the state is a 232 * number that is increases monotonically each time the 233 * state of host changes. An even number indicates that 234 * the host is down, while an odd number indicates that 235 * the host is up. 236 * 237 * Here we ignore this even/odd difference of status number 238 * reported by the NSM, we launch notification handlers 239 * every time the state is changed. The reason we why do so 240 * is that client and server can talk to each other using 241 * connectionless transport and it's easy to lose packet 242 * containing NSM notification with status number update. 243 * 244 * In nlm_host_monitor(), we put the sysid in the private data 245 * that statd carries in this callback, so we can easliy find 246 * the host this call applies to. 247 */ 248 /* ARGSUSED */ 249 void 250 nlm_do_notify1(nlm_sm_status *argp, void *res, struct svc_req *sr) 251 { 252 struct nlm_globals *g; 253 struct nlm_host *host; 254 uint16_t sysid; 255 256 g = zone_getspecific(nlm_zone_key, curzone); 257 bcopy(&argp->priv, &sysid, sizeof (sysid)); 258 259 DTRACE_PROBE2(nsm__notify, uint16_t, sysid, 260 int, argp->state); 261 262 host = nlm_host_find_by_sysid(g, (sysid_t)sysid); 263 if (host == NULL) 264 return; 265 266 nlm_host_notify_server(host, argp->state); 267 nlm_host_notify_client(host, argp->state); 268 nlm_host_release(g, host); 269 } 270 271 /* 272 * Another available call-back for NFS statd. 273 * Not currently used. 274 */ 275 /* ARGSUSED */ 276 void 277 nlm_do_notify2(nlm_sm_status *argp, void *res, struct svc_req *sr) 278 { 279 ASSERT(0); 280 } 281 282 283 /* 284 * NLM_TEST, NLM_TEST_MSG, 285 * NLM4_TEST, NLM4_TEST_MSG, 286 * Client inquiry about locks, non-blocking. 287 */ 288 void 289 nlm_do_test(nlm4_testargs *argp, nlm4_testres *resp, 290 struct svc_req *sr, nlm_testres_cb cb) 291 { 292 struct nlm_globals *g; 293 struct nlm_host *host; 294 struct nlm4_holder *lh; 295 struct nlm_owner_handle *oh; 296 nlm_rpc_t *rpcp = NULL; 297 vnode_t *vp = NULL; 298 struct netbuf *addr; 299 char *netid; 300 char *name; 301 int error; 302 struct flock64 fl; 303 304 nlm_copy_netobj(&resp->cookie, &argp->cookie); 305 306 name = argp->alock.caller_name; 307 netid = svc_getnetid(sr->rq_xprt); 308 addr = svc_getrpccaller(sr->rq_xprt); 309 310 g = zone_getspecific(nlm_zone_key, curzone); 311 host = nlm_host_findcreate(g, name, netid, addr); 312 if (host == NULL) { 313 resp->stat.stat = nlm4_denied_nolocks; 314 return; 315 } 316 if (cb != NULL) { 317 error = nlm_host_get_rpc(host, sr->rq_vers, &rpcp); 318 if (error != 0) { 319 resp->stat.stat = nlm4_denied_nolocks; 320 goto out; 321 } 322 } 323 324 vp = nlm_fh_to_vp(&argp->alock.fh); 325 if (vp == NULL) { 326 resp->stat.stat = nlm4_stale_fh; 327 goto out; 328 } 329 330 if (NLM_IN_GRACE(g)) { 331 resp->stat.stat = nlm4_denied_grace_period; 332 goto out; 333 } 334 335 /* Convert to local form. */ 336 error = nlm_init_flock(&fl, &argp->alock, host, sr->rq_vers, 337 (argp->exclusive) ? F_WRLCK : F_RDLCK); 338 if (error) { 339 resp->stat.stat = nlm4_failed; 340 goto out; 341 } 342 343 /* BSD: VOP_ADVLOCK(nv->nv_vp, NULL, F_GETLK, &fl, F_REMOTE); */ 344 error = nlm_vop_frlock(vp, F_GETLK, &fl, 345 F_REMOTELOCK | FREAD | FWRITE, 346 (u_offset_t)0, NULL, CRED(), NULL); 347 if (error) { 348 resp->stat.stat = nlm4_failed; 349 goto out; 350 } 351 352 if (fl.l_type == F_UNLCK) { 353 resp->stat.stat = nlm4_granted; 354 goto out; 355 } 356 resp->stat.stat = nlm4_denied; 357 358 /* 359 * This lock "test" fails due to a conflicting lock. 360 * 361 * If this is a v1 client, make sure the conflicting 362 * lock range we report can be expressed with 32-bit 363 * offsets. The lock range requested was expressed 364 * as 32-bit offset and length, so at least part of 365 * the conflicting lock should lie below MAX_UOFF32. 366 * If the conflicting lock extends past that, we'll 367 * trim the range to end at MAX_UOFF32 so this lock 368 * can be represented in a 32-bit response. Check 369 * the start also (paranoid, but a low cost check). 370 */ 371 if (sr->rq_vers < NLM4_VERS) { 372 uint64 maxlen; 373 if (fl.l_start > MAX_UOFF32) 374 fl.l_start = MAX_UOFF32; 375 maxlen = MAX_UOFF32 + 1 - fl.l_start; 376 if (fl.l_len > maxlen) 377 fl.l_len = maxlen; 378 } 379 380 /* 381 * Build the nlm4_holder result structure. 382 * 383 * Note that lh->oh is freed via xdr_free, 384 * xdr_nlm4_holder, xdr_netobj, xdr_bytes. 385 */ 386 oh = kmem_zalloc(sizeof (*oh), KM_SLEEP); 387 oh->oh_sysid = (sysid_t)fl.l_sysid; 388 lh = &resp->stat.nlm4_testrply_u.holder; 389 lh->exclusive = (fl.l_type == F_WRLCK); 390 lh->svid = fl.l_pid; 391 lh->oh.n_len = sizeof (*oh); 392 lh->oh.n_bytes = (void *)oh; 393 lh->l_offset = fl.l_start; 394 lh->l_len = fl.l_len; 395 396 out: 397 /* 398 * If we have a callback funtion, use that to 399 * deliver the response via another RPC call. 400 */ 401 if (cb != NULL && rpcp != NULL) 402 NLM_INVOKE_CALLBACK("test", rpcp, resp, cb); 403 404 if (vp != NULL) 405 VN_RELE(vp); 406 if (rpcp != NULL) 407 nlm_host_rele_rpc(host, rpcp); 408 409 nlm_host_release(g, host); 410 } 411 412 /* 413 * NLM_LOCK, NLM_LOCK_MSG, NLM_NM_LOCK 414 * NLM4_LOCK, NLM4_LOCK_MSG, NLM4_NM_LOCK 415 * 416 * Client request to set a lock, possibly blocking. 417 * 418 * If the lock needs to block, we return status blocked to 419 * this RPC call, and then later call back the client with 420 * a "granted" callback. Tricky aspects of this include: 421 * sending a reply before this function returns, and then 422 * borrowing this thread from the RPC service pool for the 423 * wait on the lock and doing the later granted callback. 424 * 425 * We also have to keep a list of locks (pending + granted) 426 * both to handle retransmitted requests, and to keep the 427 * vnodes for those locks active. 428 */ 429 void 430 nlm_do_lock(nlm4_lockargs *argp, nlm4_res *resp, struct svc_req *sr, 431 nlm_reply_cb reply_cb, nlm_res_cb res_cb, nlm_testargs_cb grant_cb) 432 { 433 struct nlm_globals *g; 434 struct flock64 fl; 435 struct nlm_host *host = NULL; 436 struct netbuf *addr; 437 struct nlm_vhold *nvp = NULL; 438 nlm_rpc_t *rpcp = NULL; 439 char *netid; 440 char *name; 441 int error, flags; 442 bool_t do_blocking = FALSE; 443 bool_t do_mon_req = FALSE; 444 enum nlm4_stats status; 445 446 nlm_copy_netobj(&resp->cookie, &argp->cookie); 447 448 name = argp->alock.caller_name; 449 netid = svc_getnetid(sr->rq_xprt); 450 addr = svc_getrpccaller(sr->rq_xprt); 451 452 g = zone_getspecific(nlm_zone_key, curzone); 453 host = nlm_host_findcreate(g, name, netid, addr); 454 if (host == NULL) { 455 DTRACE_PROBE4(no__host, struct nlm_globals *, g, 456 char *, name, char *, netid, struct netbuf *, addr); 457 status = nlm4_denied_nolocks; 458 goto doreply; 459 } 460 461 DTRACE_PROBE3(start, struct nlm_globals *, g, 462 struct nlm_host *, host, nlm4_lockargs *, argp); 463 464 /* 465 * If we may need to do _msg_ call needing an RPC 466 * callback, get the RPC client handle now, 467 * so we know if we can bind to the NLM service on 468 * this client. 469 * 470 * Note: host object carries transport type. 471 * One client using multiple transports gets 472 * separate sysids for each of its transports. 473 */ 474 if (res_cb != NULL || (grant_cb != NULL && argp->block == TRUE)) { 475 error = nlm_host_get_rpc(host, sr->rq_vers, &rpcp); 476 if (error != 0) { 477 status = nlm4_denied_nolocks; 478 goto doreply; 479 } 480 } 481 482 /* 483 * During the "grace period", only allow reclaim. 484 */ 485 if (argp->reclaim == 0 && NLM_IN_GRACE(g)) { 486 status = nlm4_denied_grace_period; 487 goto doreply; 488 } 489 490 /* 491 * Check whether we missed host shutdown event 492 */ 493 if (nlm_host_get_state(host) != argp->state) 494 nlm_host_notify_server(host, argp->state); 495 496 /* 497 * Get a hold on the vnode for a lock operation. 498 * Only lock() and share() need vhold objects. 499 */ 500 nvp = nlm_fh_to_vhold(host, &argp->alock.fh); 501 if (nvp == NULL) { 502 status = nlm4_stale_fh; 503 goto doreply; 504 } 505 506 /* Convert to local form. */ 507 error = nlm_init_flock(&fl, &argp->alock, host, sr->rq_vers, 508 (argp->exclusive) ? F_WRLCK : F_RDLCK); 509 if (error) { 510 status = nlm4_failed; 511 goto doreply; 512 } 513 514 /* 515 * Try to lock non-blocking first. If we succeed 516 * getting the lock, we can reply with the granted 517 * status directly and avoid the complications of 518 * making the "granted" RPC callback later. 519 * 520 * This also let's us find out now about some 521 * possible errors like EROFS, etc. 522 */ 523 flags = F_REMOTELOCK | FREAD | FWRITE; 524 error = nlm_vop_frlock(nvp->nv_vp, F_SETLK, &fl, flags, 525 (u_offset_t)0, NULL, CRED(), NULL); 526 527 DTRACE_PROBE3(setlk__res, struct flock64 *, &fl, 528 int, flags, int, error); 529 530 switch (error) { 531 case 0: 532 /* Got it without waiting! */ 533 status = nlm4_granted; 534 do_mon_req = TRUE; 535 break; 536 537 /* EINPROGRESS too? */ 538 case EAGAIN: 539 /* We did not get the lock. Should we block? */ 540 if (argp->block == FALSE || grant_cb == NULL) { 541 status = nlm4_denied; 542 break; 543 } 544 /* 545 * Should block. Try to reserve this thread 546 * so we can use it to wait for the lock and 547 * later send the granted message. If this 548 * reservation fails, say "no resources". 549 */ 550 if (!svc_reserve_thread(sr->rq_xprt)) { 551 status = nlm4_denied_nolocks; 552 break; 553 } 554 /* 555 * OK, can detach this thread, so this call 556 * will block below (after we reply). 557 */ 558 status = nlm4_blocked; 559 do_blocking = TRUE; 560 do_mon_req = TRUE; 561 break; 562 563 case ENOLCK: 564 /* Failed for lack of resources. */ 565 status = nlm4_denied_nolocks; 566 break; 567 568 case EROFS: 569 /* read-only file system */ 570 status = nlm4_rofs; 571 break; 572 573 case EFBIG: 574 /* file too big */ 575 status = nlm4_fbig; 576 break; 577 578 case EDEADLK: 579 /* dead lock condition */ 580 status = nlm4_deadlck; 581 break; 582 583 default: 584 status = nlm4_denied; 585 break; 586 } 587 588 doreply: 589 resp->stat.stat = status; 590 591 /* 592 * We get one of two function pointers; one for a 593 * normal RPC reply, and another for doing an RPC 594 * "callback" _res reply for a _msg function. 595 * Use either of those to send the reply now. 596 * 597 * If sending this reply fails, just leave the 598 * lock in the list for retransmitted requests. 599 * Cleanup is via unlock or host rele (statmon). 600 */ 601 if (reply_cb != NULL) { 602 /* i.e. nlm_lock_1_reply */ 603 if (!(*reply_cb)(sr->rq_xprt, resp)) 604 svcerr_systemerr(sr->rq_xprt); 605 } 606 if (res_cb != NULL && rpcp != NULL) 607 NLM_INVOKE_CALLBACK("lock", rpcp, resp, res_cb); 608 609 /* 610 * The reply has been sent to the client. 611 * Start monitoring this client (maybe). 612 * 613 * Note that the non-monitored (NM) calls pass grant_cb=NULL 614 * indicating that the client doesn't support RPC callbacks. 615 * No monitoring for these (lame) clients. 616 */ 617 if (do_mon_req && grant_cb != NULL) 618 nlm_host_monitor(g, host, argp->state); 619 620 if (do_blocking) { 621 /* 622 * We need to block on this lock, and when that 623 * completes, do the granted RPC call. Note that 624 * we "reserved" this thread above, so we can now 625 * "detach" it from the RPC SVC pool, allowing it 626 * to block indefinitely if needed. 627 */ 628 ASSERT(rpcp != NULL); 629 (void) svc_detach_thread(sr->rq_xprt); 630 nlm_block(argp, host, nvp, rpcp, &fl, grant_cb); 631 } 632 633 DTRACE_PROBE3(lock__end, struct nlm_globals *, g, 634 struct nlm_host *, host, nlm4_res *, resp); 635 636 if (rpcp != NULL) 637 nlm_host_rele_rpc(host, rpcp); 638 639 nlm_vhold_release(host, nvp); 640 nlm_host_release(g, host); 641 } 642 643 /* 644 * Helper for nlm_do_lock(), partly for observability, 645 * (we'll see a call blocked in this function) and 646 * because nlm_do_lock() was getting quite long. 647 */ 648 static void 649 nlm_block(nlm4_lockargs *lockargs, 650 struct nlm_host *host, 651 struct nlm_vhold *nvp, 652 nlm_rpc_t *rpcp, 653 struct flock64 *flp, 654 nlm_testargs_cb grant_cb) 655 { 656 nlm4_testargs args; 657 int error; 658 flk_callback_t flk_cb; 659 struct nlm_block_cb_data cb_data; 660 661 /* 662 * Keep a list of blocked locks on nh_pending, and use it 663 * to cancel these threads in nlm_destroy_client_pending. 664 * 665 * Check to see if this lock is already in the list 666 * and if not, add an entry for it. Allocate first, 667 * then if we don't insert, free the new one. 668 * Caller already has vp held. 669 */ 670 671 error = nlm_slreq_register(host, nvp, flp); 672 if (error != 0) { 673 /* 674 * Sleeping lock request with given fl is already 675 * registered by someone else. This means that 676 * some other thread is handling the request, let 677 * him to do its work. 678 */ 679 ASSERT(error == EEXIST); 680 return; 681 } 682 683 cb_data.hostp = host; 684 cb_data.nvp = nvp; 685 cb_data.flp = flp; 686 flk_init_callback(&flk_cb, nlm_block_callback, &cb_data); 687 688 /* BSD: VOP_ADVLOCK(vp, NULL, F_SETLK, fl, F_REMOTE); */ 689 error = nlm_vop_frlock(nvp->nv_vp, F_SETLKW, flp, 690 F_REMOTELOCK | FREAD | FWRITE, 691 (u_offset_t)0, &flk_cb, CRED(), NULL); 692 693 if (error != 0) { 694 /* 695 * We failed getting the lock, but have no way to 696 * tell the client about that. Let 'em time out. 697 */ 698 (void) nlm_slreq_unregister(host, nvp, flp); 699 return; 700 } 701 702 /* 703 * Do the "granted" call-back to the client. 704 */ 705 args.cookie = lockargs->cookie; 706 args.exclusive = lockargs->exclusive; 707 args.alock = lockargs->alock; 708 709 NLM_INVOKE_CALLBACK("grant", rpcp, &args, grant_cb); 710 } 711 712 /* 713 * The function that is used as flk callback when NLM server 714 * sets new sleeping lock. The function unregisters NLM 715 * sleeping lock request (nlm_slreq) associated with the 716 * sleeping lock _before_ lock becomes active. It prevents 717 * potential race condition between nlm_block() and 718 * nlm_do_cancel(). 719 */ 720 static callb_cpr_t * 721 nlm_block_callback(flk_cb_when_t when, void *data) 722 { 723 struct nlm_block_cb_data *cb_data; 724 725 cb_data = (struct nlm_block_cb_data *)data; 726 if (when == FLK_AFTER_SLEEP) { 727 (void) nlm_slreq_unregister(cb_data->hostp, 728 cb_data->nvp, cb_data->flp); 729 } 730 731 return (0); 732 } 733 734 /* 735 * NLM_CANCEL, NLM_CANCEL_MSG, 736 * NLM4_CANCEL, NLM4_CANCEL_MSG, 737 * Client gives up waiting for a blocking lock. 738 */ 739 void 740 nlm_do_cancel(nlm4_cancargs *argp, nlm4_res *resp, 741 struct svc_req *sr, nlm_res_cb cb) 742 { 743 struct nlm_globals *g; 744 struct nlm_host *host; 745 struct netbuf *addr; 746 struct nlm_vhold *nvp = NULL; 747 nlm_rpc_t *rpcp = NULL; 748 char *netid; 749 char *name; 750 int error; 751 struct flock64 fl; 752 753 nlm_copy_netobj(&resp->cookie, &argp->cookie); 754 netid = svc_getnetid(sr->rq_xprt); 755 addr = svc_getrpccaller(sr->rq_xprt); 756 name = argp->alock.caller_name; 757 758 g = zone_getspecific(nlm_zone_key, curzone); 759 host = nlm_host_findcreate(g, name, netid, addr); 760 if (host == NULL) { 761 resp->stat.stat = nlm4_denied_nolocks; 762 return; 763 } 764 if (cb != NULL) { 765 error = nlm_host_get_rpc(host, sr->rq_vers, &rpcp); 766 if (error != 0) { 767 resp->stat.stat = nlm4_denied_nolocks; 768 return; 769 } 770 } 771 772 DTRACE_PROBE3(start, struct nlm_globals *, g, 773 struct nlm_host *, host, nlm4_cancargs *, argp); 774 775 if (NLM_IN_GRACE(g)) { 776 resp->stat.stat = nlm4_denied_grace_period; 777 goto out; 778 } 779 780 nvp = nlm_fh_to_vhold(host, &argp->alock.fh); 781 if (nvp == NULL) { 782 resp->stat.stat = nlm4_stale_fh; 783 goto out; 784 } 785 786 /* Convert to local form. */ 787 error = nlm_init_flock(&fl, &argp->alock, host, sr->rq_vers, 788 (argp->exclusive) ? F_WRLCK : F_RDLCK); 789 if (error) { 790 resp->stat.stat = nlm4_failed; 791 goto out; 792 } 793 794 error = nlm_slreq_unregister(host, nvp, &fl); 795 if (error != 0) { 796 /* 797 * There's no sleeping lock request corresponding 798 * to the lock. Then requested sleeping lock 799 * doesn't exist. 800 */ 801 resp->stat.stat = nlm4_denied; 802 goto out; 803 } 804 805 fl.l_type = F_UNLCK; 806 error = nlm_vop_frlock(nvp->nv_vp, F_SETLK, &fl, 807 F_REMOTELOCK | FREAD | FWRITE, 808 (u_offset_t)0, NULL, CRED(), NULL); 809 810 resp->stat.stat = (error == 0) ? 811 nlm4_granted : nlm4_denied; 812 813 out: 814 /* 815 * If we have a callback funtion, use that to 816 * deliver the response via another RPC call. 817 */ 818 if (cb != NULL && rpcp != NULL) 819 NLM_INVOKE_CALLBACK("cancel", rpcp, resp, cb); 820 821 DTRACE_PROBE3(cancel__end, struct nlm_globals *, g, 822 struct nlm_host *, host, nlm4_res *, resp); 823 824 if (rpcp != NULL) 825 nlm_host_rele_rpc(host, rpcp); 826 827 nlm_vhold_release(host, nvp); 828 nlm_host_release(g, host); 829 } 830 831 /* 832 * NLM_UNLOCK, NLM_UNLOCK_MSG, 833 * NLM4_UNLOCK, NLM4_UNLOCK_MSG, 834 * Client removes one of their locks. 835 */ 836 void 837 nlm_do_unlock(nlm4_unlockargs *argp, nlm4_res *resp, 838 struct svc_req *sr, nlm_res_cb cb) 839 { 840 struct nlm_globals *g; 841 struct nlm_host *host; 842 struct netbuf *addr; 843 nlm_rpc_t *rpcp = NULL; 844 vnode_t *vp = NULL; 845 char *netid; 846 char *name; 847 int error; 848 struct flock64 fl; 849 850 nlm_copy_netobj(&resp->cookie, &argp->cookie); 851 852 netid = svc_getnetid(sr->rq_xprt); 853 addr = svc_getrpccaller(sr->rq_xprt); 854 name = argp->alock.caller_name; 855 856 /* 857 * NLM_UNLOCK operation doesn't have an error code 858 * denoting that operation failed, so we always 859 * return nlm4_granted except when the server is 860 * in a grace period. 861 */ 862 resp->stat.stat = nlm4_granted; 863 864 g = zone_getspecific(nlm_zone_key, curzone); 865 host = nlm_host_findcreate(g, name, netid, addr); 866 if (host == NULL) 867 return; 868 869 if (cb != NULL) { 870 error = nlm_host_get_rpc(host, sr->rq_vers, &rpcp); 871 if (error != 0) 872 goto out; 873 } 874 875 DTRACE_PROBE3(start, struct nlm_globals *, g, 876 struct nlm_host *, host, nlm4_unlockargs *, argp); 877 878 if (NLM_IN_GRACE(g)) { 879 resp->stat.stat = nlm4_denied_grace_period; 880 goto out; 881 } 882 883 vp = nlm_fh_to_vp(&argp->alock.fh); 884 if (vp == NULL) 885 goto out; 886 887 /* Convert to local form. */ 888 error = nlm_init_flock(&fl, &argp->alock, host, sr->rq_vers, F_UNLCK); 889 if (error) 890 goto out; 891 892 /* BSD: VOP_ADVLOCK(nv->nv_vp, NULL, F_UNLCK, &fl, F_REMOTE); */ 893 error = nlm_vop_frlock(vp, F_SETLK, &fl, 894 F_REMOTELOCK | FREAD | FWRITE, 895 (u_offset_t)0, NULL, CRED(), NULL); 896 897 DTRACE_PROBE1(unlock__res, int, error); 898 out: 899 /* 900 * If we have a callback funtion, use that to 901 * deliver the response via another RPC call. 902 */ 903 if (cb != NULL && rpcp != NULL) 904 NLM_INVOKE_CALLBACK("unlock", rpcp, resp, cb); 905 906 DTRACE_PROBE3(unlock__end, struct nlm_globals *, g, 907 struct nlm_host *, host, nlm4_res *, resp); 908 909 if (vp != NULL) 910 VN_RELE(vp); 911 if (rpcp != NULL) 912 nlm_host_rele_rpc(host, rpcp); 913 914 nlm_host_release(g, host); 915 } 916 917 /* 918 * NLM_GRANTED, NLM_GRANTED_MSG, 919 * NLM4_GRANTED, NLM4_GRANTED_MSG, 920 * 921 * This service routine is special. It's the only one that's 922 * really part of our NLM _client_ support, used by _servers_ 923 * to "call back" when a blocking lock from this NLM client 924 * is granted by the server. In this case, we _know_ there is 925 * already an nlm_host allocated and held by the client code. 926 * We want to find that nlm_host here. 927 * 928 * Over in nlm_call_lock(), the client encoded the sysid for this 929 * server in the "owner handle" netbuf sent with our lock request. 930 * We can now use that to find the nlm_host object we used there. 931 * (NB: The owner handle is opaque to the server.) 932 */ 933 void 934 nlm_do_granted(nlm4_testargs *argp, nlm4_res *resp, 935 struct svc_req *sr, nlm_res_cb cb) 936 { 937 struct nlm_globals *g; 938 struct nlm_owner_handle *oh; 939 struct nlm_host *host; 940 nlm_rpc_t *rpcp = NULL; 941 int error; 942 943 nlm_copy_netobj(&resp->cookie, &argp->cookie); 944 resp->stat.stat = nlm4_denied; 945 946 g = zone_getspecific(nlm_zone_key, curzone); 947 oh = (void *) argp->alock.oh.n_bytes; 948 if (oh == NULL) 949 return; 950 951 host = nlm_host_find_by_sysid(g, oh->oh_sysid); 952 if (host == NULL) 953 return; 954 955 if (cb != NULL) { 956 error = nlm_host_get_rpc(host, sr->rq_vers, &rpcp); 957 if (error != 0) 958 goto out; 959 } 960 961 if (NLM_IN_GRACE(g)) { 962 resp->stat.stat = nlm4_denied_grace_period; 963 goto out; 964 } 965 966 error = nlm_slock_grant(g, host, &argp->alock); 967 if (error == 0) 968 resp->stat.stat = nlm4_granted; 969 970 out: 971 /* 972 * If we have a callback funtion, use that to 973 * deliver the response via another RPC call. 974 */ 975 if (cb != NULL && rpcp != NULL) 976 NLM_INVOKE_CALLBACK("do_granted", rpcp, resp, cb); 977 978 if (rpcp != NULL) 979 nlm_host_rele_rpc(host, rpcp); 980 981 nlm_host_release(g, host); 982 } 983 984 /* 985 * NLM_FREE_ALL, NLM4_FREE_ALL 986 * 987 * Destroy all lock state for the calling client. 988 */ 989 void 990 nlm_do_free_all(nlm4_notify *argp, void *res, struct svc_req *sr) 991 { 992 struct nlm_globals *g; 993 struct nlm_host_list host_list; 994 struct nlm_host *hostp; 995 996 TAILQ_INIT(&host_list); 997 g = zone_getspecific(nlm_zone_key, curzone); 998 999 /* Serialize calls to clean locks. */ 1000 mutex_enter(&g->clean_lock); 1001 1002 /* 1003 * Find all hosts that have the given node name and put them on a 1004 * local list. 1005 */ 1006 mutex_enter(&g->lock); 1007 for (hostp = avl_first(&g->nlm_hosts_tree); hostp != NULL; 1008 hostp = AVL_NEXT(&g->nlm_hosts_tree, hostp)) { 1009 if (strcasecmp(hostp->nh_name, argp->name) == 0) { 1010 /* 1011 * If needed take the host out of the idle list since 1012 * we are taking a reference. 1013 */ 1014 if (hostp->nh_flags & NLM_NH_INIDLE) { 1015 TAILQ_REMOVE(&g->nlm_idle_hosts, hostp, nh_link); 1016 hostp->nh_flags &= ~NLM_NH_INIDLE; 1017 } 1018 hostp->nh_refs++; 1019 1020 TAILQ_INSERT_TAIL(&host_list, hostp, nh_link); 1021 } 1022 } 1023 mutex_exit(&g->lock); 1024 1025 /* Free locks for all hosts on the local list. */ 1026 while (!TAILQ_EMPTY(&host_list)) { 1027 hostp = TAILQ_FIRST(&host_list); 1028 TAILQ_REMOVE(&host_list, hostp, nh_link); 1029 1030 /* 1031 * Note that this does not do client-side cleanup. 1032 * We want to do that ONLY if statd tells us the 1033 * server has restarted. 1034 */ 1035 nlm_host_notify_server(hostp, argp->state); 1036 nlm_host_release(g, hostp); 1037 } 1038 1039 mutex_exit(&g->clean_lock); 1040 1041 (void) res; 1042 (void) sr; 1043 } 1044 1045 static void 1046 nlm_init_shrlock(struct shrlock *shr, 1047 nlm4_share *nshare, struct nlm_host *host) 1048 { 1049 1050 switch (nshare->access) { 1051 default: 1052 case fsa_NONE: 1053 shr->s_access = 0; 1054 break; 1055 case fsa_R: 1056 shr->s_access = F_RDACC; 1057 break; 1058 case fsa_W: 1059 shr->s_access = F_WRACC; 1060 break; 1061 case fsa_RW: 1062 shr->s_access = F_RWACC; 1063 break; 1064 } 1065 1066 switch (nshare->mode) { 1067 default: 1068 case fsm_DN: 1069 shr->s_deny = F_NODNY; 1070 break; 1071 case fsm_DR: 1072 shr->s_deny = F_RDDNY; 1073 break; 1074 case fsm_DW: 1075 shr->s_deny = F_WRDNY; 1076 break; 1077 case fsm_DRW: 1078 shr->s_deny = F_RWDNY; 1079 break; 1080 } 1081 1082 shr->s_sysid = host->nh_sysid; 1083 shr->s_pid = 0; 1084 shr->s_own_len = nshare->oh.n_len; 1085 shr->s_owner = nshare->oh.n_bytes; 1086 } 1087 1088 /* 1089 * NLM_SHARE, NLM4_SHARE 1090 * 1091 * Request a DOS-style share reservation 1092 */ 1093 void 1094 nlm_do_share(nlm4_shareargs *argp, nlm4_shareres *resp, struct svc_req *sr) 1095 { 1096 struct nlm_globals *g; 1097 struct nlm_host *host; 1098 struct netbuf *addr; 1099 struct nlm_vhold *nvp = NULL; 1100 char *netid; 1101 char *name; 1102 int error; 1103 struct shrlock shr; 1104 1105 nlm_copy_netobj(&resp->cookie, &argp->cookie); 1106 1107 name = argp->share.caller_name; 1108 netid = svc_getnetid(sr->rq_xprt); 1109 addr = svc_getrpccaller(sr->rq_xprt); 1110 1111 g = zone_getspecific(nlm_zone_key, curzone); 1112 host = nlm_host_findcreate(g, name, netid, addr); 1113 if (host == NULL) { 1114 resp->stat = nlm4_denied_nolocks; 1115 return; 1116 } 1117 1118 DTRACE_PROBE3(share__start, struct nlm_globals *, g, 1119 struct nlm_host *, host, nlm4_shareargs *, argp); 1120 1121 if (argp->reclaim == 0 && NLM_IN_GRACE(g)) { 1122 resp->stat = nlm4_denied_grace_period; 1123 goto out; 1124 } 1125 1126 /* 1127 * Get holded vnode when on lock operation. 1128 * Only lock() and share() need vhold objects. 1129 */ 1130 nvp = nlm_fh_to_vhold(host, &argp->share.fh); 1131 if (nvp == NULL) { 1132 resp->stat = nlm4_stale_fh; 1133 goto out; 1134 } 1135 1136 /* Convert to local form. */ 1137 nlm_init_shrlock(&shr, &argp->share, host); 1138 error = VOP_SHRLOCK(nvp->nv_vp, F_SHARE, &shr, 1139 FREAD | FWRITE, CRED(), NULL); 1140 1141 if (error == 0) { 1142 resp->stat = nlm4_granted; 1143 nlm_host_monitor(g, host, 0); 1144 } else { 1145 resp->stat = nlm4_denied; 1146 } 1147 1148 out: 1149 DTRACE_PROBE3(share__end, struct nlm_globals *, g, 1150 struct nlm_host *, host, nlm4_shareres *, resp); 1151 1152 nlm_vhold_release(host, nvp); 1153 nlm_host_release(g, host); 1154 } 1155 1156 /* 1157 * NLM_UNSHARE, NLM4_UNSHARE 1158 * 1159 * Release a DOS-style share reservation 1160 */ 1161 void 1162 nlm_do_unshare(nlm4_shareargs *argp, nlm4_shareres *resp, struct svc_req *sr) 1163 { 1164 struct nlm_globals *g; 1165 struct nlm_host *host; 1166 struct netbuf *addr; 1167 vnode_t *vp = NULL; 1168 char *netid; 1169 int error; 1170 struct shrlock shr; 1171 1172 nlm_copy_netobj(&resp->cookie, &argp->cookie); 1173 1174 netid = svc_getnetid(sr->rq_xprt); 1175 addr = svc_getrpccaller(sr->rq_xprt); 1176 1177 g = zone_getspecific(nlm_zone_key, curzone); 1178 host = nlm_host_find(g, netid, addr); 1179 if (host == NULL) { 1180 resp->stat = nlm4_denied_nolocks; 1181 return; 1182 } 1183 1184 DTRACE_PROBE3(unshare__start, struct nlm_globals *, g, 1185 struct nlm_host *, host, nlm4_shareargs *, argp); 1186 1187 if (NLM_IN_GRACE(g)) { 1188 resp->stat = nlm4_denied_grace_period; 1189 goto out; 1190 } 1191 1192 vp = nlm_fh_to_vp(&argp->share.fh); 1193 if (vp == NULL) { 1194 resp->stat = nlm4_stale_fh; 1195 goto out; 1196 } 1197 1198 /* Convert to local form. */ 1199 nlm_init_shrlock(&shr, &argp->share, host); 1200 error = VOP_SHRLOCK(vp, F_UNSHARE, &shr, 1201 FREAD | FWRITE, CRED(), NULL); 1202 1203 (void) error; 1204 resp->stat = nlm4_granted; 1205 1206 out: 1207 DTRACE_PROBE3(unshare__end, struct nlm_globals *, g, 1208 struct nlm_host *, host, nlm4_shareres *, resp); 1209 1210 if (vp != NULL) 1211 VN_RELE(vp); 1212 1213 nlm_host_release(g, host); 1214 } 1215 1216 /* 1217 * NLM wrapper to VOP_FRLOCK that checks the validity of the lock before 1218 * invoking the vnode operation. 1219 */ 1220 static int 1221 nlm_vop_frlock(vnode_t *vp, int cmd, flock64_t *bfp, int flag, offset_t offset, 1222 struct flk_callback *flk_cbp, cred_t *cr, caller_context_t *ct) 1223 { 1224 if (bfp->l_len != 0 && bfp->l_start + (bfp->l_len - 1) 1225 < bfp->l_start) { 1226 return (EOVERFLOW); 1227 } 1228 1229 return (VOP_FRLOCK(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct)); 1230 }