33#include <sys/kernel.h>
37#include <sys/rangelock.h>
44 off_t rl_q_start, rl_q_end;
55 NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
77 TAILQ_INIT(&lock->rl_waiters);
78 lock->rl_currdep = NULL;
85 KASSERT(TAILQ_EMPTY(&lock->rl_waiters), (
"Dangling waiters"));
97 if (e1->rl_q_start < e2->rl_q_end && e1->rl_q_end > e2->rl_q_start)
108 struct rl_q_entry *entry, *nextentry, *entry1;
110 for (entry = lock->rl_currdep; entry != NULL; entry = nextentry) {
111 nextentry = TAILQ_NEXT(entry, rl_q_link);
112 if (entry->rl_q_flags & RL_LOCK_READ) {
114 for (entry1 = TAILQ_FIRST(&lock->rl_waiters);
115 !(entry1->rl_q_flags & RL_LOCK_READ);
116 entry1 = TAILQ_NEXT(entry1, rl_q_link)) {
122 for (entry1 = TAILQ_FIRST(&lock->rl_waiters);
124 entry1 = TAILQ_NEXT(entry1, rl_q_link)) {
130 TAILQ_REMOVE(&lock->rl_waiters, entry, rl_q_link);
131 TAILQ_INSERT_HEAD(&lock->rl_waiters, entry, rl_q_link);
135 entry->rl_q_flags |= RL_LOCK_GRANTED;
139 lock->rl_currdep = entry;
144 struct mtx *ilk,
bool do_calc_block)
147 MPASS(lock != NULL && entry != NULL && ilk != NULL);
148 mtx_assert(ilk, MA_OWNED);
150 if (!do_calc_block) {
160 if (lock->rl_currdep == entry) {
161 KASSERT(TAILQ_NEXT(lock->rl_currdep, rl_q_link) == NULL,
162 (
"rangelock_enqueue: next entry not NULL"));
163 lock->rl_currdep = NULL;
166 KASSERT(entry != lock->rl_currdep, (
"stuck currdep"));
168 TAILQ_REMOVE(&lock->rl_waiters, entry, rl_q_link);
172 if (curthread->td_rlqe == NULL)
173 curthread->td_rlqe = entry;
182 MPASS(lock != NULL && cookie != NULL && ilk != NULL);
193 off_t end,
struct mtx *ilk)
197 MPASS(lock != NULL && cookie != NULL && ilk != NULL);
199 KASSERT(entry->rl_q_flags & RL_LOCK_GRANTED,
200 (
"Unlocking non-granted lock"));
201 KASSERT(entry->rl_q_start ==
start, (
"wrong start"));
202 KASSERT(entry->rl_q_end >= end, (
"wrong end"));
205 if (entry->rl_q_end == end) {
209 entry->rl_q_end = end;
221 struct mtx *ilk,
bool trylock)
226 MPASS(lock != NULL && ilk != NULL);
229 if (td->td_rlqe != NULL) {
234 MPASS(entry != NULL);
235 entry->rl_q_flags =
mode;
236 entry->rl_q_start =
start;
237 entry->rl_q_end = end;
246 TAILQ_INSERT_TAIL(&lock->rl_waiters, entry, rl_q_link);
253 if (lock->rl_currdep == NULL)
254 lock->rl_currdep = entry;
256 while (!(entry->rl_q_flags & RL_LOCK_GRANTED)) {
267 msleep(entry, ilk, 0,
"range", 0);
303#ifdef INVARIANT_SUPPORT
305_rangelock_cookie_assert(
void *cookie,
int what,
const char *file,
int line)
310 MPASS(cookie != NULL);
312 flags = entry->rl_q_flags;
315 if ((
flags & RL_LOCK_GRANTED) == 0)
316 panic(
"rangelock not held @ %s:%d\n", file, line);
319 if ((
flags & (RL_LOCK_GRANTED | RL_LOCK_READ)) !=
320 (RL_LOCK_GRANTED | RL_LOCK_READ))
321 panic(
"rangelock not rlocked @ %s:%d\n", file, line);
324 if ((
flags & (RL_LOCK_GRANTED | RL_LOCK_WRITE)) !=
325 (RL_LOCK_GRANTED | RL_LOCK_WRITE))
326 panic(
"rangelock not wlocked @ %s:%d\n", file, line);
329 panic(
"Unknown rangelock assertion: %d @ %s:%d", what, file,
static void rangelock_unlock_locked(struct rangelock *lock, struct rl_q_entry *entry, struct mtx *ilk, bool do_calc_block)
void rlqentry_free(struct rl_q_entry *rleq)
void * rangelock_tryrlock(struct rangelock *lock, off_t start, off_t end, struct mtx *ilk)
static struct rl_q_entry * rlqentry_alloc(void)
static void rangelock_sys_init(void)
void rangelock_destroy(struct rangelock *lock)
void * rangelock_rlock(struct rangelock *lock, off_t start, off_t end, struct mtx *ilk)
SYSINIT(vfs, SI_SUB_LOCK, SI_ORDER_ANY, rangelock_sys_init, NULL)
static uma_zone_t rl_entry_zone
void * rangelock_trywlock(struct rangelock *lock, off_t start, off_t end, struct mtx *ilk)
void rangelock_unlock(struct rangelock *lock, void *cookie, struct mtx *ilk)
void rangelock_init(struct rangelock *lock)
static void rangelock_calc_block(struct rangelock *lock)
void * rangelock_unlock_range(struct rangelock *lock, void *cookie, off_t start, off_t end, struct mtx *ilk)
void * rangelock_wlock(struct rangelock *lock, off_t start, off_t end, struct mtx *ilk)
static int ranges_overlap(const struct rl_q_entry *e1, const struct rl_q_entry *e2)
static void * rangelock_enqueue(struct rangelock *lock, off_t start, off_t end, int mode, struct mtx *ilk, bool trylock)
void panic(const char *fmt,...)
void wakeup(const void *ident)