18f0e9130SKonstantin Belousov /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 38a36da99SPedro F. Giffuni * 48f0e9130SKonstantin Belousov * Copyright (c) 2009 Konstantin Belousov <kib@FreeBSD.org> 5*d8a16b6aSKonstantin Belousov * Copyright (c) 2023 The FreeBSD Foundation 6*d8a16b6aSKonstantin Belousov * 7*d8a16b6aSKonstantin Belousov * Portions of this software were developed by 8*d8a16b6aSKonstantin Belousov * Konstantin Belousov <kib@FreeBSD.org> under sponsorship from 9*d8a16b6aSKonstantin Belousov * the FreeBSD Foundation. 108f0e9130SKonstantin Belousov * 118f0e9130SKonstantin Belousov * Redistribution and use in source and binary forms, with or without 128f0e9130SKonstantin Belousov * modification, are permitted provided that the following conditions 138f0e9130SKonstantin Belousov * are met: 148f0e9130SKonstantin Belousov * 1. Redistributions of source code must retain the above copyright 158f0e9130SKonstantin Belousov * notice unmodified, this list of conditions, and the following 168f0e9130SKonstantin Belousov * disclaimer. 178f0e9130SKonstantin Belousov * 2. Redistributions in binary form must reproduce the above copyright 188f0e9130SKonstantin Belousov * notice, this list of conditions and the following disclaimer in the 198f0e9130SKonstantin Belousov * documentation and/or other materials provided with the distribution. 208f0e9130SKonstantin Belousov * 218f0e9130SKonstantin Belousov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 228f0e9130SKonstantin Belousov * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 238f0e9130SKonstantin Belousov * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 248f0e9130SKonstantin Belousov * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 258f0e9130SKonstantin Belousov * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 268f0e9130SKonstantin Belousov * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 278f0e9130SKonstantin Belousov * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 288f0e9130SKonstantin Belousov * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 298f0e9130SKonstantin Belousov * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 308f0e9130SKonstantin Belousov * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 318f0e9130SKonstantin Belousov */ 328f0e9130SKonstantin Belousov 338f0e9130SKonstantin Belousov #include <sys/param.h> 34c3d8a931SKonstantin Belousov #include <sys/kassert.h> 358f0e9130SKonstantin Belousov #include <sys/kernel.h> 368f0e9130SKonstantin Belousov #include <sys/lock.h> 378f0e9130SKonstantin Belousov #include <sys/mutex.h> 388f0e9130SKonstantin Belousov #include <sys/proc.h> 398f0e9130SKonstantin Belousov #include <sys/rangelock.h> 40c3d8a931SKonstantin Belousov #include <sys/sleepqueue.h> 41c3d8a931SKonstantin Belousov #include <sys/smr.h> 429ef425e5SKonstantin Belousov #include <sys/sysctl.h> 438f0e9130SKonstantin Belousov 448f0e9130SKonstantin Belousov #include <vm/uma.h> 458f0e9130SKonstantin Belousov 46c3d8a931SKonstantin Belousov /* 479ef425e5SKonstantin Belousov * Immediately after initialization (subject to 'rangelock_cheat' 489ef425e5SKonstantin Belousov * below), and until a request comes that conflicts with granted ones 499ef425e5SKonstantin Belousov * based on type, rangelocks serve requests in the "cheating" mode. 509ef425e5SKonstantin Belousov * In this mode, a rangelock behaves like a sxlock, as if each request 519ef425e5SKonstantin Belousov * covered the whole range of the protected object. On receiving a 529ef425e5SKonstantin Belousov * conflicting request (any request while a write request is 539ef425e5SKonstantin Belousov * effective, or any write request while some read ones are 549ef425e5SKonstantin Belousov * effective), all requests granted in "cheating" mode are drained, 559ef425e5SKonstantin Belousov * and the rangelock then switches to effectively keeping track of the 569ef425e5SKonstantin Belousov * precise range of each new request. 579ef425e5SKonstantin Belousov * 589ef425e5SKonstantin Belousov * Normal sx implementation is not used to not bloat structures (most 599ef425e5SKonstantin Belousov * important, vnodes) which embeds rangelocks. 609ef425e5SKonstantin Belousov * 619ef425e5SKonstantin Belousov * The cheating greatly helps very common pattern where file is first 629ef425e5SKonstantin Belousov * written single-threaded, and then read by many processes. 639ef425e5SKonstantin Belousov * 649ef425e5SKonstantin Belousov * Lock is in cheat mode when RL_CHEAT_CHEATING bit is set in the 659ef425e5SKonstantin Belousov * lock->head. Special cookies are returned in this mode, and 669ef425e5SKonstantin Belousov * trylocks are same as normal locks but do not drain. 679ef425e5SKonstantin Belousov */ 689ef425e5SKonstantin Belousov 699ef425e5SKonstantin Belousov static int rangelock_cheat = 1; 709ef425e5SKonstantin Belousov SYSCTL_INT(_debug, OID_AUTO, rangelock_cheat, CTLFLAG_RWTUN, 719ef425e5SKonstantin Belousov &rangelock_cheat, 0, 729ef425e5SKonstantin Belousov ""); 739ef425e5SKonstantin Belousov 749ef425e5SKonstantin Belousov #define RL_CHEAT_MASK 0x7 759ef425e5SKonstantin Belousov #define RL_CHEAT_CHEATING 0x1 769ef425e5SKonstantin Belousov /* #define RL_CHEAT_RLOCKED 0x0 */ 779ef425e5SKonstantin Belousov #define RL_CHEAT_WLOCKED 0x2 789ef425e5SKonstantin Belousov #define RL_CHEAT_DRAINING 0x4 799ef425e5SKonstantin Belousov 809ef425e5SKonstantin Belousov #define RL_CHEAT_READER 0x8 819ef425e5SKonstantin Belousov 829ef425e5SKonstantin Belousov #define RL_RET_CHEAT_RLOCKED 0x1100 839ef425e5SKonstantin Belousov #define RL_RET_CHEAT_WLOCKED 0x2200 849ef425e5SKonstantin Belousov 859ef425e5SKonstantin Belousov static bool 869ef425e5SKonstantin Belousov rangelock_cheat_lock(struct rangelock *lock, int locktype, bool trylock, 879ef425e5SKonstantin Belousov void **cookie) 889ef425e5SKonstantin Belousov { 899ef425e5SKonstantin Belousov uintptr_t v, x; 909ef425e5SKonstantin Belousov 919ef425e5SKonstantin Belousov v = (uintptr_t)atomic_load_ptr(&lock->head); 929ef425e5SKonstantin Belousov if ((v & RL_CHEAT_CHEATING) == 0) 939ef425e5SKonstantin Belousov return (false); 949ef425e5SKonstantin Belousov if ((v & RL_CHEAT_DRAINING) != 0) { 959ef425e5SKonstantin Belousov drain: 969ef425e5SKonstantin Belousov if (trylock) { 979ef425e5SKonstantin Belousov *cookie = NULL; 989ef425e5SKonstantin Belousov return (true); 999ef425e5SKonstantin Belousov } 1009ef425e5SKonstantin Belousov sleepq_lock(&lock->head); 1019ef425e5SKonstantin Belousov drain1: 1029ef425e5SKonstantin Belousov DROP_GIANT(); 1039ef425e5SKonstantin Belousov for (;;) { 1049ef425e5SKonstantin Belousov v = (uintptr_t)atomic_load_ptr(&lock->head); 1059ef425e5SKonstantin Belousov if ((v & RL_CHEAT_DRAINING) == 0) 1069ef425e5SKonstantin Belousov break; 1079ef425e5SKonstantin Belousov sleepq_add(&lock->head, NULL, "ranged1", 0, 0); 1089ef425e5SKonstantin Belousov sleepq_wait(&lock->head, PRI_USER); 1099ef425e5SKonstantin Belousov sleepq_lock(&lock->head); 1109ef425e5SKonstantin Belousov } 1119ef425e5SKonstantin Belousov sleepq_release(&lock->head); 1129ef425e5SKonstantin Belousov PICKUP_GIANT(); 1139ef425e5SKonstantin Belousov return (false); 1149ef425e5SKonstantin Belousov } 1159ef425e5SKonstantin Belousov 1169ef425e5SKonstantin Belousov switch (locktype) { 1179ef425e5SKonstantin Belousov case RL_LOCK_READ: 1189ef425e5SKonstantin Belousov for (;;) { 1199ef425e5SKonstantin Belousov if ((v & RL_CHEAT_WLOCKED) != 0) { 1209ef425e5SKonstantin Belousov if (trylock) { 1219ef425e5SKonstantin Belousov *cookie = NULL; 1229ef425e5SKonstantin Belousov return (true); 1239ef425e5SKonstantin Belousov } 1249ef425e5SKonstantin Belousov x = v | RL_CHEAT_DRAINING; 1259ef425e5SKonstantin Belousov sleepq_lock(&lock->head); 1269ef425e5SKonstantin Belousov if (atomic_fcmpset_rel_ptr(&lock->head, &v, 1279ef425e5SKonstantin Belousov x) != 0) 1289ef425e5SKonstantin Belousov goto drain1; 1299ef425e5SKonstantin Belousov sleepq_release(&lock->head); 1309ef425e5SKonstantin Belousov /* Possibly forgive passed conflict */ 1319ef425e5SKonstantin Belousov continue; 1329ef425e5SKonstantin Belousov } 1339ef425e5SKonstantin Belousov x = (v & ~RL_CHEAT_MASK) + RL_CHEAT_READER; 1349ef425e5SKonstantin Belousov x |= RL_CHEAT_CHEATING; 1359ef425e5SKonstantin Belousov if (atomic_fcmpset_acq_ptr(&lock->head, &v, x) != 0) 1369ef425e5SKonstantin Belousov break; 1379ef425e5SKonstantin Belousov if ((v & RL_CHEAT_CHEATING) == 0) 1389ef425e5SKonstantin Belousov return (false); 1399ef425e5SKonstantin Belousov if ((v & RL_CHEAT_DRAINING) != 0) 1409ef425e5SKonstantin Belousov goto drain; 1419ef425e5SKonstantin Belousov } 1429ef425e5SKonstantin Belousov *(uintptr_t *)cookie = RL_RET_CHEAT_RLOCKED; 1439ef425e5SKonstantin Belousov break; 1449ef425e5SKonstantin Belousov case RL_LOCK_WRITE: 1459ef425e5SKonstantin Belousov for (;;) { 1469ef425e5SKonstantin Belousov if ((v & ~RL_CHEAT_MASK) >= RL_CHEAT_READER || 1479ef425e5SKonstantin Belousov (v & RL_CHEAT_WLOCKED) != 0) { 1489ef425e5SKonstantin Belousov if (trylock) { 1499ef425e5SKonstantin Belousov *cookie = NULL; 1509ef425e5SKonstantin Belousov return (true); 1519ef425e5SKonstantin Belousov } 1529ef425e5SKonstantin Belousov x = v | RL_CHEAT_DRAINING; 1539ef425e5SKonstantin Belousov sleepq_lock(&lock->head); 1549ef425e5SKonstantin Belousov if (atomic_fcmpset_rel_ptr(&lock->head, &v, 1559ef425e5SKonstantin Belousov x) != 0) 1569ef425e5SKonstantin Belousov goto drain1; 1579ef425e5SKonstantin Belousov sleepq_release(&lock->head); 1589ef425e5SKonstantin Belousov /* Possibly forgive passed conflict */ 1599ef425e5SKonstantin Belousov continue; 1609ef425e5SKonstantin Belousov } 1619ef425e5SKonstantin Belousov x = RL_CHEAT_WLOCKED | RL_CHEAT_CHEATING; 1629ef425e5SKonstantin Belousov if (atomic_fcmpset_acq_ptr(&lock->head, &v, x) != 0) 1639ef425e5SKonstantin Belousov break; 1649ef425e5SKonstantin Belousov if ((v & RL_CHEAT_CHEATING) == 0) 1659ef425e5SKonstantin Belousov return (false); 1669ef425e5SKonstantin Belousov if ((v & RL_CHEAT_DRAINING) != 0) 1679ef425e5SKonstantin Belousov goto drain; 1689ef425e5SKonstantin Belousov } 1699ef425e5SKonstantin Belousov *(uintptr_t *)cookie = RL_RET_CHEAT_WLOCKED; 1709ef425e5SKonstantin Belousov break; 1719ef425e5SKonstantin Belousov default: 1729ef425e5SKonstantin Belousov __assert_unreachable(); 1739ef425e5SKonstantin Belousov break; 1749ef425e5SKonstantin Belousov } 1759ef425e5SKonstantin Belousov return (true); 1769ef425e5SKonstantin Belousov } 1779ef425e5SKonstantin Belousov 1789ef425e5SKonstantin Belousov static bool 1799ef425e5SKonstantin Belousov rangelock_cheat_unlock(struct rangelock *lock, void *cookie) 1809ef425e5SKonstantin Belousov { 1819ef425e5SKonstantin Belousov uintptr_t v, x; 1829ef425e5SKonstantin Belousov 1839ef425e5SKonstantin Belousov v = (uintptr_t)atomic_load_ptr(&lock->head); 1849ef425e5SKonstantin Belousov if ((v & RL_CHEAT_CHEATING) == 0) 1859ef425e5SKonstantin Belousov return (false); 1869ef425e5SKonstantin Belousov 1879ef425e5SKonstantin Belousov MPASS((uintptr_t)cookie == RL_RET_CHEAT_WLOCKED || 1889ef425e5SKonstantin Belousov (uintptr_t)cookie == RL_RET_CHEAT_RLOCKED); 1899ef425e5SKonstantin Belousov 1909ef425e5SKonstantin Belousov switch ((uintptr_t)cookie) { 1919ef425e5SKonstantin Belousov case RL_RET_CHEAT_RLOCKED: 1929ef425e5SKonstantin Belousov for (;;) { 1939ef425e5SKonstantin Belousov MPASS((v & ~RL_CHEAT_MASK) >= RL_CHEAT_READER); 1949ef425e5SKonstantin Belousov MPASS((v & RL_CHEAT_WLOCKED) == 0); 1959ef425e5SKonstantin Belousov x = (v & ~RL_CHEAT_MASK) - RL_CHEAT_READER; 1969ef425e5SKonstantin Belousov if ((v & RL_CHEAT_DRAINING) != 0) { 1979ef425e5SKonstantin Belousov if (x != 0) { 1989ef425e5SKonstantin Belousov x |= RL_CHEAT_DRAINING | 1999ef425e5SKonstantin Belousov RL_CHEAT_CHEATING; 2009ef425e5SKonstantin Belousov if (atomic_fcmpset_rel_ptr(&lock->head, 2019ef425e5SKonstantin Belousov &v, x) != 0) 2029ef425e5SKonstantin Belousov break; 2039ef425e5SKonstantin Belousov } else { 2049ef425e5SKonstantin Belousov sleepq_lock(&lock->head); 2059ef425e5SKonstantin Belousov if (atomic_fcmpset_rel_ptr(&lock->head, 2069ef425e5SKonstantin Belousov &v, x) != 0) { 2079ef425e5SKonstantin Belousov sleepq_broadcast( 2089ef425e5SKonstantin Belousov &lock->head, 2099ef425e5SKonstantin Belousov SLEEPQ_SLEEP, 0, 0); 2109ef425e5SKonstantin Belousov sleepq_release(&lock->head); 2119ef425e5SKonstantin Belousov break; 2129ef425e5SKonstantin Belousov } 2139ef425e5SKonstantin Belousov sleepq_release(&lock->head); 2149ef425e5SKonstantin Belousov } 2159ef425e5SKonstantin Belousov } else { 2169ef425e5SKonstantin Belousov x |= RL_CHEAT_CHEATING; 2179ef425e5SKonstantin Belousov if (atomic_fcmpset_rel_ptr(&lock->head, &v, 2189ef425e5SKonstantin Belousov x) != 0) 2199ef425e5SKonstantin Belousov break; 2209ef425e5SKonstantin Belousov } 2219ef425e5SKonstantin Belousov } 2229ef425e5SKonstantin Belousov break; 2239ef425e5SKonstantin Belousov case RL_RET_CHEAT_WLOCKED: 2249ef425e5SKonstantin Belousov for (;;) { 2259ef425e5SKonstantin Belousov MPASS((v & RL_CHEAT_WLOCKED) != 0); 2269ef425e5SKonstantin Belousov if ((v & RL_CHEAT_DRAINING) != 0) { 2279ef425e5SKonstantin Belousov sleepq_lock(&lock->head); 2289ef425e5SKonstantin Belousov atomic_store_ptr(&lock->head, 0); 2299ef425e5SKonstantin Belousov sleepq_broadcast(&lock->head, 2309ef425e5SKonstantin Belousov SLEEPQ_SLEEP, 0, 0); 2319ef425e5SKonstantin Belousov sleepq_release(&lock->head); 2329ef425e5SKonstantin Belousov break; 2339ef425e5SKonstantin Belousov } else { 2349ef425e5SKonstantin Belousov if (atomic_fcmpset_ptr(&lock->head, &v, 2359ef425e5SKonstantin Belousov RL_CHEAT_CHEATING) != 0) 2369ef425e5SKonstantin Belousov break; 2379ef425e5SKonstantin Belousov } 2389ef425e5SKonstantin Belousov } 2399ef425e5SKonstantin Belousov break; 2409ef425e5SKonstantin Belousov default: 2419ef425e5SKonstantin Belousov __assert_unreachable(); 2429ef425e5SKonstantin Belousov break; 2439ef425e5SKonstantin Belousov } 2449ef425e5SKonstantin Belousov return (true); 2459ef425e5SKonstantin Belousov } 2469ef425e5SKonstantin Belousov 2479ef425e5SKonstantin Belousov static bool 2489ef425e5SKonstantin Belousov rangelock_cheat_destroy(struct rangelock *lock) 2499ef425e5SKonstantin Belousov { 2509ef425e5SKonstantin Belousov uintptr_t v; 2519ef425e5SKonstantin Belousov 2529ef425e5SKonstantin Belousov v = (uintptr_t)atomic_load_ptr(&lock->head); 2539ef425e5SKonstantin Belousov if ((v & RL_CHEAT_CHEATING) == 0) 2549ef425e5SKonstantin Belousov return (false); 2559ef425e5SKonstantin Belousov MPASS(v == RL_CHEAT_CHEATING); 2569ef425e5SKonstantin Belousov return (true); 2579ef425e5SKonstantin Belousov } 2589ef425e5SKonstantin Belousov 2599ef425e5SKonstantin Belousov /* 260c3d8a931SKonstantin Belousov * Implementation of range locks based on the paper 261c3d8a931SKonstantin Belousov * https://doi.org/10.1145/3342195.3387533 262c3d8a931SKonstantin Belousov * arXiv:2006.12144v1 [cs.OS] 22 Jun 2020 263c3d8a931SKonstantin Belousov * Scalable Range Locks for Scalable Address Spaces and Beyond 264c3d8a931SKonstantin Belousov * by Alex Kogan, Dave Dice, and Shady Issa 265c3d8a931SKonstantin Belousov */ 266c3d8a931SKonstantin Belousov 267c3d8a931SKonstantin Belousov static struct rl_q_entry *rl_e_unmark(const struct rl_q_entry *e); 268c3d8a931SKonstantin Belousov 269c3d8a931SKonstantin Belousov /* 270c3d8a931SKonstantin Belousov * rl_q_next links all granted ranges in the lock. We cannot free an 271c3d8a931SKonstantin Belousov * rl_q_entry while in the smr section, and cannot reuse rl_q_next 272c3d8a931SKonstantin Belousov * linkage since other threads might follow it even after CAS removed 273c3d8a931SKonstantin Belousov * the range. Use rl_q_free for local list of ranges to remove after 274c3d8a931SKonstantin Belousov * the smr section is dropped. 275c3d8a931SKonstantin Belousov */ 2768f0e9130SKonstantin Belousov struct rl_q_entry { 277c3d8a931SKonstantin Belousov struct rl_q_entry *rl_q_next; 278c3d8a931SKonstantin Belousov struct rl_q_entry *rl_q_free; 2798f0e9130SKonstantin Belousov off_t rl_q_start, rl_q_end; 2808f0e9130SKonstantin Belousov int rl_q_flags; 281c3d8a931SKonstantin Belousov #ifdef INVARIANTS 282c3d8a931SKonstantin Belousov struct thread *rl_q_owner; 283c3d8a931SKonstantin Belousov #endif 2848f0e9130SKonstantin Belousov }; 2858f0e9130SKonstantin Belousov 2868f0e9130SKonstantin Belousov static uma_zone_t rl_entry_zone; 287c3d8a931SKonstantin Belousov static smr_t rl_smr; 2888f0e9130SKonstantin Belousov 2898f0e9130SKonstantin Belousov static void 2908f0e9130SKonstantin Belousov rangelock_sys_init(void) 2918f0e9130SKonstantin Belousov { 2928f0e9130SKonstantin Belousov rl_entry_zone = uma_zcreate("rl_entry", sizeof(struct rl_q_entry), 293c3d8a931SKonstantin Belousov NULL, NULL, NULL, NULL, UMA_ALIGNOF(struct rl_q_entry), 294c3d8a931SKonstantin Belousov UMA_ZONE_SMR); 295c3d8a931SKonstantin Belousov rl_smr = uma_zone_get_smr(rl_entry_zone); 2968f0e9130SKonstantin Belousov } 297c3d8a931SKonstantin Belousov SYSINIT(rl, SI_SUB_LOCK, SI_ORDER_ANY, rangelock_sys_init, NULL); 2988f0e9130SKonstantin Belousov 2998f0e9130SKonstantin Belousov static struct rl_q_entry * 300c3d8a931SKonstantin Belousov rlqentry_alloc(vm_ooffset_t start, vm_ooffset_t end, int flags) 3018f0e9130SKonstantin Belousov { 302c3d8a931SKonstantin Belousov struct rl_q_entry *e; 303ff1ae3b3SKonstantin Belousov struct thread *td; 3048f0e9130SKonstantin Belousov 305ff1ae3b3SKonstantin Belousov td = curthread; 306ff1ae3b3SKonstantin Belousov if (td->td_rlqe != NULL) { 307ff1ae3b3SKonstantin Belousov e = td->td_rlqe; 308ff1ae3b3SKonstantin Belousov td->td_rlqe = NULL; 309ff1ae3b3SKonstantin Belousov } else { 310c3d8a931SKonstantin Belousov e = uma_zalloc_smr(rl_entry_zone, M_WAITOK); 311ff1ae3b3SKonstantin Belousov } 312c3d8a931SKonstantin Belousov e->rl_q_next = NULL; 313c3d8a931SKonstantin Belousov e->rl_q_free = NULL; 314c3d8a931SKonstantin Belousov e->rl_q_start = start; 315c3d8a931SKonstantin Belousov e->rl_q_end = end; 316c3d8a931SKonstantin Belousov e->rl_q_flags = flags; 317c3d8a931SKonstantin Belousov #ifdef INVARIANTS 318c3d8a931SKonstantin Belousov e->rl_q_owner = curthread; 319c3d8a931SKonstantin Belousov #endif 320c3d8a931SKonstantin Belousov return (e); 3218f0e9130SKonstantin Belousov } 3228f0e9130SKonstantin Belousov 3238f0e9130SKonstantin Belousov void 324ff1ae3b3SKonstantin Belousov rangelock_entry_free(struct rl_q_entry *e) 325ff1ae3b3SKonstantin Belousov { 326ff1ae3b3SKonstantin Belousov uma_zfree_smr(rl_entry_zone, e); 327ff1ae3b3SKonstantin Belousov } 328ff1ae3b3SKonstantin Belousov 329ff1ae3b3SKonstantin Belousov void 3308f0e9130SKonstantin Belousov rangelock_init(struct rangelock *lock) 3318f0e9130SKonstantin Belousov { 332c3d8a931SKonstantin Belousov lock->sleepers = false; 3339ef425e5SKonstantin Belousov atomic_store_ptr(&lock->head, rangelock_cheat ? RL_CHEAT_CHEATING : 0); 3348f0e9130SKonstantin Belousov } 3358f0e9130SKonstantin Belousov 3368f0e9130SKonstantin Belousov void 3378f0e9130SKonstantin Belousov rangelock_destroy(struct rangelock *lock) 3388f0e9130SKonstantin Belousov { 339c3d8a931SKonstantin Belousov struct rl_q_entry *e, *ep; 3408f0e9130SKonstantin Belousov 341c3d8a931SKonstantin Belousov MPASS(!lock->sleepers); 3429ef425e5SKonstantin Belousov if (rangelock_cheat_destroy(lock)) 3439ef425e5SKonstantin Belousov return; 344c3d8a931SKonstantin Belousov for (e = (struct rl_q_entry *)atomic_load_ptr(&lock->head); 345c3d8a931SKonstantin Belousov e != NULL; e = rl_e_unmark(ep)) { 346c3d8a931SKonstantin Belousov ep = atomic_load_ptr(&e->rl_q_next); 347c3d8a931SKonstantin Belousov uma_zfree_smr(rl_entry_zone, e); 348c3d8a931SKonstantin Belousov } 3498f0e9130SKonstantin Belousov } 3508f0e9130SKonstantin Belousov 351c3d8a931SKonstantin Belousov static bool 352c3d8a931SKonstantin Belousov rl_e_is_marked(const struct rl_q_entry *e) 3538f0e9130SKonstantin Belousov { 354c3d8a931SKonstantin Belousov return (((uintptr_t)e & 1) != 0); 3558f0e9130SKonstantin Belousov } 3568f0e9130SKonstantin Belousov 357c3d8a931SKonstantin Belousov static struct rl_q_entry * 3585badbeeaSKonstantin Belousov rl_e_unmark_unchecked(const struct rl_q_entry *e) 3595badbeeaSKonstantin Belousov { 3605badbeeaSKonstantin Belousov return ((struct rl_q_entry *)((uintptr_t)e & ~1)); 3615badbeeaSKonstantin Belousov } 3625badbeeaSKonstantin Belousov 3635badbeeaSKonstantin Belousov static struct rl_q_entry * 364c3d8a931SKonstantin Belousov rl_e_unmark(const struct rl_q_entry *e) 3658f0e9130SKonstantin Belousov { 366c3d8a931SKonstantin Belousov MPASS(rl_e_is_marked(e)); 3675badbeeaSKonstantin Belousov return (rl_e_unmark_unchecked(e)); 3685badbeeaSKonstantin Belousov } 3695badbeeaSKonstantin Belousov 3705badbeeaSKonstantin Belousov static void 3715badbeeaSKonstantin Belousov rl_e_mark(struct rl_q_entry *e) 3725badbeeaSKonstantin Belousov { 3735badbeeaSKonstantin Belousov #if defined(INVARIANTS) && defined(__LP64__) 3745badbeeaSKonstantin Belousov int r = atomic_testandset_long((uintptr_t *)&e->rl_q_next, 0); 3755badbeeaSKonstantin Belousov MPASS(r == 0); 3765badbeeaSKonstantin Belousov #else 3775badbeeaSKonstantin Belousov atomic_set_ptr((uintptr_t *)&e->rl_q_next, 1); 3785badbeeaSKonstantin Belousov #endif 3792bb93f2dSColin Percival } 3802bb93f2dSColin Percival 381c3d8a931SKonstantin Belousov static struct rl_q_entry * 382c3d8a931SKonstantin Belousov rl_q_load(struct rl_q_entry **p) 3838f0e9130SKonstantin Belousov { 384c3d8a931SKonstantin Belousov return ((struct rl_q_entry *)atomic_load_acq_ptr((uintptr_t *)p)); 3858f0e9130SKonstantin Belousov } 3868f0e9130SKonstantin Belousov 3876c32d89eSKonstantin Belousov static bool 3886c32d89eSKonstantin Belousov rl_e_is_rlock(const struct rl_q_entry *e) 3896c32d89eSKonstantin Belousov { 3906c32d89eSKonstantin Belousov return ((e->rl_q_flags & RL_LOCK_TYPE_MASK) == RL_LOCK_READ); 3916c32d89eSKonstantin Belousov } 3926c32d89eSKonstantin Belousov 3935badbeeaSKonstantin Belousov static void 3945badbeeaSKonstantin Belousov rangelock_unlock_int(struct rangelock *lock, struct rl_q_entry *e) 3958f0e9130SKonstantin Belousov { 396c3158008SKonstantin Belousov bool sleepers; 397c3158008SKonstantin Belousov 398c3d8a931SKonstantin Belousov MPASS(lock != NULL && e != NULL); 399c3d8a931SKonstantin Belousov MPASS(!rl_e_is_marked(rl_q_load(&e->rl_q_next))); 400c3d8a931SKonstantin Belousov MPASS(e->rl_q_owner == curthread); 4018f0e9130SKonstantin Belousov 4025badbeeaSKonstantin Belousov rl_e_mark(e); 403c3158008SKonstantin Belousov sleepers = lock->sleepers; 404c3d8a931SKonstantin Belousov lock->sleepers = false; 405c3158008SKonstantin Belousov if (sleepers) 406c3d8a931SKonstantin Belousov sleepq_broadcast(&lock->sleepers, SLEEPQ_SLEEP, 0, 0); 4075badbeeaSKonstantin Belousov } 4085badbeeaSKonstantin Belousov 4095badbeeaSKonstantin Belousov void 4105badbeeaSKonstantin Belousov rangelock_unlock(struct rangelock *lock, void *cookie) 4115badbeeaSKonstantin Belousov { 4129ef425e5SKonstantin Belousov if (rangelock_cheat_unlock(lock, cookie)) 4139ef425e5SKonstantin Belousov return; 4149ef425e5SKonstantin Belousov 4155badbeeaSKonstantin Belousov sleepq_lock(&lock->sleepers); 4165badbeeaSKonstantin Belousov rangelock_unlock_int(lock, cookie); 417c3d8a931SKonstantin Belousov sleepq_release(&lock->sleepers); 4188f0e9130SKonstantin Belousov } 4198f0e9130SKonstantin Belousov 4208f0e9130SKonstantin Belousov /* 4215badbeeaSKonstantin Belousov * result: -1 if e1 before e2, or both locks are readers and e1 4225badbeeaSKonstantin Belousov * starts before or at e2 4235badbeeaSKonstantin Belousov * 1 if e1 after e2, or both locks are readers and e1 4245badbeeaSKonstantin Belousov * starts after e2 4255badbeeaSKonstantin Belousov * 0 if e1 and e2 overlap and at least one lock is writer 4268f0e9130SKonstantin Belousov */ 427c3d8a931SKonstantin Belousov static int 428c3d8a931SKonstantin Belousov rl_e_compare(const struct rl_q_entry *e1, const struct rl_q_entry *e2) 4298f0e9130SKonstantin Belousov { 4305badbeeaSKonstantin Belousov bool rds; 4315badbeeaSKonstantin Belousov 432c3d8a931SKonstantin Belousov if (e1 == NULL) 433c3d8a931SKonstantin Belousov return (1); 434c3d8a931SKonstantin Belousov if (e2->rl_q_start >= e1->rl_q_end) 435c3d8a931SKonstantin Belousov return (-1); 4365badbeeaSKonstantin Belousov rds = rl_e_is_rlock(e1) && rl_e_is_rlock(e2); 4375badbeeaSKonstantin Belousov if (e2->rl_q_start >= e1->rl_q_start && rds) 4385badbeeaSKonstantin Belousov return (-1); 4395badbeeaSKonstantin Belousov if (e1->rl_q_start >= e2->rl_q_end) 4405badbeeaSKonstantin Belousov return (1); 4415badbeeaSKonstantin Belousov if (e1->rl_q_start >= e2->rl_q_start && rds) 4425badbeeaSKonstantin Belousov return (1); 443c3d8a931SKonstantin Belousov return (0); 4448f0e9130SKonstantin Belousov } 4458f0e9130SKonstantin Belousov 446c3d8a931SKonstantin Belousov static void 447c3d8a931SKonstantin Belousov rl_insert_sleep(struct rangelock *lock) 4488f0e9130SKonstantin Belousov { 449c3d8a931SKonstantin Belousov smr_exit(rl_smr); 450c3d8a931SKonstantin Belousov DROP_GIANT(); 451c3d8a931SKonstantin Belousov lock->sleepers = true; 452c3d8a931SKonstantin Belousov sleepq_add(&lock->sleepers, NULL, "rangelk", 0, 0); 453c3d8a931SKonstantin Belousov sleepq_wait(&lock->sleepers, PRI_USER); 454c3d8a931SKonstantin Belousov PICKUP_GIANT(); 455c3d8a931SKonstantin Belousov smr_enter(rl_smr); 456c3d8a931SKonstantin Belousov } 4578f0e9130SKonstantin Belousov 458c3d8a931SKonstantin Belousov static bool 459c3d8a931SKonstantin Belousov rl_q_cas(struct rl_q_entry **prev, struct rl_q_entry *old, 460c3d8a931SKonstantin Belousov struct rl_q_entry *new) 461c3d8a931SKonstantin Belousov { 462c3d8a931SKonstantin Belousov return (atomic_cmpset_rel_ptr((uintptr_t *)prev, (uintptr_t)old, 463c3d8a931SKonstantin Belousov (uintptr_t)new) != 0); 464c3d8a931SKonstantin Belousov } 4658f0e9130SKonstantin Belousov 4665badbeeaSKonstantin Belousov enum RL_INSERT_RES { 4675badbeeaSKonstantin Belousov RL_TRYLOCK_FAILED, 4685badbeeaSKonstantin Belousov RL_LOCK_SUCCESS, 4695badbeeaSKonstantin Belousov RL_LOCK_RETRY, 4705badbeeaSKonstantin Belousov }; 4715badbeeaSKonstantin Belousov 4725badbeeaSKonstantin Belousov static enum RL_INSERT_RES 4735badbeeaSKonstantin Belousov rl_r_validate(struct rangelock *lock, struct rl_q_entry *e, bool trylock, 4745badbeeaSKonstantin Belousov struct rl_q_entry **free) 4755badbeeaSKonstantin Belousov { 4765badbeeaSKonstantin Belousov struct rl_q_entry *cur, *next, **prev; 4775badbeeaSKonstantin Belousov 4785badbeeaSKonstantin Belousov prev = &e->rl_q_next; 4795badbeeaSKonstantin Belousov cur = rl_q_load(prev); 4805badbeeaSKonstantin Belousov MPASS(!rl_e_is_marked(cur)); /* nobody can unlock e yet */ 4815badbeeaSKonstantin Belousov for (;;) { 4825badbeeaSKonstantin Belousov if (cur == NULL || cur->rl_q_start > e->rl_q_end) 4835badbeeaSKonstantin Belousov return (RL_LOCK_SUCCESS); 4845badbeeaSKonstantin Belousov next = rl_q_load(&cur->rl_q_next); 4855badbeeaSKonstantin Belousov if (rl_e_is_marked(next)) { 4865badbeeaSKonstantin Belousov next = rl_e_unmark(next); 4875badbeeaSKonstantin Belousov if (rl_q_cas(prev, cur, next)) { 4885badbeeaSKonstantin Belousov cur->rl_q_free = *free; 4895badbeeaSKonstantin Belousov *free = cur; 4905badbeeaSKonstantin Belousov } 4915badbeeaSKonstantin Belousov cur = next; 4925badbeeaSKonstantin Belousov continue; 4935badbeeaSKonstantin Belousov } 4945badbeeaSKonstantin Belousov if (rl_e_is_rlock(cur)) { 4955badbeeaSKonstantin Belousov prev = &cur->rl_q_next; 4965badbeeaSKonstantin Belousov cur = rl_e_unmark_unchecked(rl_q_load(prev)); 4975badbeeaSKonstantin Belousov continue; 4985badbeeaSKonstantin Belousov } 4995badbeeaSKonstantin Belousov if (!rl_e_is_marked(rl_q_load(&cur->rl_q_next))) { 5005badbeeaSKonstantin Belousov sleepq_lock(&lock->sleepers); 5015badbeeaSKonstantin Belousov if (rl_e_is_marked(rl_q_load(&cur->rl_q_next))) { 5025badbeeaSKonstantin Belousov sleepq_release(&lock->sleepers); 5035badbeeaSKonstantin Belousov continue; 5045badbeeaSKonstantin Belousov } 5055badbeeaSKonstantin Belousov rangelock_unlock_int(lock, e); 5065badbeeaSKonstantin Belousov if (trylock) { 5075badbeeaSKonstantin Belousov sleepq_release(&lock->sleepers); 5085badbeeaSKonstantin Belousov return (RL_TRYLOCK_FAILED); 5095badbeeaSKonstantin Belousov } 5105badbeeaSKonstantin Belousov rl_insert_sleep(lock); 5115badbeeaSKonstantin Belousov return (RL_LOCK_RETRY); 5125badbeeaSKonstantin Belousov } 5135badbeeaSKonstantin Belousov } 5145badbeeaSKonstantin Belousov } 5155badbeeaSKonstantin Belousov 5165badbeeaSKonstantin Belousov static enum RL_INSERT_RES 5175badbeeaSKonstantin Belousov rl_w_validate(struct rangelock *lock, struct rl_q_entry *e, 5185badbeeaSKonstantin Belousov bool trylock, struct rl_q_entry **free) 5195badbeeaSKonstantin Belousov { 5205badbeeaSKonstantin Belousov struct rl_q_entry *cur, *next, **prev; 5215badbeeaSKonstantin Belousov 5229ef425e5SKonstantin Belousov prev = (struct rl_q_entry **)&lock->head; 5235badbeeaSKonstantin Belousov cur = rl_q_load(prev); 5245badbeeaSKonstantin Belousov MPASS(!rl_e_is_marked(cur)); /* head is not marked */ 5255badbeeaSKonstantin Belousov for (;;) { 5265badbeeaSKonstantin Belousov if (cur == e) 5275badbeeaSKonstantin Belousov return (RL_LOCK_SUCCESS); 5285badbeeaSKonstantin Belousov next = rl_q_load(&cur->rl_q_next); 5295badbeeaSKonstantin Belousov if (rl_e_is_marked(next)) { 5305badbeeaSKonstantin Belousov next = rl_e_unmark(next); 5315badbeeaSKonstantin Belousov if (rl_q_cas(prev, cur, next)) { 5325badbeeaSKonstantin Belousov cur->rl_q_next = *free; 5335badbeeaSKonstantin Belousov *free = cur; 5345badbeeaSKonstantin Belousov } 5355badbeeaSKonstantin Belousov cur = next; 5365badbeeaSKonstantin Belousov continue; 5375badbeeaSKonstantin Belousov } 5385badbeeaSKonstantin Belousov if (cur->rl_q_end <= e->rl_q_start) { 5395badbeeaSKonstantin Belousov prev = &cur->rl_q_next; 5405badbeeaSKonstantin Belousov cur = rl_e_unmark_unchecked(rl_q_load(prev)); 5415badbeeaSKonstantin Belousov continue; 5425badbeeaSKonstantin Belousov } 5435badbeeaSKonstantin Belousov sleepq_lock(&lock->sleepers); 5445badbeeaSKonstantin Belousov rangelock_unlock_int(lock, e); 5455badbeeaSKonstantin Belousov if (trylock) { 5465badbeeaSKonstantin Belousov sleepq_release(&lock->sleepers); 5475badbeeaSKonstantin Belousov return (RL_TRYLOCK_FAILED); 5485badbeeaSKonstantin Belousov } 5495badbeeaSKonstantin Belousov rl_insert_sleep(lock); 5505badbeeaSKonstantin Belousov return (RL_LOCK_RETRY); 5515badbeeaSKonstantin Belousov } 5525badbeeaSKonstantin Belousov } 5535badbeeaSKonstantin Belousov 5545badbeeaSKonstantin Belousov static enum RL_INSERT_RES 555c3d8a931SKonstantin Belousov rl_insert(struct rangelock *lock, struct rl_q_entry *e, bool trylock, 556c3d8a931SKonstantin Belousov struct rl_q_entry **free) 557c3d8a931SKonstantin Belousov { 558c3d8a931SKonstantin Belousov struct rl_q_entry *cur, *next, **prev; 559c3d8a931SKonstantin Belousov int r; 5608f0e9130SKonstantin Belousov 561c3d8a931SKonstantin Belousov again: 5629ef425e5SKonstantin Belousov prev = (struct rl_q_entry **)&lock->head; 5635badbeeaSKonstantin Belousov cur = rl_q_load(prev); 5645badbeeaSKonstantin Belousov if (cur == NULL && rl_q_cas(prev, NULL, e)) 5655badbeeaSKonstantin Belousov return (RL_LOCK_SUCCESS); 5668f0e9130SKonstantin Belousov 5675badbeeaSKonstantin Belousov for (;;) { 5685badbeeaSKonstantin Belousov if (cur != NULL) { 569c3d8a931SKonstantin Belousov if (rl_e_is_marked(cur)) 570c3d8a931SKonstantin Belousov goto again; 571c3d8a931SKonstantin Belousov 572c3d8a931SKonstantin Belousov next = rl_q_load(&cur->rl_q_next); 573c3d8a931SKonstantin Belousov if (rl_e_is_marked(next)) { 574c3d8a931SKonstantin Belousov next = rl_e_unmark(next); 575c3d8a931SKonstantin Belousov if (rl_q_cas(prev, cur, next)) { 576c3d8a931SKonstantin Belousov #ifdef INVARIANTS 577c3d8a931SKonstantin Belousov cur->rl_q_owner = NULL; 578c3d8a931SKonstantin Belousov #endif 579c3d8a931SKonstantin Belousov cur->rl_q_free = *free; 580c3d8a931SKonstantin Belousov *free = cur; 581c3d8a931SKonstantin Belousov } 582c3d8a931SKonstantin Belousov cur = next; 583c3d8a931SKonstantin Belousov continue; 584c3d8a931SKonstantin Belousov } 585c3d8a931SKonstantin Belousov } 586c3d8a931SKonstantin Belousov 587c3d8a931SKonstantin Belousov r = rl_e_compare(cur, e); 588c3d8a931SKonstantin Belousov if (r == -1) { 589c3d8a931SKonstantin Belousov prev = &cur->rl_q_next; 590c3d8a931SKonstantin Belousov cur = rl_q_load(prev); 591c3d8a931SKonstantin Belousov } else if (r == 0) { 592c3d8a931SKonstantin Belousov sleepq_lock(&lock->sleepers); 593c3d8a931SKonstantin Belousov if (__predict_false(rl_e_is_marked(rl_q_load( 594c3d8a931SKonstantin Belousov &cur->rl_q_next)))) { 595c3d8a931SKonstantin Belousov sleepq_release(&lock->sleepers); 596c3d8a931SKonstantin Belousov continue; 597c3d8a931SKonstantin Belousov } 598e3680954SRick Macklem if (trylock) { 599c3d8a931SKonstantin Belousov sleepq_release(&lock->sleepers); 6005badbeeaSKonstantin Belousov return (RL_TRYLOCK_FAILED); 601e3680954SRick Macklem } 602c3d8a931SKonstantin Belousov rl_insert_sleep(lock); 603c3d8a931SKonstantin Belousov /* e is still valid */ 604c3d8a931SKonstantin Belousov goto again; 605c3d8a931SKonstantin Belousov } else /* r == 1 */ { 606c3d8a931SKonstantin Belousov e->rl_q_next = cur; 607c3d8a931SKonstantin Belousov if (rl_q_cas(prev, cur, e)) { 608c3d8a931SKonstantin Belousov atomic_thread_fence_acq(); 6095badbeeaSKonstantin Belousov return (rl_e_is_rlock(e) ? 6105badbeeaSKonstantin Belousov rl_r_validate(lock, e, trylock, free) : 6115badbeeaSKonstantin Belousov rl_w_validate(lock, e, trylock, free)); 612e3680954SRick Macklem } 613c3d8a931SKonstantin Belousov /* Reset rl_q_next in case we hit fast path. */ 614c3d8a931SKonstantin Belousov e->rl_q_next = NULL; 615c3d8a931SKonstantin Belousov cur = rl_q_load(prev); 616c3d8a931SKonstantin Belousov } 617c3d8a931SKonstantin Belousov } 618c3d8a931SKonstantin Belousov } 619c3d8a931SKonstantin Belousov 620c3d8a931SKonstantin Belousov static struct rl_q_entry * 6215badbeeaSKonstantin Belousov rangelock_lock_int(struct rangelock *lock, bool trylock, vm_ooffset_t start, 6225badbeeaSKonstantin Belousov vm_ooffset_t end, int locktype) 623c3d8a931SKonstantin Belousov { 6245badbeeaSKonstantin Belousov struct rl_q_entry *e, *free, *x, *xp; 625ff1ae3b3SKonstantin Belousov struct thread *td; 6269ef425e5SKonstantin Belousov void *cookie; 6275badbeeaSKonstantin Belousov enum RL_INSERT_RES res; 628c3d8a931SKonstantin Belousov 6299ef425e5SKonstantin Belousov if (rangelock_cheat_lock(lock, locktype, trylock, &cookie)) 6309ef425e5SKonstantin Belousov return (cookie); 631ff1ae3b3SKonstantin Belousov td = curthread; 6325badbeeaSKonstantin Belousov for (res = RL_LOCK_RETRY; res == RL_LOCK_RETRY;) { 633c3d8a931SKonstantin Belousov free = NULL; 6345badbeeaSKonstantin Belousov e = rlqentry_alloc(start, end, locktype); 635c3d8a931SKonstantin Belousov smr_enter(rl_smr); 636c3d8a931SKonstantin Belousov res = rl_insert(lock, e, trylock, &free); 637c3d8a931SKonstantin Belousov smr_exit(rl_smr); 6385badbeeaSKonstantin Belousov if (res == RL_TRYLOCK_FAILED) { 6395badbeeaSKonstantin Belousov MPASS(trylock); 640c3d8a931SKonstantin Belousov e->rl_q_free = free; 641c3d8a931SKonstantin Belousov free = e; 642c3d8a931SKonstantin Belousov e = NULL; 643c3d8a931SKonstantin Belousov } 644c3d8a931SKonstantin Belousov for (x = free; x != NULL; x = xp) { 645c3d8a931SKonstantin Belousov MPASS(!rl_e_is_marked(x)); 646c3d8a931SKonstantin Belousov xp = x->rl_q_free; 647c3d8a931SKonstantin Belousov MPASS(!rl_e_is_marked(xp)); 648ff1ae3b3SKonstantin Belousov if (td->td_rlqe == NULL) { 649ff1ae3b3SKonstantin Belousov smr_synchronize(rl_smr); 650ff1ae3b3SKonstantin Belousov td->td_rlqe = x; 651ff1ae3b3SKonstantin Belousov } else { 652c3d8a931SKonstantin Belousov uma_zfree_smr(rl_entry_zone, x); 653c3d8a931SKonstantin Belousov } 6545badbeeaSKonstantin Belousov } 655ff1ae3b3SKonstantin Belousov } 656c3d8a931SKonstantin Belousov return (e); 6578f0e9130SKonstantin Belousov } 6588f0e9130SKonstantin Belousov 6598f0e9130SKonstantin Belousov void * 660c3d8a931SKonstantin Belousov rangelock_rlock(struct rangelock *lock, vm_ooffset_t start, vm_ooffset_t end) 6618f0e9130SKonstantin Belousov { 6625badbeeaSKonstantin Belousov return (rangelock_lock_int(lock, false, start, end, RL_LOCK_READ)); 663e3680954SRick Macklem } 664e3680954SRick Macklem 665e3680954SRick Macklem void * 666c3d8a931SKonstantin Belousov rangelock_tryrlock(struct rangelock *lock, vm_ooffset_t start, vm_ooffset_t end) 667e3680954SRick Macklem { 6685badbeeaSKonstantin Belousov return (rangelock_lock_int(lock, true, start, end, RL_LOCK_READ)); 6698f0e9130SKonstantin Belousov } 6708f0e9130SKonstantin Belousov 6718f0e9130SKonstantin Belousov void * 672c3d8a931SKonstantin Belousov rangelock_wlock(struct rangelock *lock, vm_ooffset_t start, vm_ooffset_t end) 6738f0e9130SKonstantin Belousov { 6749ef425e5SKonstantin Belousov return (rangelock_lock_int(lock, false, start, end, RL_LOCK_WRITE)); 675e3680954SRick Macklem } 676e3680954SRick Macklem 677e3680954SRick Macklem void * 678c3d8a931SKonstantin Belousov rangelock_trywlock(struct rangelock *lock, vm_ooffset_t start, vm_ooffset_t end) 679e3680954SRick Macklem { 6805badbeeaSKonstantin Belousov return (rangelock_lock_int(lock, true, start, end, RL_LOCK_WRITE)); 6818f0e9130SKonstantin Belousov } 6823155f2f0SKyle Evans 6833155f2f0SKyle Evans #ifdef INVARIANT_SUPPORT 6843155f2f0SKyle Evans void 6853155f2f0SKyle Evans _rangelock_cookie_assert(void *cookie, int what, const char *file, int line) 6863155f2f0SKyle Evans { 6873155f2f0SKyle Evans } 6883155f2f0SKyle Evans #endif /* INVARIANT_SUPPORT */ 689c3d8a931SKonstantin Belousov 690c3d8a931SKonstantin Belousov #include "opt_ddb.h" 691c3d8a931SKonstantin Belousov #ifdef DDB 692c3d8a931SKonstantin Belousov #include <ddb/ddb.h> 693c3d8a931SKonstantin Belousov 694c3d8a931SKonstantin Belousov DB_SHOW_COMMAND(rangelock, db_show_rangelock) 695c3d8a931SKonstantin Belousov { 696c3d8a931SKonstantin Belousov struct rangelock *lock; 697c3d8a931SKonstantin Belousov struct rl_q_entry *e, *x; 6989ef425e5SKonstantin Belousov uintptr_t v; 699c3d8a931SKonstantin Belousov 700c3d8a931SKonstantin Belousov if (!have_addr) { 701c3d8a931SKonstantin Belousov db_printf("show rangelock addr\n"); 702c3d8a931SKonstantin Belousov return; 703c3d8a931SKonstantin Belousov } 704c3d8a931SKonstantin Belousov 705c3d8a931SKonstantin Belousov lock = (struct rangelock *)addr; 706c3d8a931SKonstantin Belousov db_printf("rangelock %p sleepers %d\n", lock, lock->sleepers); 7079ef425e5SKonstantin Belousov v = lock->head; 7089ef425e5SKonstantin Belousov if ((v & RL_CHEAT_CHEATING) != 0) { 7099ef425e5SKonstantin Belousov db_printf(" cheating head %#jx\n", (uintmax_t)v); 7109ef425e5SKonstantin Belousov return; 7119ef425e5SKonstantin Belousov } 7129ef425e5SKonstantin Belousov for (e = (struct rl_q_entry *)(lock->head);;) { 713c3d8a931SKonstantin Belousov x = rl_e_is_marked(e) ? rl_e_unmark(e) : e; 714c3d8a931SKonstantin Belousov if (x == NULL) 715c3d8a931SKonstantin Belousov break; 716c3d8a931SKonstantin Belousov db_printf(" entry %p marked %d %d start %#jx end %#jx " 717c3d8a931SKonstantin Belousov "flags %x next %p", 718c3d8a931SKonstantin Belousov e, rl_e_is_marked(e), rl_e_is_marked(x->rl_q_next), 719c3d8a931SKonstantin Belousov x->rl_q_start, x->rl_q_end, x->rl_q_flags, x->rl_q_next); 720c3d8a931SKonstantin Belousov #ifdef INVARIANTS 721c3d8a931SKonstantin Belousov db_printf(" owner %p (%d)", x->rl_q_owner, 722c3d8a931SKonstantin Belousov x->rl_q_owner != NULL ? x->rl_q_owner->td_tid : -1); 723c3d8a931SKonstantin Belousov #endif 724c3d8a931SKonstantin Belousov db_printf("\n"); 725c3d8a931SKonstantin Belousov e = x->rl_q_next; 726c3d8a931SKonstantin Belousov } 727c3d8a931SKonstantin Belousov } 728c3d8a931SKonstantin Belousov 729c3d8a931SKonstantin Belousov #endif /* DDB */ 730