1 /* 2 * Copyright (c) 1995 3 * The Regents of the University of California. All rights reserved. 4 * Copyright (C) 1997 5 * John S. Dyson. All rights reserved. 6 * Copyright (C) 2013-2017 7 * Matthew Dillon, All rights reserved. 8 * 9 * This code contains ideas from software contributed to Berkeley by 10 * Avadis Tevanian, Jr., Michael Wayne Young, and the Mach Operating 11 * System project at Carnegie-Mellon University. 12 * 13 * This code is derived from software contributed to The DragonFly Project 14 * by Matthew Dillon <dillon@backplane.com>. Extensively rewritten. 15 * 16 * Redistribution and use in source and binary forms, with or without 17 * modification, are permitted provided that the following conditions 18 * are met: 19 * 1. Redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer. 21 * 2. Redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution. 24 * 3. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 */ 40 41 #include "opt_lint.h" 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/kernel.h> 46 #include <sys/proc.h> 47 #include <sys/lock.h> 48 #include <sys/sysctl.h> 49 #include <sys/spinlock.h> 50 #include <sys/spinlock2.h> 51 #include <sys/indefinite2.h> 52 53 static void undo_shreq(struct lock *lkp); 54 static int undo_upreq(struct lock *lkp); 55 static int undo_exreq(struct lock *lkp); 56 57 #ifdef DEBUG_CANCEL_LOCKS 58 59 static int sysctl_cancel_lock(SYSCTL_HANDLER_ARGS); 60 static int sysctl_cancel_test(SYSCTL_HANDLER_ARGS); 61 62 static struct lock cancel_lk; 63 LOCK_SYSINIT(cancellk, &cancel_lk, "cancel", 0); 64 SYSCTL_PROC(_kern, OID_AUTO, cancel_lock, CTLTYPE_INT|CTLFLAG_RW, 0, 0, 65 sysctl_cancel_lock, "I", "test cancelable locks"); 66 SYSCTL_PROC(_kern, OID_AUTO, cancel_test, CTLTYPE_INT|CTLFLAG_RW, 0, 0, 67 sysctl_cancel_test, "I", "test cancelable locks"); 68 69 #endif 70 71 __read_frequently int lock_test_mode; 72 SYSCTL_INT(_debug, OID_AUTO, lock_test_mode, CTLFLAG_RW, 73 &lock_test_mode, 0, ""); 74 75 /* 76 * Locking primitives implementation. 77 * Locks provide shared/exclusive sychronization. 78 */ 79 80 #ifdef DEBUG_LOCKS 81 #define COUNT(td, x) (td)->td_locks += (x) 82 #else 83 #define COUNT(td, x) do { } while (0) 84 #endif 85 86 /* 87 * Helper, assert basic conditions 88 */ 89 static __inline void 90 _lockmgr_assert(struct lock *lkp, u_int flags) 91 { 92 if (mycpu->gd_intr_nesting_level && 93 (flags & LK_NOWAIT) == 0 && 94 (flags & LK_TYPE_MASK) != LK_RELEASE && 95 panic_cpu_gd != mycpu 96 ) { 97 panic("lockmgr %s from %p: called from interrupt, ipi, " 98 "or hard code section", 99 lkp->lk_wmesg, ((int **)&lkp)[-1]); 100 } 101 } 102 103 /* 104 * Acquire a shared lock 105 */ 106 int 107 lockmgr_shared(struct lock *lkp, u_int flags) 108 { 109 uint32_t extflags; 110 thread_t td; 111 uint64_t count; 112 int error; 113 int pflags; 114 int timo; 115 int didloop; 116 117 _lockmgr_assert(lkp, flags); 118 extflags = (flags | lkp->lk_flags) & LK_EXTFLG_MASK; 119 td = curthread; 120 121 count = lkp->lk_count; 122 cpu_ccfence(); 123 124 /* 125 * If the caller already holds the lock exclusively then 126 * we silently obtain another count on the exclusive lock. 127 * Avoid accessing lk_lockholder until testing exclusivity. 128 * 129 * WARNING! The old FreeBSD behavior was to downgrade, 130 * but this creates a problem when recursions 131 * return to the caller and the caller expects 132 * its original exclusive lock to remain exclusively 133 * locked. 134 */ 135 if ((count & LKC_XMASK) && lkp->lk_lockholder == td) { 136 KKASSERT(lkp->lk_count & LKC_XMASK); 137 if ((extflags & LK_CANRECURSE) == 0) { 138 if (extflags & LK_NOWAIT) 139 return EBUSY; 140 panic("lockmgr: locking against myself"); 141 } 142 atomic_add_64(&lkp->lk_count, 1); 143 COUNT(td, 1); 144 return 0; 145 } 146 147 /* 148 * Unless TDF_DEADLKTREAT is set, we cannot add LKC_SCOUNT while 149 * SHARED is set and either EXREQ or UPREQ are set. 150 * 151 * NOTE: In the race-to-0 case (see undo_shreq()), we could 152 * theoretically work the SMASK == 0 case here. 153 */ 154 if ((td->td_flags & TDF_DEADLKTREAT) == 0) { 155 while ((count & LKC_SHARED) && 156 (count & (LKC_EXREQ | LKC_UPREQ))) { 157 /* 158 * Immediate failure conditions 159 */ 160 if (extflags & LK_CANCELABLE) { 161 if (count & LKC_CANCEL) 162 return ENOLCK; 163 } 164 if (extflags & LK_NOWAIT) 165 return EBUSY; 166 167 /* 168 * Interlocked tsleep 169 */ 170 pflags = (extflags & LK_PCATCH) ? PCATCH : 0; 171 timo = (extflags & LK_TIMELOCK) ? lkp->lk_timo : 0; 172 173 tsleep_interlock(lkp, pflags); 174 count = atomic_fetchadd_long(&lkp->lk_count, 0); 175 176 if ((count & LKC_SHARED) && 177 (count & (LKC_EXREQ | LKC_UPREQ))) { 178 error = tsleep(lkp, pflags | PINTERLOCKED, 179 lkp->lk_wmesg, timo); 180 if (error) 181 return error; 182 count = lkp->lk_count; 183 cpu_ccfence(); 184 continue; 185 } 186 break; 187 } 188 } 189 190 /* 191 * Bump the SCOUNT field. The shared lock is granted only once 192 * the SHARED flag gets set. If it is already set, we are done. 193 * 194 * (Racing an EXREQ or UPREQ operation is ok here, we already did 195 * our duty above). 196 */ 197 count = atomic_fetchadd_64(&lkp->lk_count, LKC_SCOUNT) + LKC_SCOUNT; 198 error = 0; 199 didloop = 0; 200 201 for (;;) { 202 /* 203 * We may be able to grant ourselves the bit trivially. 204 * We're done once the SHARED bit is granted. 205 */ 206 if ((count & (LKC_XMASK | LKC_EXREQ | 207 LKC_UPREQ | LKC_SHARED)) == 0) { 208 if (atomic_fcmpset_64(&lkp->lk_count, 209 &count, count | LKC_SHARED)) { 210 /* count |= LKC_SHARED; NOT USED */ 211 break; 212 } 213 continue; 214 } 215 if ((td->td_flags & TDF_DEADLKTREAT) && 216 (count & (LKC_XMASK | LKC_SHARED)) == 0) { 217 if (atomic_fcmpset_64(&lkp->lk_count, 218 &count, count | LKC_SHARED)) { 219 /* count |= LKC_SHARED; NOT USED */ 220 break; 221 } 222 continue; 223 } 224 if (count & LKC_SHARED) 225 break; 226 227 /* 228 * Slow path 229 */ 230 pflags = (extflags & LK_PCATCH) ? PCATCH : 0; 231 timo = (extflags & LK_TIMELOCK) ? lkp->lk_timo : 0; 232 233 if (extflags & LK_CANCELABLE) { 234 if (count & LKC_CANCEL) { 235 undo_shreq(lkp); 236 error = ENOLCK; 237 break; 238 } 239 } 240 if (extflags & LK_NOWAIT) { 241 undo_shreq(lkp); 242 error = EBUSY; 243 break; 244 } 245 246 /* 247 * Interlocked after the first loop. 248 */ 249 if (didloop) { 250 error = tsleep(lkp, pflags | PINTERLOCKED, 251 lkp->lk_wmesg, timo); 252 if (extflags & LK_SLEEPFAIL) { 253 undo_shreq(lkp); 254 error = ENOLCK; 255 break; 256 } 257 if (error) { 258 undo_shreq(lkp); 259 break; 260 } 261 } 262 didloop = 1; 263 264 /* 265 * Reload, shortcut grant case, then loop interlock 266 * and loop. 267 */ 268 count = lkp->lk_count; 269 if (count & LKC_SHARED) 270 break; 271 tsleep_interlock(lkp, pflags); 272 count = atomic_fetchadd_64(&lkp->lk_count, 0); 273 } 274 if (error == 0) 275 COUNT(td, 1); 276 277 return error; 278 } 279 280 /* 281 * Acquire an exclusive lock 282 */ 283 int 284 lockmgr_exclusive(struct lock *lkp, u_int flags) 285 { 286 uint64_t count; 287 uint64_t ncount; 288 uint32_t extflags; 289 thread_t td; 290 int error; 291 int pflags; 292 int timo; 293 294 _lockmgr_assert(lkp, flags); 295 extflags = (flags | lkp->lk_flags) & LK_EXTFLG_MASK; 296 td = curthread; 297 298 error = 0; 299 count = lkp->lk_count; 300 cpu_ccfence(); 301 302 /* 303 * Recursive lock if we already hold it exclusively. Avoid testing 304 * lk_lockholder until after testing lk_count. 305 */ 306 if ((count & LKC_XMASK) && lkp->lk_lockholder == td) { 307 if ((extflags & LK_CANRECURSE) == 0) { 308 if (extflags & LK_NOWAIT) 309 return EBUSY; 310 panic("lockmgr: locking against myself"); 311 } 312 count = atomic_fetchadd_64(&lkp->lk_count, 1) + 1; 313 KKASSERT((count & LKC_XMASK) > 1); 314 COUNT(td, 1); 315 return 0; 316 } 317 318 /* 319 * Trivially acquire the lock, or block until we can set EXREQ. 320 * Set EXREQ2 if EXREQ is already set or the lock is already 321 * held exclusively. EXREQ2 is an aggregation bit to request 322 * a wakeup. 323 * 324 * WARNING! We cannot set EXREQ if the lock is already held 325 * exclusively because it may race another EXREQ 326 * being cleared and granted. We use the exclusivity 327 * to prevent both EXREQ and UPREQ from being set. 328 * 329 * This means that both shared and exclusive requests 330 * have equal priority against a current exclusive holder's 331 * release. Exclusive requests still have priority over 332 * new shared requests when the lock is already held shared. 333 */ 334 for (;;) { 335 /* 336 * Normal trivial case 337 */ 338 if ((count & (LKC_UPREQ | LKC_EXREQ | 339 LKC_XMASK)) == 0 && 340 ((count & LKC_SHARED) == 0 || 341 (count & LKC_SMASK) == 0)) { 342 ncount = (count + 1) & ~LKC_SHARED; 343 if (atomic_fcmpset_64(&lkp->lk_count, 344 &count, ncount)) { 345 lkp->lk_lockholder = td; 346 COUNT(td, 1); 347 return 0; 348 } 349 continue; 350 } 351 352 if (extflags & LK_CANCELABLE) { 353 if (count & LKC_CANCEL) 354 return ENOLCK; 355 } 356 if (extflags & LK_NOWAIT) 357 return EBUSY; 358 359 /* 360 * Interlock to set EXREQ or EXREQ2 361 */ 362 pflags = (extflags & LK_PCATCH) ? PCATCH : 0; 363 timo = (extflags & LK_TIMELOCK) ? lkp->lk_timo : 0; 364 365 if (count & (LKC_EXREQ | LKC_XMASK)) 366 ncount = count | LKC_EXREQ2; 367 else 368 ncount = count | LKC_EXREQ; 369 tsleep_interlock(lkp, pflags); 370 if (atomic_fcmpset_64(&lkp->lk_count, &count, ncount)) { 371 /* 372 * If we successfully transitioned to EXREQ we 373 * can break out, otherwise we had set EXREQ2 and 374 * we block. 375 */ 376 if ((count & (LKC_EXREQ | LKC_XMASK)) == 0) { 377 count = ncount; 378 break; 379 } 380 381 error = tsleep(lkp, pflags | PINTERLOCKED, 382 lkp->lk_wmesg, timo); 383 count = lkp->lk_count; /* relod */ 384 cpu_ccfence(); 385 } 386 #ifdef INVARIANTS 387 if (lock_test_mode > 0) { 388 --lock_test_mode; 389 print_backtrace(8); 390 } 391 #endif 392 if (error) 393 return error; 394 if (extflags & LK_SLEEPFAIL) 395 return ENOLCK; 396 } 397 398 /* 399 * Once EXREQ has been set, wait for it to be granted 400 * We enter the loop with tsleep_interlock() already called. 401 */ 402 for (;;) { 403 /* 404 * Waiting for EXREQ to be granted to us. 405 * 406 * NOTE! If we try to trivially get the exclusive lock 407 * (basically by racing undo_shreq()) and succeed, 408 * we must still wakeup(lkp) for another exclusive 409 * lock trying to acquire EXREQ. Easier to simply 410 * wait for our own wakeup. 411 */ 412 if ((count & LKC_EXREQ) == 0) { 413 KKASSERT(count & LKC_XMASK); 414 lkp->lk_lockholder = td; 415 COUNT(td, 1); 416 break; 417 } 418 419 /* 420 * Block waiting for our exreq to be granted. 421 * Check cancelation. NOWAIT was already dealt with. 422 */ 423 if (extflags & LK_CANCELABLE) { 424 if (count & LKC_CANCEL) { 425 if (undo_exreq(lkp) == 0) { 426 lkp->lk_lockholder = LK_KERNTHREAD; 427 lockmgr_release(lkp, 0); 428 } 429 error = ENOLCK; 430 break; 431 } 432 } 433 434 pflags = (extflags & LK_PCATCH) ? PCATCH : 0; 435 timo = (extflags & LK_TIMELOCK) ? lkp->lk_timo : 0; 436 437 error = tsleep(lkp, pflags | PINTERLOCKED, lkp->lk_wmesg, timo); 438 #ifdef INVARIANTS 439 if (lock_test_mode > 0) { 440 --lock_test_mode; 441 print_backtrace(8); 442 } 443 #endif 444 /* 445 * A tsleep error is uncommon. If it occurs we have to 446 * undo our EXREQ. If we are granted the exclusive lock 447 * as we try to undo we have to deal with it. 448 */ 449 if (extflags & LK_SLEEPFAIL) { 450 if (undo_exreq(lkp) == 0) { 451 lkp->lk_lockholder = LK_KERNTHREAD; 452 lockmgr_release(lkp, 0); 453 } 454 if (error == 0) 455 error = ENOLCK; 456 break; 457 } 458 if (error) { 459 if (undo_exreq(lkp)) 460 break; 461 lkp->lk_lockholder = td; 462 COUNT(td, 1); 463 error = 0; 464 break; 465 } 466 467 /* 468 * Reload after sleep, shortcut grant case. 469 * Then set the interlock and loop. 470 */ 471 count = lkp->lk_count; 472 cpu_ccfence(); 473 if ((count & LKC_EXREQ) == 0) { 474 KKASSERT(count & LKC_XMASK); 475 lkp->lk_lockholder = td; 476 COUNT(td, 1); 477 break; 478 } 479 tsleep_interlock(lkp, pflags); 480 count = atomic_fetchadd_64(&lkp->lk_count, 0); 481 } 482 return error; 483 } 484 485 /* 486 * Downgrade an exclusive lock to shared. 487 * 488 * This function always succeeds as long as the caller owns a legal 489 * exclusive lock with one reference. UPREQ and EXREQ is ignored. 490 */ 491 int 492 lockmgr_downgrade(struct lock *lkp, u_int flags) 493 { 494 uint64_t count; 495 uint64_t ncount; 496 uint32_t extflags; 497 thread_t otd; 498 thread_t td; 499 500 extflags = (flags | lkp->lk_flags) & LK_EXTFLG_MASK; 501 td = curthread; 502 count = lkp->lk_count; 503 504 for (;;) { 505 cpu_ccfence(); 506 507 /* 508 * Downgrade an exclusive lock into a shared lock. All 509 * counts on a recursive exclusive lock become shared. 510 * 511 * NOTE: Currently to reduce confusion we only allow 512 * there to be one exclusive lock count, and panic 513 * if there are more. 514 */ 515 if (lkp->lk_lockholder != td || (count & LKC_XMASK) != 1) { 516 panic("lockmgr: not holding exclusive lock: " 517 "%p/%p %016jx", lkp->lk_lockholder, td, count); 518 } 519 520 /* 521 * NOTE! Must NULL-out lockholder before releasing the 522 * exclusive lock. 523 * 524 * NOTE! There might be pending shared requests, check 525 * and wake them up. 526 */ 527 otd = lkp->lk_lockholder; 528 lkp->lk_lockholder = NULL; 529 ncount = (count & ~(LKC_XMASK | LKC_EXREQ2)) + 530 ((count & LKC_XMASK) << LKC_SSHIFT); 531 ncount |= LKC_SHARED; 532 533 if (atomic_fcmpset_64(&lkp->lk_count, &count, ncount)) { 534 /* 535 * Wakeup any shared waiters (prior SMASK), or 536 * any exclusive requests that couldn't set EXREQ 537 * because the lock had been held exclusively. 538 */ 539 if (count & (LKC_SMASK | LKC_EXREQ2)) 540 wakeup(lkp); 541 /* count = ncount; NOT USED */ 542 break; 543 } 544 lkp->lk_lockholder = otd; 545 /* retry */ 546 } 547 return 0; 548 } 549 550 /* 551 * Upgrade a shared lock to exclusive. If LK_EXCLUPGRADE then guarantee 552 * that no other exclusive requester can get in front of us and fail 553 * immediately if another upgrade is pending. If we fail, the shared 554 * lock is released. 555 * 556 * If LK_EXCLUPGRADE is not set and we cannot upgrade because someone 557 * else is in front of us, we release the shared lock and acquire the 558 * exclusive lock normally. If a failure occurs, the shared lock is 559 * released. 560 */ 561 int 562 lockmgr_upgrade(struct lock *lkp, u_int flags) 563 { 564 uint64_t count; 565 uint64_t ncount; 566 uint32_t extflags; 567 thread_t td; 568 int error; 569 int pflags; 570 int timo; 571 572 _lockmgr_assert(lkp, flags); 573 extflags = (flags | lkp->lk_flags) & LK_EXTFLG_MASK; 574 td = curthread; 575 error = 0; 576 count = lkp->lk_count; 577 cpu_ccfence(); 578 579 /* 580 * If we already hold the lock exclusively this operation 581 * succeeds and is a NOP. 582 */ 583 if (count & LKC_XMASK) { 584 if (lkp->lk_lockholder == td) 585 return 0; 586 panic("lockmgr: upgrade unowned lock"); 587 } 588 if ((count & LKC_SMASK) == 0) 589 panic("lockmgr: upgrade unowned lock"); 590 591 /* 592 * Loop to acquire LKC_UPREQ 593 */ 594 for (;;) { 595 /* 596 * If UPREQ is already pending, release the shared lock 597 * and acquire an exclusive lock normally. 598 * 599 * If NOWAIT or EXCLUPGRADE the operation must be atomic, 600 * and this isn't, so we fail. 601 */ 602 if (count & LKC_UPREQ) { 603 lockmgr_release(lkp, 0); 604 if ((flags & LK_TYPE_MASK) == LK_EXCLUPGRADE) 605 error = EBUSY; 606 else if (extflags & LK_NOWAIT) 607 error = EBUSY; 608 else 609 error = lockmgr_exclusive(lkp, flags); 610 return error; 611 } 612 613 /* 614 * Try to immediately grant the upgrade, handle NOWAIT, 615 * or release the shared lock and simultaneously set UPREQ. 616 */ 617 if ((count & LKC_SMASK) == LKC_SCOUNT) { 618 /* 619 * Immediate grant 620 */ 621 ncount = (count - LKC_SCOUNT + 1) & ~LKC_SHARED; 622 if (atomic_fcmpset_64(&lkp->lk_count, &count, ncount)) { 623 lkp->lk_lockholder = td; 624 return 0; 625 } 626 } else if (extflags & LK_NOWAIT) { 627 /* 628 * Early EBUSY if an immediate grant is impossible 629 */ 630 lockmgr_release(lkp, 0); 631 return EBUSY; 632 } else { 633 /* 634 * Multiple shared locks present, request the 635 * upgrade and break to the next loop. 636 */ 637 pflags = (extflags & LK_PCATCH) ? PCATCH : 0; 638 tsleep_interlock(lkp, pflags); 639 ncount = (count - LKC_SCOUNT) | LKC_UPREQ; 640 if (atomic_fcmpset_64(&lkp->lk_count, &count, ncount)) { 641 count = ncount; 642 break; 643 } 644 } 645 /* retry */ 646 } 647 648 /* 649 * We have acquired LKC_UPREQ, wait until the upgrade is granted 650 * or the tsleep fails. 651 * 652 * NOWAIT and EXCLUPGRADE have already been handled. The first 653 * tsleep_interlock() has already been associated. 654 */ 655 for (;;) { 656 cpu_ccfence(); 657 658 /* 659 * We were granted our upgrade. No other UPREQ can be 660 * made pending because we are now exclusive. 661 */ 662 if ((count & LKC_UPREQ) == 0) { 663 KKASSERT((count & LKC_XMASK) == 1); 664 lkp->lk_lockholder = td; 665 break; 666 } 667 668 if (extflags & LK_CANCELABLE) { 669 if (count & LKC_CANCEL) { 670 if (undo_upreq(lkp) == 0) { 671 lkp->lk_lockholder = LK_KERNTHREAD; 672 lockmgr_release(lkp, 0); 673 } 674 error = ENOLCK; 675 break; 676 } 677 } 678 679 pflags = (extflags & LK_PCATCH) ? PCATCH : 0; 680 timo = (extflags & LK_TIMELOCK) ? lkp->lk_timo : 0; 681 682 error = tsleep(lkp, pflags | PINTERLOCKED, lkp->lk_wmesg, timo); 683 if (extflags & LK_SLEEPFAIL) { 684 if (undo_upreq(lkp) == 0) { 685 lkp->lk_lockholder = LK_KERNTHREAD; 686 lockmgr_release(lkp, 0); 687 } 688 if (error == 0) 689 error = ENOLCK; 690 break; 691 } 692 if (error) { 693 if (undo_upreq(lkp)) 694 break; 695 error = 0; 696 } 697 698 /* 699 * Reload the lock, short-cut the UPGRANT code before 700 * taking the time to interlock and loop. 701 */ 702 count = lkp->lk_count; 703 if ((count & LKC_UPREQ) == 0) { 704 KKASSERT((count & LKC_XMASK) == 1); 705 lkp->lk_lockholder = td; 706 break; 707 } 708 tsleep_interlock(lkp, pflags); 709 count = atomic_fetchadd_64(&lkp->lk_count, 0); 710 /* retry */ 711 } 712 return error; 713 } 714 715 /* 716 * Release a held lock 717 * 718 * NOTE: When releasing to an unlocked state, we set the SHARED bit 719 * to optimize shared lock requests. 720 */ 721 int 722 lockmgr_release(struct lock *lkp, u_int flags) 723 { 724 uint64_t count; 725 uint64_t ncount; 726 uint32_t extflags; 727 thread_t otd; 728 thread_t td; 729 730 extflags = (flags | lkp->lk_flags) & LK_EXTFLG_MASK; 731 td = curthread; 732 733 count = lkp->lk_count; 734 cpu_ccfence(); 735 736 for (;;) { 737 /* 738 * Release the currently held lock, grant all requests 739 * possible. 740 * 741 * WARNING! lksleep() assumes that LK_RELEASE does not 742 * block. 743 * 744 * Always succeeds. 745 * Never blocks. 746 */ 747 if ((count & (LKC_SMASK | LKC_XMASK)) == 0) 748 panic("lockmgr: LK_RELEASE: no lock held"); 749 750 if (count & LKC_XMASK) { 751 /* 752 * Release exclusively held lock 753 */ 754 if (lkp->lk_lockholder != LK_KERNTHREAD && 755 lkp->lk_lockholder != td) { 756 panic("lockmgr: pid %d, not exclusive " 757 "lock holder thr %p/%p unlocking", 758 (td->td_proc ? td->td_proc->p_pid : -1), 759 td, lkp->lk_lockholder); 760 } 761 if ((count & (LKC_UPREQ | LKC_EXREQ | 762 LKC_XMASK)) == 1) { 763 /* 764 * Last exclusive count is being released 765 * with no UPREQ or EXREQ. The SHARED 766 * bit can be set or not without messing 767 * anything up, so precondition it to 768 * SHARED (which is the most cpu-optimal). 769 * 770 * Wakeup any EXREQ2. EXREQ cannot be 771 * set while an exclusive count is present 772 * so we have to wakeup any EXREQ2 we find. 773 * 774 * We could hint the EXREQ2 by leaving 775 * SHARED unset, but atm I don't see any 776 * usefulness. 777 */ 778 otd = lkp->lk_lockholder; 779 lkp->lk_lockholder = NULL; 780 ncount = (count - 1); 781 ncount &= ~(LKC_CANCEL | LKC_EXREQ2); 782 ncount |= LKC_SHARED; 783 if (atomic_fcmpset_64(&lkp->lk_count, 784 &count, ncount)) { 785 if (count & (LKC_SMASK | LKC_EXREQ2)) 786 wakeup(lkp); 787 if (otd != LK_KERNTHREAD) 788 COUNT(td, -1); 789 /* count = ncount; NOT USED */ 790 break; 791 } 792 lkp->lk_lockholder = otd; 793 /* retry */ 794 } else if ((count & (LKC_UPREQ | LKC_XMASK)) == 795 (LKC_UPREQ | 1)) { 796 /* 797 * Last exclusive count is being released but 798 * an upgrade request is present, automatically 799 * grant an exclusive state to the owner of 800 * the upgrade request. Transfer count to 801 * grant. 802 * 803 * EXREQ cannot be set while an exclusive 804 * holder exists, so do not clear EXREQ2. 805 */ 806 otd = lkp->lk_lockholder; 807 lkp->lk_lockholder = NULL; 808 ncount = count & ~LKC_UPREQ; 809 if (atomic_fcmpset_64(&lkp->lk_count, 810 &count, ncount)) { 811 wakeup(lkp); 812 if (otd != LK_KERNTHREAD) 813 COUNT(td, -1); 814 /* count = ncount; NOT USED */ 815 break; 816 } 817 lkp->lk_lockholder = otd; 818 /* retry */ 819 } else if ((count & (LKC_EXREQ | LKC_XMASK)) == 820 (LKC_EXREQ | 1)) { 821 /* 822 * Last exclusive count is being released but 823 * an exclusive request is present. We 824 * automatically grant an exclusive state to 825 * the owner of the exclusive request, 826 * transfering our count. 827 * 828 * This case virtually never occurs because 829 * EXREQ is not set while exclusive holders 830 * exist. However, it might be set if a 831 * an exclusive request is pending and a 832 * shared holder upgrades. 833 * 834 * Don't bother clearing EXREQ2. A thread 835 * waiting to set EXREQ can't do it while 836 * an exclusive lock is present. 837 */ 838 otd = lkp->lk_lockholder; 839 lkp->lk_lockholder = NULL; 840 ncount = count & ~LKC_EXREQ; 841 if (atomic_fcmpset_64(&lkp->lk_count, 842 &count, ncount)) { 843 wakeup(lkp); 844 if (otd != LK_KERNTHREAD) 845 COUNT(td, -1); 846 /* count = ncount; NOT USED */ 847 break; 848 } 849 lkp->lk_lockholder = otd; 850 /* retry */ 851 } else { 852 /* 853 * Multiple exclusive counts, drop by 1. 854 * Since we are the holder and there is more 855 * than one count, we can just decrement it. 856 */ 857 count = 858 atomic_fetchadd_long(&lkp->lk_count, -1); 859 /* count = count - 1 NOT NEEDED */ 860 if (lkp->lk_lockholder != LK_KERNTHREAD) 861 COUNT(td, -1); 862 break; 863 } 864 /* retry */ 865 } else { 866 /* 867 * Release shared lock 868 */ 869 KKASSERT((count & LKC_SHARED) && (count & LKC_SMASK)); 870 if ((count & (LKC_EXREQ | LKC_UPREQ | LKC_SMASK)) == 871 LKC_SCOUNT) { 872 /* 873 * Last shared count is being released, 874 * no exclusive or upgrade request present. 875 * Generally leave the shared bit set. 876 * Clear the CANCEL bit. 877 */ 878 ncount = (count - LKC_SCOUNT) & ~LKC_CANCEL; 879 if (atomic_fcmpset_64(&lkp->lk_count, 880 &count, ncount)) { 881 COUNT(td, -1); 882 /* count = ncount; NOT USED */ 883 break; 884 } 885 /* retry */ 886 } else if ((count & (LKC_UPREQ | LKC_SMASK)) == 887 (LKC_UPREQ | LKC_SCOUNT)) { 888 /* 889 * Last shared count is being released but 890 * an upgrade request is present, automatically 891 * grant an exclusive state to the owner of 892 * the upgrade request and transfer the count. 893 */ 894 ncount = (count - LKC_SCOUNT + 1) & 895 ~(LKC_UPREQ | LKC_CANCEL | LKC_SHARED); 896 if (atomic_fcmpset_64(&lkp->lk_count, 897 &count, ncount)) { 898 wakeup(lkp); 899 COUNT(td, -1); 900 /* count = ncount; NOT USED */ 901 break; 902 } 903 /* retry */ 904 } else if ((count & (LKC_EXREQ | LKC_SMASK)) == 905 (LKC_EXREQ | LKC_SCOUNT)) { 906 /* 907 * Last shared count is being released but 908 * an exclusive request is present, we 909 * automatically grant an exclusive state to 910 * the owner of the request and transfer 911 * the count. 912 */ 913 ncount = (count - LKC_SCOUNT + 1) & 914 ~(LKC_EXREQ | LKC_EXREQ2 | 915 LKC_CANCEL | LKC_SHARED); 916 if (atomic_fcmpset_64(&lkp->lk_count, 917 &count, ncount)) { 918 wakeup(lkp); 919 COUNT(td, -1); 920 /* count = ncount; NOT USED */ 921 break; 922 } 923 /* retry */ 924 } else { 925 /* 926 * Shared count is greater than 1. We can 927 * just use undo_shreq() to clean things up. 928 * undo_shreq() will also handle races to 0 929 * after the fact. 930 */ 931 undo_shreq(lkp); 932 COUNT(td, -1); 933 break; 934 } 935 /* retry */ 936 } 937 /* retry */ 938 } 939 return 0; 940 } 941 942 /* 943 * Start canceling blocked requesters or later requestors. 944 * Only blocked requesters using CANCELABLE can be canceled. 945 * 946 * This is intended to then allow other requesters (usually the 947 * caller) to obtain a non-cancelable lock. 948 * 949 * Don't waste time issuing a wakeup if nobody is pending. 950 */ 951 int 952 lockmgr_cancel_beg(struct lock *lkp, u_int flags) 953 { 954 uint64_t count; 955 956 count = lkp->lk_count; 957 for (;;) { 958 cpu_ccfence(); 959 960 KKASSERT((count & LKC_CANCEL) == 0); /* disallowed case */ 961 962 /* issue w/lock held */ 963 KKASSERT((count & (LKC_XMASK | LKC_SMASK)) != 0); 964 965 if (!atomic_fcmpset_64(&lkp->lk_count, 966 &count, count | LKC_CANCEL)) { 967 continue; 968 } 969 /* count |= LKC_CANCEL; NOT USED */ 970 971 /* 972 * Wakeup any waiters. 973 * 974 * NOTE: EXREQ2 only matters when EXREQ is set, so don't 975 * bother checking EXREQ2. 976 */ 977 if (count & (LKC_EXREQ | LKC_SMASK | LKC_UPREQ)) { 978 wakeup(lkp); 979 } 980 break; 981 } 982 return 0; 983 } 984 985 /* 986 * End our cancel request (typically after we have acquired 987 * the lock ourselves). 988 */ 989 int 990 lockmgr_cancel_end(struct lock *lkp, u_int flags) 991 { 992 atomic_clear_long(&lkp->lk_count, LKC_CANCEL); 993 994 return 0; 995 } 996 997 /* 998 * Backout SCOUNT from a failed shared lock attempt and handle any race 999 * to 0. This function is also used by the release code for the less 1000 * optimal race to 0 case. 1001 * 1002 * WARNING! Since we are unconditionally decrementing LKC_SCOUNT, it is 1003 * possible for the lock to get into a LKC_SHARED + ZERO SCOUNT 1004 * situation. A shared request can block with a ZERO SCOUNT if 1005 * EXREQ or UPREQ is pending in this situation. Be sure to always 1006 * issue a wakeup() in this situation if we are unable to 1007 * transition to an exclusive lock, to handle the race. 1008 * 1009 * Always succeeds 1010 * Must not block 1011 */ 1012 static void 1013 undo_shreq(struct lock *lkp) 1014 { 1015 uint64_t count; 1016 uint64_t ncount; 1017 1018 count = atomic_fetchadd_64(&lkp->lk_count, -LKC_SCOUNT) - LKC_SCOUNT; 1019 while ((count & (LKC_EXREQ | LKC_UPREQ | LKC_CANCEL)) && 1020 (count & (LKC_SMASK | LKC_XMASK)) == 0) { 1021 /* 1022 * Note that UPREQ must have priority over EXREQ, and EXREQ 1023 * over CANCEL, so if the atomic op fails we have to loop up. 1024 */ 1025 if (count & LKC_UPREQ) { 1026 ncount = (count + 1) & ~(LKC_UPREQ | LKC_CANCEL | 1027 LKC_SHARED); 1028 if (atomic_fcmpset_64(&lkp->lk_count, &count, ncount)) { 1029 wakeup(lkp); 1030 /* count = ncount; NOT USED */ 1031 break; 1032 } 1033 wakeup(lkp); 1034 continue; 1035 } 1036 if (count & LKC_EXREQ) { 1037 ncount = (count + 1) & ~(LKC_EXREQ | LKC_EXREQ2 | 1038 LKC_CANCEL | LKC_SHARED); 1039 if (atomic_fcmpset_64(&lkp->lk_count, &count, ncount)) { 1040 wakeup(lkp); 1041 /* count = ncount; NOT USED */ 1042 break; 1043 } 1044 wakeup(lkp); 1045 continue; 1046 } 1047 if (count & LKC_CANCEL) { 1048 ncount = count & ~LKC_CANCEL; 1049 if (atomic_fcmpset_64(&lkp->lk_count, &count, ncount)) { 1050 wakeup(lkp); 1051 /* count = ncount; NOT USED */ 1052 break; 1053 } 1054 } 1055 /* retry */ 1056 } 1057 } 1058 1059 /* 1060 * Undo an exclusive request. Returns EBUSY if we were able to undo the 1061 * request, and 0 if the request was granted before we could undo it. 1062 * When 0 is returned, the lock state has not been modified. The caller 1063 * is responsible for setting the lockholder to curthread. 1064 */ 1065 static 1066 int 1067 undo_exreq(struct lock *lkp) 1068 { 1069 uint64_t count; 1070 uint64_t ncount; 1071 int error; 1072 1073 count = lkp->lk_count; 1074 error = 0; 1075 1076 for (;;) { 1077 cpu_ccfence(); 1078 1079 if ((count & LKC_EXREQ) == 0) { 1080 /* 1081 * EXREQ was granted. We own the exclusive lock. 1082 */ 1083 break; 1084 } 1085 if (count & LKC_XMASK) { 1086 /* 1087 * Clear the EXREQ we still own. Only wakeup on 1088 * EXREQ2 if no UPREQ. There are still exclusive 1089 * holders so do not wake up any shared locks or 1090 * any UPREQ. 1091 * 1092 * If there is an UPREQ it will issue a wakeup() 1093 * for any EXREQ wait looops, so we can clear EXREQ2 1094 * now. 1095 */ 1096 ncount = count & ~(LKC_EXREQ | LKC_EXREQ2); 1097 if (atomic_fcmpset_64(&lkp->lk_count, &count, ncount)) { 1098 if ((count & (LKC_EXREQ2 | LKC_UPREQ)) == 1099 LKC_EXREQ2) { 1100 wakeup(lkp); 1101 } 1102 error = EBUSY; 1103 /* count = ncount; NOT USED */ 1104 break; 1105 } 1106 /* retry */ 1107 } else if (count & LKC_UPREQ) { 1108 /* 1109 * Clear the EXREQ we still own. We cannot wakeup any 1110 * shared or exclusive waiters because there is an 1111 * uprequest pending (that we do not handle here). 1112 * 1113 * If there is an UPREQ it will issue a wakeup() 1114 * for any EXREQ wait looops, so we can clear EXREQ2 1115 * now. 1116 */ 1117 ncount = count & ~(LKC_EXREQ | LKC_EXREQ2); 1118 if (atomic_fcmpset_64(&lkp->lk_count, &count, ncount)) { 1119 error = EBUSY; 1120 break; 1121 } 1122 /* retry */ 1123 } else if ((count & LKC_SHARED) && (count & LKC_SMASK)) { 1124 /* 1125 * No UPREQ, lock not held exclusively, but the lock 1126 * is held shared. Clear EXREQ, wakeup anyone trying 1127 * to get the EXREQ bit (they have to set it 1128 * themselves, EXREQ2 is an aggregation). 1129 * 1130 * We must also wakeup any shared locks blocked 1131 * by the EXREQ, so just issue the wakeup 1132 * unconditionally. See lockmgr_shared() + 76 lines 1133 * or so. 1134 */ 1135 ncount = count & ~(LKC_EXREQ | LKC_EXREQ2); 1136 if (atomic_fcmpset_64(&lkp->lk_count, &count, ncount)) { 1137 wakeup(lkp); 1138 error = EBUSY; 1139 /* count = ncount; NOT USED */ 1140 break; 1141 } 1142 /* retry */ 1143 } else { 1144 /* 1145 * No UPREQ, lock not held exclusively or shared. 1146 * Grant the EXREQ and wakeup anyone waiting on 1147 * EXREQ2. 1148 * 1149 * We must also issue a wakeup if SHARED is set, 1150 * even without an SCOUNT, due to pre-shared blocking 1151 * that can occur on EXREQ in lockmgr_shared(). 1152 */ 1153 ncount = (count + 1) & ~(LKC_EXREQ | LKC_EXREQ2); 1154 if (atomic_fcmpset_64(&lkp->lk_count, &count, ncount)) { 1155 if (count & (LKC_EXREQ2 | LKC_SHARED)) 1156 wakeup(lkp); 1157 /* count = ncount; NOT USED */ 1158 /* we are granting, error == 0 */ 1159 break; 1160 } 1161 /* retry */ 1162 } 1163 /* retry */ 1164 } 1165 return error; 1166 } 1167 1168 /* 1169 * Undo an upgrade request. Returns EBUSY if we were able to undo the 1170 * request, and 0 if the request was granted before we could undo it. 1171 * When 0 is returned, the lock state has not been modified. The caller 1172 * is responsible for setting the lockholder to curthread. 1173 */ 1174 static 1175 int 1176 undo_upreq(struct lock *lkp) 1177 { 1178 uint64_t count; 1179 uint64_t ncount; 1180 int error; 1181 1182 count = lkp->lk_count; 1183 error = 0; 1184 1185 for (;;) { 1186 cpu_ccfence(); 1187 1188 if ((count & LKC_UPREQ) == 0) { 1189 /* 1190 * UPREQ was granted 1191 */ 1192 break; 1193 } 1194 if (count & LKC_XMASK) { 1195 /* 1196 * Clear the UPREQ we still own. Nobody to wakeup 1197 * here because there is an existing exclusive 1198 * holder. 1199 */ 1200 if (atomic_fcmpset_64(&lkp->lk_count, &count, 1201 count & ~LKC_UPREQ)) { 1202 error = EBUSY; 1203 /* count &= ~LKC_UPREQ; NOT USED */ 1204 break; 1205 } 1206 } else if (count & LKC_EXREQ) { 1207 /* 1208 * Clear the UPREQ we still own. Grant the exclusive 1209 * request and wake it up. 1210 */ 1211 ncount = (count + 1); 1212 ncount &= ~(LKC_EXREQ | LKC_EXREQ2 | LKC_UPREQ); 1213 1214 if (atomic_fcmpset_64(&lkp->lk_count, &count, ncount)) { 1215 wakeup(lkp); 1216 error = EBUSY; 1217 /* count = ncount; NOT USED */ 1218 break; 1219 } 1220 } else { 1221 /* 1222 * Clear the UPREQ we still own. Wakeup any shared 1223 * waiters. 1224 * 1225 * We must also issue a wakeup if SHARED was set 1226 * even if no shared waiters due to pre-shared blocking 1227 * that can occur on UPREQ. 1228 */ 1229 ncount = count & ~LKC_UPREQ; 1230 if (count & LKC_SMASK) 1231 ncount |= LKC_SHARED; 1232 1233 if (atomic_fcmpset_64(&lkp->lk_count, &count, ncount)) { 1234 if ((count & LKC_SHARED) || 1235 (ncount & LKC_SHARED)) { 1236 wakeup(lkp); 1237 } 1238 error = EBUSY; 1239 /* count = ncount; NOT USED */ 1240 break; 1241 } 1242 } 1243 /* retry */ 1244 } 1245 return error; 1246 } 1247 1248 void 1249 lockmgr_kernproc(struct lock *lp) 1250 { 1251 struct thread *td __debugvar = curthread; 1252 1253 if (lp->lk_lockholder != LK_KERNTHREAD) { 1254 KASSERT(lp->lk_lockholder == td, 1255 ("lockmgr_kernproc: lock not owned by curthread %p: %p", 1256 td, lp->lk_lockholder)); 1257 lp->lk_lockholder = LK_KERNTHREAD; 1258 COUNT(td, -1); 1259 } 1260 } 1261 1262 /* 1263 * Initialize a lock; required before use. 1264 */ 1265 void 1266 lockinit(struct lock *lkp, const char *wmesg, int timo, int flags) 1267 { 1268 lkp->lk_flags = (flags & LK_EXTFLG_MASK); 1269 lkp->lk_count = 0; 1270 lkp->lk_wmesg = wmesg; 1271 lkp->lk_timo = timo; 1272 lkp->lk_lockholder = NULL; 1273 } 1274 1275 /* 1276 * Reinitialize a lock that is being reused for a different purpose, but 1277 * which may have pending (blocked) threads sitting on it. The caller 1278 * must already hold the interlock. 1279 */ 1280 void 1281 lockreinit(struct lock *lkp, const char *wmesg, int timo, int flags) 1282 { 1283 lkp->lk_wmesg = wmesg; 1284 lkp->lk_timo = timo; 1285 } 1286 1287 /* 1288 * De-initialize a lock. The structure must no longer be used by anyone. 1289 */ 1290 void 1291 lockuninit(struct lock *lkp) 1292 { 1293 uint64_t count __unused; 1294 1295 count = lkp->lk_count; 1296 cpu_ccfence(); 1297 KKASSERT((count & (LKC_EXREQ | LKC_UPREQ)) == 0 && 1298 ((count & LKC_SHARED) || (count & LKC_SMASK) == 0)); 1299 } 1300 1301 /* 1302 * Determine the status of a lock. 1303 */ 1304 int 1305 lockstatus(struct lock *lkp, struct thread *td) 1306 { 1307 int lock_type = 0; 1308 uint64_t count; 1309 1310 count = lkp->lk_count; 1311 cpu_ccfence(); 1312 1313 if (count & (LKC_XMASK | LKC_SMASK | LKC_EXREQ | LKC_UPREQ)) { 1314 if (count & LKC_XMASK) { 1315 if (td == NULL || lkp->lk_lockholder == td) 1316 lock_type = LK_EXCLUSIVE; 1317 else 1318 lock_type = LK_EXCLOTHER; 1319 } else if ((count & LKC_SMASK) && (count & LKC_SHARED)) { 1320 lock_type = LK_SHARED; 1321 } 1322 } 1323 return (lock_type); 1324 } 1325 1326 /* 1327 * Return non-zero if the caller owns the lock shared or exclusive. 1328 * We can only guess re: shared locks. 1329 */ 1330 int 1331 lockowned(struct lock *lkp) 1332 { 1333 thread_t td = curthread; 1334 uint64_t count; 1335 1336 count = lkp->lk_count; 1337 cpu_ccfence(); 1338 1339 if (count & LKC_XMASK) 1340 return(lkp->lk_lockholder == td); 1341 else 1342 return((count & LKC_SMASK) != 0); 1343 } 1344 1345 #if 0 1346 /* 1347 * Determine the number of holders of a lock. 1348 * 1349 * REMOVED - Cannot be used due to our use of atomic_fetchadd_64() 1350 * for shared locks. Caller can only test if the lock has 1351 * a count or not using lockinuse(lk) (sys/lock.h) 1352 */ 1353 int 1354 lockcount(struct lock *lkp) 1355 { 1356 panic("lockcount cannot be used"); 1357 } 1358 1359 int 1360 lockcountnb(struct lock *lkp) 1361 { 1362 panic("lockcount cannot be used"); 1363 } 1364 #endif 1365 1366 /* 1367 * Print out information about state of a lock. Used by VOP_PRINT 1368 * routines to display status about contained locks. 1369 */ 1370 void 1371 lockmgr_printinfo(struct lock *lkp) 1372 { 1373 struct thread *td = lkp->lk_lockholder; 1374 struct proc *p; 1375 uint64_t count; 1376 1377 count = lkp->lk_count; 1378 cpu_ccfence(); 1379 1380 if (td && td != LK_KERNTHREAD) 1381 p = td->td_proc; 1382 else 1383 p = NULL; 1384 1385 if (count & LKC_XMASK) { 1386 kprintf(" lock type %s: EXCLUS (count %016jx) by td %p pid %d", 1387 lkp->lk_wmesg, (intmax_t)count, td, 1388 p ? p->p_pid : -99); 1389 } else if ((count & LKC_SMASK) && (count & LKC_SHARED)) { 1390 kprintf(" lock type %s: SHARED (count %016jx)", 1391 lkp->lk_wmesg, (intmax_t)count); 1392 } else { 1393 kprintf(" lock type %s: NOTHELD", lkp->lk_wmesg); 1394 } 1395 if ((count & (LKC_EXREQ | LKC_UPREQ)) || 1396 ((count & LKC_XMASK) && (count & LKC_SMASK))) 1397 kprintf(" with waiters\n"); 1398 else 1399 kprintf("\n"); 1400 } 1401 1402 void 1403 lock_sysinit(struct lock_args *arg) 1404 { 1405 lockinit(arg->la_lock, arg->la_desc, 0, arg->la_flags); 1406 } 1407 1408 #ifdef DEBUG_CANCEL_LOCKS 1409 1410 static 1411 int 1412 sysctl_cancel_lock(SYSCTL_HANDLER_ARGS) 1413 { 1414 int error; 1415 1416 if (req->newptr) { 1417 SYSCTL_XUNLOCK(); 1418 lockmgr(&cancel_lk, LK_EXCLUSIVE); 1419 error = tsleep(&error, PCATCH, "canmas", hz * 5); 1420 lockmgr(&cancel_lk, LK_CANCEL_BEG); 1421 error = tsleep(&error, PCATCH, "canmas", hz * 5); 1422 lockmgr(&cancel_lk, LK_RELEASE); 1423 SYSCTL_XLOCK(); 1424 SYSCTL_OUT(req, &error, sizeof(error)); 1425 } 1426 error = 0; 1427 1428 return error; 1429 } 1430 1431 static 1432 int 1433 sysctl_cancel_test(SYSCTL_HANDLER_ARGS) 1434 { 1435 int error; 1436 1437 if (req->newptr) { 1438 error = lockmgr(&cancel_lk, LK_EXCLUSIVE|LK_CANCELABLE); 1439 if (error == 0) 1440 lockmgr(&cancel_lk, LK_RELEASE); 1441 SYSCTL_OUT(req, &error, sizeof(error)); 1442 kprintf("test %d\n", error); 1443 } 1444 1445 return 0; 1446 } 1447 1448 #endif 1449