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 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include <sys/param.h> 32 #include <sys/fcntl.h> 33 #include <sys/jail.h> 34 #include <sys/kernel.h> 35 #include <sys/limits.h> 36 #include <sys/lock.h> 37 #include <sys/lockf.h> 38 #include <sys/malloc.h> 39 #include <sys/mbuf.h> 40 #include <sys/mount.h> 41 #include <sys/mutex.h> 42 #include <sys/proc.h> 43 #include <sys/socket.h> 44 #include <sys/syslog.h> 45 #include <sys/systm.h> 46 #include <sys/unistd.h> 47 #include <sys/vnode.h> 48 49 #include <nfs/nfsproto.h> 50 #include <nfsclient/nfs.h> 51 #include <nfsclient/nfsmount.h> 52 53 #include <nlm/nlm_prot.h> 54 #include <nlm/nlm.h> 55 56 /* 57 * We need to keep track of the svid values used for F_FLOCK locks. 58 */ 59 struct nlm_file_svid { 60 int ns_refs; /* thread count + 1 if active */ 61 int ns_svid; /* on-the-wire SVID for this file */ 62 struct ucred *ns_ucred; /* creds to use for lock recovery */ 63 void *ns_id; /* local struct file pointer */ 64 bool_t ns_active; /* TRUE if we own a lock */ 65 LIST_ENTRY(nlm_file_svid) ns_link; 66 }; 67 LIST_HEAD(nlm_file_svid_list, nlm_file_svid); 68 69 #define NLM_SVID_HASH_SIZE 256 70 struct nlm_file_svid_list nlm_file_svids[NLM_SVID_HASH_SIZE]; 71 72 struct mtx nlm_svid_lock; 73 static struct unrhdr *nlm_svid_allocator; 74 static volatile u_int nlm_xid = 1; 75 76 static int nlm_setlock(struct nlm_host *host, struct rpc_callextra *ext, 77 rpcvers_t vers, struct timeval *timo, int retries, 78 struct vnode *vp, int op, struct flock *fl, int flags, 79 int svid, size_t fhlen, void *fh, off_t size, bool_t reclaim); 80 static int nlm_clearlock(struct nlm_host *host, struct rpc_callextra *ext, 81 rpcvers_t vers, struct timeval *timo, int retries, 82 struct vnode *vp, int op, struct flock *fl, int flags, 83 int svid, size_t fhlen, void *fh, off_t size); 84 static int nlm_getlock(struct nlm_host *host, struct rpc_callextra *ext, 85 rpcvers_t vers, struct timeval *timo, int retries, 86 struct vnode *vp, int op, struct flock *fl, int flags, 87 int svid, size_t fhlen, void *fh, off_t size); 88 static int nlm_map_status(nlm4_stats stat); 89 static struct nlm_file_svid *nlm_find_svid(void *id); 90 static void nlm_free_svid(struct nlm_file_svid *nf); 91 static int nlm_init_lock(struct flock *fl, int flags, int svid, 92 rpcvers_t vers, size_t fhlen, void *fh, off_t size, 93 struct nlm4_lock *lock, char oh_space[32]); 94 95 static void 96 nlm_client_init(void *dummy) 97 { 98 int i; 99 100 mtx_init(&nlm_svid_lock, "NLM svid lock", NULL, MTX_DEF); 101 nlm_svid_allocator = new_unrhdr(PID_MAX + 2, INT_MAX, &nlm_svid_lock); 102 for (i = 0; i < NLM_SVID_HASH_SIZE; i++) 103 LIST_INIT(&nlm_file_svids[i]); 104 } 105 SYSINIT(nlm_client_init, SI_SUB_LOCK, SI_ORDER_FIRST, nlm_client_init, NULL); 106 107 static int 108 nlm_msg(struct thread *td, const char *server, const char *msg, int error) 109 { 110 struct proc *p; 111 112 p = td ? td->td_proc : NULL; 113 if (error) { 114 tprintf(p, LOG_INFO, "nfs server %s: %s, error %d\n", server, 115 msg, error); 116 } else { 117 tprintf(p, LOG_INFO, "nfs server %s: %s\n", server, msg); 118 } 119 return (0); 120 } 121 122 struct nlm_feedback_arg { 123 bool_t nf_printed; 124 struct nfsmount *nf_nmp; 125 }; 126 127 static void 128 nlm_down(struct nlm_feedback_arg *nf, struct thread *td, 129 const char *msg, int error) 130 { 131 struct nfsmount *nmp = nf->nf_nmp; 132 133 if (nmp == NULL) 134 return; 135 mtx_lock(&nmp->nm_mtx); 136 if (!(nmp->nm_state & NFSSTA_LOCKTIMEO)) { 137 nmp->nm_state |= NFSSTA_LOCKTIMEO; 138 mtx_unlock(&nmp->nm_mtx); 139 vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid, 140 VQ_NOTRESPLOCK, 0); 141 } else { 142 mtx_unlock(&nmp->nm_mtx); 143 } 144 145 nf->nf_printed = TRUE; 146 nlm_msg(td, nmp->nm_mountp->mnt_stat.f_mntfromname, msg, error); 147 } 148 149 static void 150 nlm_up(struct nlm_feedback_arg *nf, struct thread *td, 151 const char *msg) 152 { 153 struct nfsmount *nmp = nf->nf_nmp; 154 155 if (!nf->nf_printed) 156 return; 157 158 nlm_msg(td, nmp->nm_mountp->mnt_stat.f_mntfromname, msg, 0); 159 160 mtx_lock(&nmp->nm_mtx); 161 if (nmp->nm_state & NFSSTA_LOCKTIMEO) { 162 nmp->nm_state &= ~NFSSTA_LOCKTIMEO; 163 mtx_unlock(&nmp->nm_mtx); 164 vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid, 165 VQ_NOTRESPLOCK, 1); 166 } else { 167 mtx_unlock(&nmp->nm_mtx); 168 } 169 } 170 171 static void 172 nlm_feedback(int type, int proc, void *arg) 173 { 174 struct thread *td = curthread; 175 struct nlm_feedback_arg *nf = (struct nlm_feedback_arg *) arg; 176 177 switch (type) { 178 case FEEDBACK_REXMIT2: 179 case FEEDBACK_RECONNECT: 180 nlm_down(nf, td, "lockd not responding", 0); 181 break; 182 183 case FEEDBACK_OK: 184 nlm_up(nf, td, "lockd is alive again"); 185 break; 186 } 187 } 188 189 /* 190 * nlm_advlock -- 191 * NFS advisory byte-level locks. 192 */ 193 static int 194 nlm_advlock_internal(struct vnode *vp, void *id, int op, struct flock *fl, 195 int flags, bool_t reclaim, bool_t unlock_vp) 196 { 197 struct thread *td = curthread; 198 struct nfsmount *nmp; 199 off_t size; 200 size_t fhlen; 201 union nfsfh fh; 202 struct sockaddr *sa; 203 struct sockaddr_storage ss; 204 char servername[MNAMELEN]; 205 struct timeval timo; 206 int retries; 207 rpcvers_t vers; 208 struct nlm_host *host; 209 struct rpc_callextra ext; 210 struct nlm_feedback_arg nf; 211 AUTH *auth; 212 struct ucred *cred; 213 struct nlm_file_svid *ns; 214 int svid; 215 int error; 216 int is_v3; 217 218 ASSERT_VOP_LOCKED(vp, "nlm_advlock_1"); 219 220 nmp = VFSTONFS(vp->v_mount); 221 /* 222 * Push any pending writes to the server and flush our cache 223 * so that if we are contending with another machine for a 224 * file, we get whatever they wrote and vice-versa. 225 */ 226 if (op == F_SETLK || op == F_UNLCK) 227 nmp->nm_vinvalbuf(vp, V_SAVE, td, 1); 228 229 strcpy(servername, nmp->nm_hostname); 230 nmp->nm_getinfo(vp, fh.fh_bytes, &fhlen, &ss, &is_v3, &size, &timo); 231 sa = (struct sockaddr *) &ss; 232 if (is_v3 != 0) 233 vers = NLM_VERS4; 234 else 235 vers = NLM_VERS; 236 237 if (nmp->nm_flag & NFSMNT_SOFT) 238 retries = nmp->nm_retry; 239 else 240 retries = INT_MAX; 241 242 if (unlock_vp) 243 VOP_UNLOCK(vp, 0); 244 245 /* 246 * We need to switch to mount-point creds so that we can send 247 * packets from a privileged port. 248 */ 249 cred = td->td_ucred; 250 td->td_ucred = vp->v_mount->mnt_cred; 251 252 host = nlm_find_host_by_name(servername, sa, vers); 253 auth = authunix_create(cred); 254 memset(&ext, 0, sizeof(ext)); 255 256 nf.nf_printed = FALSE; 257 nf.nf_nmp = nmp; 258 ext.rc_auth = auth; 259 260 ext.rc_feedback = nlm_feedback; 261 ext.rc_feedback_arg = &nf; 262 ext.rc_timers = NULL; 263 264 ns = NULL; 265 if (flags & F_FLOCK) { 266 ns = nlm_find_svid(id); 267 KASSERT(fl->l_start == 0 && fl->l_len == 0, 268 ("F_FLOCK lock requests must be whole-file locks")); 269 if (!ns->ns_ucred) { 270 /* 271 * Remember the creds used for locking in case 272 * we need to recover the lock later. 273 */ 274 ns->ns_ucred = crdup(cred); 275 } 276 svid = ns->ns_svid; 277 } else if (flags & F_REMOTE) { 278 /* 279 * If we are recovering after a server restart or 280 * trashing locks on a force unmount, use the same 281 * svid as last time. 282 */ 283 svid = fl->l_pid; 284 } else { 285 svid = ((struct proc *) id)->p_pid; 286 } 287 288 switch(op) { 289 case F_SETLK: 290 if ((flags & (F_FLOCK|F_WAIT)) == (F_FLOCK|F_WAIT) 291 && fl->l_type == F_WRLCK) { 292 /* 293 * The semantics for flock(2) require that any 294 * shared lock on the file must be released 295 * before an exclusive lock is granted. The 296 * local locking code interprets this by 297 * unlocking the file before sleeping on a 298 * blocked exclusive lock request. We 299 * approximate this by first attempting 300 * non-blocking and if that fails, we unlock 301 * the file and block. 302 */ 303 error = nlm_setlock(host, &ext, vers, &timo, retries, 304 vp, F_SETLK, fl, flags & ~F_WAIT, 305 svid, fhlen, &fh.fh_bytes, size, reclaim); 306 if (error == EAGAIN) { 307 fl->l_type = F_UNLCK; 308 error = nlm_clearlock(host, &ext, vers, &timo, 309 retries, vp, F_UNLCK, fl, flags, 310 svid, fhlen, &fh.fh_bytes, size); 311 fl->l_type = F_WRLCK; 312 if (!error) { 313 mtx_lock(&nlm_svid_lock); 314 if (ns->ns_active) { 315 ns->ns_refs--; 316 ns->ns_active = FALSE; 317 } 318 mtx_unlock(&nlm_svid_lock); 319 flags |= F_WAIT; 320 error = nlm_setlock(host, &ext, vers, 321 &timo, retries, vp, F_SETLK, fl, 322 flags, svid, fhlen, &fh.fh_bytes, 323 size, reclaim); 324 } 325 } 326 } else { 327 error = nlm_setlock(host, &ext, vers, &timo, retries, 328 vp, op, fl, flags, svid, fhlen, &fh.fh_bytes, 329 size, reclaim); 330 } 331 if (!error && ns) { 332 mtx_lock(&nlm_svid_lock); 333 if (!ns->ns_active) { 334 /* 335 * Add one to the reference count to 336 * hold onto the SVID for the lifetime 337 * of the lock. Note that since 338 * F_FLOCK only supports whole-file 339 * locks, there can only be one active 340 * lock for this SVID. 341 */ 342 ns->ns_refs++; 343 ns->ns_active = TRUE; 344 } 345 mtx_unlock(&nlm_svid_lock); 346 } 347 break; 348 349 case F_UNLCK: 350 error = nlm_clearlock(host, &ext, vers, &timo, retries, 351 vp, op, fl, flags, svid, fhlen, &fh.fh_bytes, size); 352 if (!error && ns) { 353 mtx_lock(&nlm_svid_lock); 354 if (ns->ns_active) { 355 ns->ns_refs--; 356 ns->ns_active = FALSE; 357 } 358 mtx_unlock(&nlm_svid_lock); 359 } 360 break; 361 362 case F_GETLK: 363 error = nlm_getlock(host, &ext, vers, &timo, retries, 364 vp, op, fl, flags, svid, fhlen, &fh.fh_bytes, size); 365 break; 366 367 default: 368 error = EINVAL; 369 break; 370 } 371 372 if (ns) 373 nlm_free_svid(ns); 374 375 td->td_ucred = cred; 376 AUTH_DESTROY(auth); 377 378 nlm_host_release(host); 379 380 return (error); 381 } 382 383 int 384 nlm_advlock(struct vop_advlock_args *ap) 385 { 386 387 return (nlm_advlock_internal(ap->a_vp, ap->a_id, ap->a_op, ap->a_fl, 388 ap->a_flags, FALSE, TRUE)); 389 } 390 391 /* 392 * Set the creds of td to the creds of the given lock's owner. The new 393 * creds reference count will be incremented via crhold. The caller is 394 * responsible for calling crfree and restoring td's original creds. 395 */ 396 static void 397 nlm_set_creds_for_lock(struct thread *td, struct flock *fl) 398 { 399 int i; 400 struct nlm_file_svid *ns; 401 struct proc *p; 402 struct ucred *cred; 403 404 cred = NULL; 405 if (fl->l_pid > PID_MAX) { 406 /* 407 * If this was originally a F_FLOCK-style lock, we 408 * recorded the creds used when it was originally 409 * locked in the nlm_file_svid structure. 410 */ 411 mtx_lock(&nlm_svid_lock); 412 for (i = 0; i < NLM_SVID_HASH_SIZE; i++) { 413 for (ns = LIST_FIRST(&nlm_file_svids[i]); ns; 414 ns = LIST_NEXT(ns, ns_link)) { 415 if (ns->ns_svid == fl->l_pid) { 416 cred = crhold(ns->ns_ucred); 417 break; 418 } 419 } 420 } 421 mtx_unlock(&nlm_svid_lock); 422 } else { 423 /* 424 * This lock is owned by a process. Get a reference to 425 * the process creds. 426 */ 427 p = pfind(fl->l_pid); 428 if (p) { 429 cred = crhold(p->p_ucred); 430 PROC_UNLOCK(p); 431 } 432 } 433 434 /* 435 * If we can't find a cred, fall back on the recovery 436 * thread's cred. 437 */ 438 if (!cred) { 439 cred = crhold(td->td_ucred); 440 } 441 442 td->td_ucred = cred; 443 } 444 445 static int 446 nlm_reclaim_free_lock(struct vnode *vp, struct flock *fl, void *arg) 447 { 448 struct flock newfl; 449 struct thread *td = curthread; 450 struct ucred *oldcred; 451 int error; 452 453 newfl = *fl; 454 newfl.l_type = F_UNLCK; 455 456 oldcred = td->td_ucred; 457 nlm_set_creds_for_lock(td, &newfl); 458 459 error = nlm_advlock_internal(vp, NULL, F_UNLCK, &newfl, F_REMOTE, 460 FALSE, FALSE); 461 462 crfree(td->td_ucred); 463 td->td_ucred = oldcred; 464 465 return (error); 466 } 467 468 int 469 nlm_reclaim(struct vop_reclaim_args *ap) 470 { 471 472 nlm_cancel_wait(ap->a_vp); 473 lf_iteratelocks_vnode(ap->a_vp, nlm_reclaim_free_lock, NULL); 474 return (0); 475 } 476 477 struct nlm_recovery_context { 478 struct nlm_host *nr_host; /* host we are recovering */ 479 int nr_state; /* remote NSM state for recovery */ 480 }; 481 482 static int 483 nlm_client_recover_lock(struct vnode *vp, struct flock *fl, void *arg) 484 { 485 struct nlm_recovery_context *nr = (struct nlm_recovery_context *) arg; 486 struct thread *td = curthread; 487 struct ucred *oldcred; 488 int state, error; 489 490 /* 491 * If the remote NSM state changes during recovery, the host 492 * must have rebooted a second time. In that case, we must 493 * restart the recovery. 494 */ 495 state = nlm_host_get_state(nr->nr_host); 496 if (nr->nr_state != state) 497 return (ERESTART); 498 499 error = vn_lock(vp, LK_SHARED); 500 if (error) 501 return (error); 502 503 oldcred = td->td_ucred; 504 nlm_set_creds_for_lock(td, fl); 505 506 error = nlm_advlock_internal(vp, NULL, F_SETLK, fl, F_REMOTE, 507 TRUE, TRUE); 508 509 crfree(td->td_ucred); 510 td->td_ucred = oldcred; 511 512 return (error); 513 } 514 515 void 516 nlm_client_recovery(struct nlm_host *host) 517 { 518 struct nlm_recovery_context nr; 519 int sysid, error; 520 521 sysid = NLM_SYSID_CLIENT | nlm_host_get_sysid(host); 522 do { 523 nr.nr_host = host; 524 nr.nr_state = nlm_host_get_state(host); 525 error = lf_iteratelocks_sysid(sysid, 526 nlm_client_recover_lock, &nr); 527 } while (error == ERESTART); 528 } 529 530 static void 531 nlm_convert_to_nlm_lock(struct nlm_lock *dst, struct nlm4_lock *src) 532 { 533 534 dst->caller_name = src->caller_name; 535 dst->fh = src->fh; 536 dst->oh = src->oh; 537 dst->svid = src->svid; 538 dst->l_offset = src->l_offset; 539 dst->l_len = src->l_len; 540 } 541 542 static void 543 nlm_convert_to_nlm4_holder(struct nlm4_holder *dst, struct nlm_holder *src) 544 { 545 546 dst->exclusive = src->exclusive; 547 dst->svid = src->svid; 548 dst->oh = src->oh; 549 dst->l_offset = src->l_offset; 550 dst->l_len = src->l_len; 551 } 552 553 static void 554 nlm_convert_to_nlm4_res(struct nlm4_res *dst, struct nlm_res *src) 555 { 556 dst->cookie = src->cookie; 557 dst->stat.stat = (enum nlm4_stats) src->stat.stat; 558 } 559 560 static enum clnt_stat 561 nlm_test_rpc(rpcvers_t vers, nlm4_testargs *args, nlm4_testres *res, CLIENT *client, 562 struct rpc_callextra *ext, struct timeval timo) 563 { 564 if (vers == NLM_VERS4) { 565 return nlm4_test_4(args, res, client, ext, timo); 566 } else { 567 nlm_testargs args1; 568 nlm_testres res1; 569 enum clnt_stat stat; 570 571 args1.cookie = args->cookie; 572 args1.exclusive = args->exclusive; 573 nlm_convert_to_nlm_lock(&args1.alock, &args->alock); 574 memset(&res1, 0, sizeof(res1)); 575 576 stat = nlm_test_1(&args1, &res1, client, ext, timo); 577 578 if (stat == RPC_SUCCESS) { 579 res->cookie = res1.cookie; 580 res->stat.stat = (enum nlm4_stats) res1.stat.stat; 581 if (res1.stat.stat == nlm_denied) 582 nlm_convert_to_nlm4_holder( 583 &res->stat.nlm4_testrply_u.holder, 584 &res1.stat.nlm_testrply_u.holder); 585 } 586 587 return (stat); 588 } 589 } 590 591 static enum clnt_stat 592 nlm_lock_rpc(rpcvers_t vers, nlm4_lockargs *args, nlm4_res *res, CLIENT *client, 593 struct rpc_callextra *ext, struct timeval timo) 594 { 595 if (vers == NLM_VERS4) { 596 return nlm4_lock_4(args, res, client, ext, timo); 597 } else { 598 nlm_lockargs args1; 599 nlm_res res1; 600 enum clnt_stat stat; 601 602 args1.cookie = args->cookie; 603 args1.block = args->block; 604 args1.exclusive = args->exclusive; 605 nlm_convert_to_nlm_lock(&args1.alock, &args->alock); 606 args1.reclaim = args->reclaim; 607 args1.state = args->state; 608 memset(&res1, 0, sizeof(res1)); 609 610 stat = nlm_lock_1(&args1, &res1, client, ext, timo); 611 612 if (stat == RPC_SUCCESS) { 613 nlm_convert_to_nlm4_res(res, &res1); 614 } 615 616 return (stat); 617 } 618 } 619 620 static enum clnt_stat 621 nlm_cancel_rpc(rpcvers_t vers, nlm4_cancargs *args, nlm4_res *res, CLIENT *client, 622 struct rpc_callextra *ext, struct timeval timo) 623 { 624 if (vers == NLM_VERS4) { 625 return nlm4_cancel_4(args, res, client, ext, timo); 626 } else { 627 nlm_cancargs args1; 628 nlm_res res1; 629 enum clnt_stat stat; 630 631 args1.cookie = args->cookie; 632 args1.block = args->block; 633 args1.exclusive = args->exclusive; 634 nlm_convert_to_nlm_lock(&args1.alock, &args->alock); 635 memset(&res1, 0, sizeof(res1)); 636 637 stat = nlm_cancel_1(&args1, &res1, client, ext, timo); 638 639 if (stat == RPC_SUCCESS) { 640 nlm_convert_to_nlm4_res(res, &res1); 641 } 642 643 return (stat); 644 } 645 } 646 647 static enum clnt_stat 648 nlm_unlock_rpc(rpcvers_t vers, nlm4_unlockargs *args, nlm4_res *res, CLIENT *client, 649 struct rpc_callextra *ext, struct timeval timo) 650 { 651 if (vers == NLM_VERS4) { 652 return nlm4_unlock_4(args, res, client, ext, timo); 653 } else { 654 nlm_unlockargs args1; 655 nlm_res res1; 656 enum clnt_stat stat; 657 658 args1.cookie = args->cookie; 659 nlm_convert_to_nlm_lock(&args1.alock, &args->alock); 660 memset(&res1, 0, sizeof(res1)); 661 662 stat = nlm_unlock_1(&args1, &res1, client, ext, timo); 663 664 if (stat == RPC_SUCCESS) { 665 nlm_convert_to_nlm4_res(res, &res1); 666 } 667 668 return (stat); 669 } 670 } 671 672 /* 673 * Called after a lock request (set or clear) succeeded. We record the 674 * details in the local lock manager. Note that since the remote 675 * server has granted the lock, we can be sure that it doesn't 676 * conflict with any other locks we have in the local lock manager. 677 * 678 * Since it is possible that host may also make NLM client requests to 679 * our NLM server, we use a different sysid value to record our own 680 * client locks. 681 * 682 * Note that since it is possible for us to receive replies from the 683 * server in a different order than the locks were granted (e.g. if 684 * many local threads are contending for the same lock), we must use a 685 * blocking operation when registering with the local lock manager. 686 * We expect that any actual wait will be rare and short hence we 687 * ignore signals for this. 688 */ 689 static void 690 nlm_record_lock(struct vnode *vp, int op, struct flock *fl, 691 int svid, int sysid, off_t size) 692 { 693 struct vop_advlockasync_args a; 694 struct flock newfl; 695 int error; 696 697 a.a_vp = vp; 698 a.a_id = NULL; 699 a.a_op = op; 700 a.a_fl = &newfl; 701 a.a_flags = F_REMOTE|F_WAIT|F_NOINTR; 702 a.a_task = NULL; 703 a.a_cookiep = NULL; 704 newfl.l_start = fl->l_start; 705 newfl.l_len = fl->l_len; 706 newfl.l_type = fl->l_type; 707 newfl.l_whence = fl->l_whence; 708 newfl.l_pid = svid; 709 newfl.l_sysid = NLM_SYSID_CLIENT | sysid; 710 711 error = lf_advlockasync(&a, &vp->v_lockf, size); 712 KASSERT(error == 0 || error == ENOENT, 713 ("Failed to register NFS lock locally - error=%d", error)); 714 } 715 716 static int 717 nlm_setlock(struct nlm_host *host, struct rpc_callextra *ext, 718 rpcvers_t vers, struct timeval *timo, int retries, 719 struct vnode *vp, int op, struct flock *fl, int flags, 720 int svid, size_t fhlen, void *fh, off_t size, bool_t reclaim) 721 { 722 struct nlm4_lockargs args; 723 char oh_space[32]; 724 struct nlm4_res res; 725 u_int xid; 726 CLIENT *client; 727 enum clnt_stat stat; 728 int retry, block, exclusive; 729 void *wait_handle = NULL; 730 int error; 731 732 memset(&args, 0, sizeof(args)); 733 memset(&res, 0, sizeof(res)); 734 735 block = (flags & F_WAIT) ? TRUE : FALSE; 736 exclusive = (fl->l_type == F_WRLCK); 737 738 error = nlm_init_lock(fl, flags, svid, vers, fhlen, fh, size, 739 &args.alock, oh_space); 740 if (error) 741 return (error); 742 args.block = block; 743 args.exclusive = exclusive; 744 args.reclaim = reclaim; 745 args.state = nlm_nsm_state; 746 747 retry = 5*hz; 748 for (;;) { 749 client = nlm_host_get_rpc(host, FALSE); 750 if (!client) 751 return (ENOLCK); /* XXX retry? */ 752 753 if (block) 754 wait_handle = nlm_register_wait_lock(&args.alock, vp); 755 756 xid = atomic_fetchadd_int(&nlm_xid, 1); 757 args.cookie.n_len = sizeof(xid); 758 args.cookie.n_bytes = (char*) &xid; 759 760 stat = nlm_lock_rpc(vers, &args, &res, client, ext, *timo); 761 762 CLNT_RELEASE(client); 763 764 if (stat != RPC_SUCCESS) { 765 if (block) 766 nlm_deregister_wait_lock(wait_handle); 767 if (retries) { 768 retries--; 769 continue; 770 } 771 return (EINVAL); 772 } 773 774 /* 775 * Free res.cookie. 776 */ 777 xdr_free((xdrproc_t) xdr_nlm4_res, &res); 778 779 if (block && res.stat.stat != nlm4_blocked) 780 nlm_deregister_wait_lock(wait_handle); 781 782 if (res.stat.stat == nlm4_denied_grace_period) { 783 /* 784 * The server has recently rebooted and is 785 * giving old clients a change to reclaim 786 * their locks. Wait for a few seconds and try 787 * again. 788 */ 789 error = tsleep(&args, PCATCH, "nlmgrace", retry); 790 if (error && error != EWOULDBLOCK) 791 return (error); 792 retry = 2*retry; 793 if (retry > 30*hz) 794 retry = 30*hz; 795 continue; 796 } 797 798 if (block && res.stat.stat == nlm4_blocked) { 799 /* 800 * The server should call us back with a 801 * granted message when the lock succeeds. In 802 * order to deal with broken servers, lost 803 * granted messages and server reboots, we 804 * will also re-try every few seconds. 805 */ 806 error = nlm_wait_lock(wait_handle, retry); 807 if (error == EWOULDBLOCK) { 808 retry = 2*retry; 809 if (retry > 30*hz) 810 retry = 30*hz; 811 continue; 812 } 813 if (error) { 814 /* 815 * We need to call the server to 816 * cancel our lock request. 817 */ 818 nlm4_cancargs cancel; 819 820 memset(&cancel, 0, sizeof(cancel)); 821 822 xid = atomic_fetchadd_int(&nlm_xid, 1); 823 cancel.cookie.n_len = sizeof(xid); 824 cancel.cookie.n_bytes = (char*) &xid; 825 cancel.block = block; 826 cancel.exclusive = exclusive; 827 cancel.alock = args.alock; 828 829 do { 830 client = nlm_host_get_rpc(host, FALSE); 831 if (!client) 832 /* XXX retry? */ 833 return (ENOLCK); 834 835 stat = nlm_cancel_rpc(vers, &cancel, 836 &res, client, ext, *timo); 837 838 CLNT_RELEASE(client); 839 840 if (stat != RPC_SUCCESS) { 841 /* 842 * We need to cope 843 * with temporary 844 * network partitions 845 * as well as server 846 * reboots. This means 847 * we have to keep 848 * trying to cancel 849 * until the server 850 * wakes up again. 851 */ 852 pause("nlmcancel", 10*hz); 853 } 854 } while (stat != RPC_SUCCESS); 855 856 /* 857 * Free res.cookie. 858 */ 859 xdr_free((xdrproc_t) xdr_nlm4_res, &res); 860 861 switch (res.stat.stat) { 862 case nlm_denied: 863 /* 864 * There was nothing 865 * to cancel. We are 866 * going to go ahead 867 * and assume we got 868 * the lock. 869 */ 870 error = 0; 871 break; 872 873 case nlm4_denied_grace_period: 874 /* 875 * The server has 876 * recently rebooted - 877 * treat this as a 878 * successful 879 * cancellation. 880 */ 881 break; 882 883 case nlm4_granted: 884 /* 885 * We managed to 886 * cancel. 887 */ 888 break; 889 890 default: 891 /* 892 * Broken server 893 * implementation - 894 * can't really do 895 * anything here. 896 */ 897 break; 898 } 899 900 } 901 } else { 902 error = nlm_map_status(res.stat.stat); 903 } 904 905 if (!error && !reclaim) { 906 nlm_record_lock(vp, op, fl, args.alock.svid, 907 nlm_host_get_sysid(host), size); 908 nlm_host_monitor(host, 0); 909 } 910 911 return (error); 912 } 913 } 914 915 static int 916 nlm_clearlock(struct nlm_host *host, struct rpc_callextra *ext, 917 rpcvers_t vers, struct timeval *timo, int retries, 918 struct vnode *vp, int op, struct flock *fl, int flags, 919 int svid, size_t fhlen, void *fh, off_t size) 920 { 921 struct nlm4_unlockargs args; 922 char oh_space[32]; 923 struct nlm4_res res; 924 u_int xid; 925 CLIENT *client; 926 enum clnt_stat stat; 927 int error; 928 929 memset(&args, 0, sizeof(args)); 930 memset(&res, 0, sizeof(res)); 931 932 error = nlm_init_lock(fl, flags, svid, vers, fhlen, fh, size, 933 &args.alock, oh_space); 934 if (error) 935 return (error); 936 937 for (;;) { 938 client = nlm_host_get_rpc(host, FALSE); 939 if (!client) 940 return (ENOLCK); /* XXX retry? */ 941 942 xid = atomic_fetchadd_int(&nlm_xid, 1); 943 args.cookie.n_len = sizeof(xid); 944 args.cookie.n_bytes = (char*) &xid; 945 946 stat = nlm_unlock_rpc(vers, &args, &res, client, ext, *timo); 947 948 CLNT_RELEASE(client); 949 950 if (stat != RPC_SUCCESS) { 951 if (retries) { 952 retries--; 953 continue; 954 } 955 return (EINVAL); 956 } 957 958 /* 959 * Free res.cookie. 960 */ 961 xdr_free((xdrproc_t) xdr_nlm4_res, &res); 962 963 if (res.stat.stat == nlm4_denied_grace_period) { 964 /* 965 * The server has recently rebooted and is 966 * giving old clients a change to reclaim 967 * their locks. Wait for a few seconds and try 968 * again. 969 */ 970 error = tsleep(&args, PCATCH, "nlmgrace", 5*hz); 971 if (error && error != EWOULDBLOCK) 972 return (error); 973 continue; 974 } 975 976 /* 977 * If we are being called via nlm_reclaim (which will 978 * use the F_REMOTE flag), don't record the lock 979 * operation in the local lock manager since the vnode 980 * is going away. 981 */ 982 if (!(flags & F_REMOTE)) 983 nlm_record_lock(vp, op, fl, args.alock.svid, 984 nlm_host_get_sysid(host), size); 985 986 return (0); 987 } 988 } 989 990 static int 991 nlm_getlock(struct nlm_host *host, struct rpc_callextra *ext, 992 rpcvers_t vers, struct timeval *timo, int retries, 993 struct vnode *vp, int op, struct flock *fl, int flags, 994 int svid, size_t fhlen, void *fh, off_t size) 995 { 996 struct nlm4_testargs args; 997 char oh_space[32]; 998 struct nlm4_testres res; 999 u_int xid; 1000 CLIENT *client; 1001 enum clnt_stat stat; 1002 int exclusive; 1003 int error; 1004 1005 KASSERT(!(flags & F_FLOCK), ("unexpected F_FLOCK for F_GETLK")); 1006 1007 memset(&args, 0, sizeof(args)); 1008 memset(&res, 0, sizeof(res)); 1009 1010 exclusive = (fl->l_type == F_WRLCK); 1011 1012 error = nlm_init_lock(fl, flags, svid, vers, fhlen, fh, size, 1013 &args.alock, oh_space); 1014 if (error) 1015 return (error); 1016 args.exclusive = exclusive; 1017 1018 for (;;) { 1019 client = nlm_host_get_rpc(host, FALSE); 1020 if (!client) 1021 return (ENOLCK); /* XXX retry? */ 1022 1023 xid = atomic_fetchadd_int(&nlm_xid, 1); 1024 args.cookie.n_len = sizeof(xid); 1025 args.cookie.n_bytes = (char*) &xid; 1026 1027 stat = nlm_test_rpc(vers, &args, &res, client, ext, *timo); 1028 1029 CLNT_RELEASE(client); 1030 1031 if (stat != RPC_SUCCESS) { 1032 if (retries) { 1033 retries--; 1034 continue; 1035 } 1036 return (EINVAL); 1037 } 1038 1039 if (res.stat.stat == nlm4_denied_grace_period) { 1040 /* 1041 * The server has recently rebooted and is 1042 * giving old clients a change to reclaim 1043 * their locks. Wait for a few seconds and try 1044 * again. 1045 */ 1046 xdr_free((xdrproc_t) xdr_nlm4_testres, &res); 1047 error = tsleep(&args, PCATCH, "nlmgrace", 5*hz); 1048 if (error && error != EWOULDBLOCK) 1049 return (error); 1050 continue; 1051 } 1052 1053 if (res.stat.stat == nlm4_denied) { 1054 struct nlm4_holder *h = 1055 &res.stat.nlm4_testrply_u.holder; 1056 fl->l_start = h->l_offset; 1057 fl->l_len = h->l_len; 1058 fl->l_pid = h->svid; 1059 if (h->exclusive) 1060 fl->l_type = F_WRLCK; 1061 else 1062 fl->l_type = F_RDLCK; 1063 fl->l_whence = SEEK_SET; 1064 fl->l_sysid = 0; 1065 } else { 1066 fl->l_type = F_UNLCK; 1067 } 1068 1069 xdr_free((xdrproc_t) xdr_nlm4_testres, &res); 1070 1071 return (0); 1072 } 1073 } 1074 1075 static int 1076 nlm_map_status(nlm4_stats stat) 1077 { 1078 switch (stat) { 1079 case nlm4_granted: 1080 return (0); 1081 1082 case nlm4_denied: 1083 return (EAGAIN); 1084 1085 case nlm4_denied_nolocks: 1086 return (ENOLCK); 1087 1088 case nlm4_deadlck: 1089 return (EDEADLK); 1090 1091 case nlm4_rofs: 1092 return (EROFS); 1093 1094 case nlm4_stale_fh: 1095 return (ESTALE); 1096 1097 case nlm4_fbig: 1098 return (EFBIG); 1099 1100 case nlm4_failed: 1101 return (EACCES); 1102 1103 default: 1104 return (EINVAL); 1105 } 1106 } 1107 1108 static struct nlm_file_svid * 1109 nlm_find_svid(void *id) 1110 { 1111 struct nlm_file_svid *ns, *newns; 1112 int h; 1113 1114 h = (((uintptr_t) id) >> 7) % NLM_SVID_HASH_SIZE; 1115 1116 mtx_lock(&nlm_svid_lock); 1117 LIST_FOREACH(ns, &nlm_file_svids[h], ns_link) { 1118 if (ns->ns_id == id) { 1119 ns->ns_refs++; 1120 break; 1121 } 1122 } 1123 mtx_unlock(&nlm_svid_lock); 1124 if (!ns) { 1125 int svid = alloc_unr(nlm_svid_allocator); 1126 newns = malloc(sizeof(struct nlm_file_svid), M_NLM, 1127 M_WAITOK); 1128 newns->ns_refs = 1; 1129 newns->ns_id = id; 1130 newns->ns_svid = svid; 1131 newns->ns_ucred = NULL; 1132 newns->ns_active = FALSE; 1133 1134 /* 1135 * We need to check for a race with some other 1136 * thread allocating a svid for this file. 1137 */ 1138 mtx_lock(&nlm_svid_lock); 1139 LIST_FOREACH(ns, &nlm_file_svids[h], ns_link) { 1140 if (ns->ns_id == id) { 1141 ns->ns_refs++; 1142 break; 1143 } 1144 } 1145 if (ns) { 1146 mtx_unlock(&nlm_svid_lock); 1147 free_unr(nlm_svid_allocator, newns->ns_svid); 1148 free(newns, M_NLM); 1149 } else { 1150 LIST_INSERT_HEAD(&nlm_file_svids[h], newns, 1151 ns_link); 1152 ns = newns; 1153 mtx_unlock(&nlm_svid_lock); 1154 } 1155 } 1156 1157 return (ns); 1158 } 1159 1160 static void 1161 nlm_free_svid(struct nlm_file_svid *ns) 1162 { 1163 1164 mtx_lock(&nlm_svid_lock); 1165 ns->ns_refs--; 1166 if (!ns->ns_refs) { 1167 KASSERT(!ns->ns_active, ("Freeing active SVID")); 1168 LIST_REMOVE(ns, ns_link); 1169 mtx_unlock(&nlm_svid_lock); 1170 free_unr(nlm_svid_allocator, ns->ns_svid); 1171 if (ns->ns_ucred) 1172 crfree(ns->ns_ucred); 1173 free(ns, M_NLM); 1174 } else { 1175 mtx_unlock(&nlm_svid_lock); 1176 } 1177 } 1178 1179 static int 1180 nlm_init_lock(struct flock *fl, int flags, int svid, 1181 rpcvers_t vers, size_t fhlen, void *fh, off_t size, 1182 struct nlm4_lock *lock, char oh_space[32]) 1183 { 1184 size_t oh_len; 1185 off_t start, len; 1186 1187 if (fl->l_whence == SEEK_END) { 1188 if (size > OFF_MAX 1189 || (fl->l_start > 0 && size > OFF_MAX - fl->l_start)) 1190 return (EOVERFLOW); 1191 start = size + fl->l_start; 1192 } else if (fl->l_whence == SEEK_SET || fl->l_whence == SEEK_CUR) { 1193 start = fl->l_start; 1194 } else { 1195 return (EINVAL); 1196 } 1197 if (start < 0) 1198 return (EINVAL); 1199 if (fl->l_len < 0) { 1200 len = -fl->l_len; 1201 start -= len; 1202 if (start < 0) 1203 return (EINVAL); 1204 } else { 1205 len = fl->l_len; 1206 } 1207 1208 if (vers == NLM_VERS) { 1209 /* 1210 * Enforce range limits on V1 locks 1211 */ 1212 if (start > 0xffffffffLL || len > 0xffffffffLL) 1213 return (EOVERFLOW); 1214 } 1215 1216 snprintf(oh_space, 32, "%d@", svid); 1217 oh_len = strlen(oh_space); 1218 getcredhostname(NULL, oh_space + oh_len, 32 - oh_len); 1219 oh_len = strlen(oh_space); 1220 1221 memset(lock, 0, sizeof(*lock)); 1222 lock->caller_name = prison0.pr_hostname; 1223 lock->fh.n_len = fhlen; 1224 lock->fh.n_bytes = fh; 1225 lock->oh.n_len = oh_len; 1226 lock->oh.n_bytes = oh_space; 1227 lock->svid = svid; 1228 lock->l_offset = start; 1229 lock->l_len = len; 1230 1231 return (0); 1232 } 1233