xref: /netbsd-src/sys/external/bsd/drm2/linux/linux_ww_mutex.c (revision 181254a7b1bdde6873432bffef2d2decc4b5c22f)
1 /*	$NetBSD: linux_ww_mutex.c,v 1.7 2019/05/09 05:00:31 ozaki-r Exp $	*/
2 
3 /*-
4  * Copyright (c) 2014 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Taylor R. Campbell.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: linux_ww_mutex.c,v 1.7 2019/05/09 05:00:31 ozaki-r Exp $");
34 
35 #include <sys/types.h>
36 #include <sys/atomic.h>
37 #include <sys/condvar.h>
38 #include <sys/lockdebug.h>
39 #include <sys/lwp.h>
40 #include <sys/mutex.h>
41 #include <sys/rbtree.h>
42 
43 #include <linux/ww_mutex.h>
44 #include <linux/errno.h>
45 
46 #define	WW_WANTLOCK(WW)							      \
47 	LOCKDEBUG_WANTLOCK((WW)->wwm_debug, (WW),			      \
48 	    (uintptr_t)__builtin_return_address(0), 0)
49 #define	WW_LOCKED(WW)							      \
50 	LOCKDEBUG_LOCKED((WW)->wwm_debug, (WW), NULL,			      \
51 	    (uintptr_t)__builtin_return_address(0), 0)
52 #define	WW_UNLOCKED(WW)							      \
53 	LOCKDEBUG_UNLOCKED((WW)->wwm_debug, (WW),			      \
54 	    (uintptr_t)__builtin_return_address(0), 0)
55 
56 static int
57 ww_acquire_ctx_compare(void *cookie __unused, const void *va, const void *vb)
58 {
59 	const struct ww_acquire_ctx *const ctx_a = va;
60 	const struct ww_acquire_ctx *const ctx_b = vb;
61 
62 	if (ctx_a->wwx_ticket < ctx_b->wwx_ticket)
63 		return -1;
64 	if (ctx_a->wwx_ticket > ctx_b->wwx_ticket)
65 		return -1;
66 	return 0;
67 }
68 
69 static int
70 ww_acquire_ctx_compare_key(void *cookie __unused, const void *vn,
71     const void *vk)
72 {
73 	const struct ww_acquire_ctx *const ctx = vn;
74 	const uint64_t *const ticketp = vk, ticket = *ticketp;
75 
76 	if (ctx->wwx_ticket < ticket)
77 		return -1;
78 	if (ctx->wwx_ticket > ticket)
79 		return -1;
80 	return 0;
81 }
82 
83 static const rb_tree_ops_t ww_acquire_ctx_rb_ops = {
84 	.rbto_compare_nodes = &ww_acquire_ctx_compare,
85 	.rbto_compare_key = &ww_acquire_ctx_compare_key,
86 	.rbto_node_offset = offsetof(struct ww_acquire_ctx, wwx_rb_node),
87 	.rbto_context = NULL,
88 };
89 
90 void
91 ww_acquire_init(struct ww_acquire_ctx *ctx, struct ww_class *class)
92 {
93 
94 	ctx->wwx_class = class;
95 	ctx->wwx_owner = curlwp;
96 	ctx->wwx_ticket = atomic64_inc_return(&class->wwc_ticket);
97 	ctx->wwx_acquired = 0;
98 	ctx->wwx_acquire_done = false;
99 }
100 
101 void
102 ww_acquire_done(struct ww_acquire_ctx *ctx)
103 {
104 
105 	KASSERTMSG((ctx->wwx_owner == curlwp),
106 	    "ctx %p owned by %p, not self (%p)", ctx, ctx->wwx_owner, curlwp);
107 
108 	ctx->wwx_acquire_done = true;
109 }
110 
111 void
112 ww_acquire_fini(struct ww_acquire_ctx *ctx)
113 {
114 
115 	KASSERTMSG((ctx->wwx_owner == curlwp),
116 	    "ctx %p owned by %p, not self (%p)", ctx, ctx->wwx_owner, curlwp);
117 	KASSERTMSG((ctx->wwx_acquired == 0), "ctx %p still holds %u locks",
118 	    ctx, ctx->wwx_acquired);
119 
120 	ctx->wwx_acquired = ~0U;	/* Fail if called again. */
121 	ctx->wwx_owner = NULL;
122 }
123 
124 #ifdef LOCKDEBUG
125 static void
126 ww_dump(const volatile void *cookie, lockop_printer_t pr)
127 {
128 	const volatile struct ww_mutex *mutex = cookie;
129 
130 	pr("%-13s: ", "state");
131 	switch (mutex->wwm_state) {
132 	case WW_UNLOCKED:
133 		pr("unlocked\n");
134 		break;
135 	case WW_OWNED:
136 		pr("owned by lwp\n");
137 		pr("%-13s: %p\n", "owner", mutex->wwm_u.owner);
138 		pr("%-13s: %s\n", "waiters",
139 		    cv_has_waiters((void *)(intptr_t)&mutex->wwm_cv)
140 			? "yes" : "no");
141 		break;
142 	case WW_CTX:
143 		pr("owned via ctx\n");
144 		pr("%-13s: %p\n", "context", mutex->wwm_u.ctx);
145 		pr("%-13s: %p\n", "lwp",
146 		    mutex->wwm_u.ctx->wwx_owner);
147 		pr("%-13s: %s\n", "waiters",
148 		    cv_has_waiters((void *)(intptr_t)&mutex->wwm_cv)
149 			? "yes" : "no");
150 		break;
151 	case WW_WANTOWN:
152 		pr("owned via ctx\n");
153 		pr("%-13s: %p\n", "context", mutex->wwm_u.ctx);
154 		pr("%-13s: %p\n", "lwp",
155 		    mutex->wwm_u.ctx->wwx_owner);
156 		pr("%-13s: %s\n", "waiters", "yes (noctx)");
157 		break;
158 	default:
159 		pr("unknown\n");
160 		break;
161 	}
162 }
163 
164 static lockops_t ww_lockops = {
165 	.lo_name = "Wait/wound mutex",
166 	.lo_type = LOCKOPS_SLEEP,
167 	.lo_dump = ww_dump,
168 };
169 #endif
170 
171 void
172 ww_mutex_init(struct ww_mutex *mutex, struct ww_class *class)
173 {
174 
175 	/*
176 	 * XXX Apparently Linux takes these with spin locks held.  That
177 	 * strikes me as a bad idea, but so it is...
178 	 */
179 	mutex_init(&mutex->wwm_lock, MUTEX_DEFAULT, IPL_VM);
180 	mutex->wwm_state = WW_UNLOCKED;
181 	mutex->wwm_class = class;
182 	rb_tree_init(&mutex->wwm_waiters, &ww_acquire_ctx_rb_ops);
183 	cv_init(&mutex->wwm_cv, "linuxwwm");
184 #ifdef LOCKDEBUG
185 	mutex->wwm_debug = LOCKDEBUG_ALLOC(mutex, &ww_lockops,
186 	    (uintptr_t)__builtin_return_address(0));
187 #endif
188 }
189 
190 void
191 ww_mutex_destroy(struct ww_mutex *mutex)
192 {
193 
194 	KASSERT(mutex->wwm_state == WW_UNLOCKED);
195 
196 #ifdef LOCKDEBUG
197 	LOCKDEBUG_FREE(mutex->wwm_debug, mutex);
198 #endif
199 	cv_destroy(&mutex->wwm_cv);
200 #if 0
201 	rb_tree_destroy(&mutex->wwm_waiters, &ww_acquire_ctx_rb_ops);
202 #endif
203 	KASSERT(mutex->wwm_state == WW_UNLOCKED);
204 	mutex_destroy(&mutex->wwm_lock);
205 }
206 
207 /*
208  * XXX WARNING: This returns true if it is locked by ANYONE.  Does not
209  * mean `Do I hold this lock?' (answering which really requires an
210  * acquire context).
211  */
212 bool
213 ww_mutex_is_locked(struct ww_mutex *mutex)
214 {
215 	int locked;
216 
217 	mutex_enter(&mutex->wwm_lock);
218 	switch (mutex->wwm_state) {
219 	case WW_UNLOCKED:
220 		locked = false;
221 		break;
222 	case WW_OWNED:
223 	case WW_CTX:
224 	case WW_WANTOWN:
225 		locked = true;
226 		break;
227 	default:
228 		panic("wait/wound mutex %p in bad state: %d", mutex,
229 		    (int)mutex->wwm_state);
230 	}
231 	mutex_exit(&mutex->wwm_lock);
232 
233 	return locked;
234 }
235 
236 static void
237 ww_mutex_state_wait(struct ww_mutex *mutex, enum ww_mutex_state state)
238 {
239 
240 	KASSERT(mutex->wwm_state == state);
241 	do cv_wait(&mutex->wwm_cv, &mutex->wwm_lock);
242 	while (mutex->wwm_state == state);
243 }
244 
245 static int
246 ww_mutex_state_wait_sig(struct ww_mutex *mutex, enum ww_mutex_state state)
247 {
248 	int ret;
249 
250 	KASSERT(mutex->wwm_state == state);
251 	do {
252 		/* XXX errno NetBSD->Linux */
253 		ret = -cv_wait_sig(&mutex->wwm_cv, &mutex->wwm_lock);
254 		if (ret == -ERESTART)
255 			ret = -ERESTARTSYS;
256 		if (ret)
257 			break;
258 	} while (mutex->wwm_state == state);
259 
260 	return ret;
261 }
262 
263 static void
264 ww_mutex_lock_wait(struct ww_mutex *mutex, struct ww_acquire_ctx *ctx)
265 {
266 	struct ww_acquire_ctx *collision __diagused;
267 
268 	KASSERT(mutex_owned(&mutex->wwm_lock));
269 
270 	KASSERT((mutex->wwm_state == WW_CTX) ||
271 	    (mutex->wwm_state == WW_WANTOWN));
272 	KASSERT(mutex->wwm_u.ctx != ctx);
273 	KASSERTMSG((ctx->wwx_class == mutex->wwm_u.ctx->wwx_class),
274 	    "ww mutex class mismatch: %p != %p",
275 	    ctx->wwx_class, mutex->wwm_u.ctx->wwx_class);
276 	KASSERTMSG((mutex->wwm_u.ctx->wwx_ticket != ctx->wwx_ticket),
277 	    "ticket number reused: %"PRId64" (%p) %"PRId64" (%p)",
278 	    ctx->wwx_ticket, ctx,
279 	    mutex->wwm_u.ctx->wwx_ticket, mutex->wwm_u.ctx);
280 
281 	collision = rb_tree_insert_node(&mutex->wwm_waiters, ctx);
282 	KASSERTMSG((collision == ctx),
283 	    "ticket number reused: %"PRId64" (%p) %"PRId64" (%p)",
284 	    ctx->wwx_ticket, ctx, collision->wwx_ticket, collision);
285 
286 	do cv_wait(&mutex->wwm_cv, &mutex->wwm_lock);
287 	while (!(((mutex->wwm_state == WW_CTX) ||
288 		    (mutex->wwm_state == WW_WANTOWN)) &&
289 		 (mutex->wwm_u.ctx == ctx)));
290 
291 	rb_tree_remove_node(&mutex->wwm_waiters, ctx);
292 }
293 
294 static int
295 ww_mutex_lock_wait_sig(struct ww_mutex *mutex, struct ww_acquire_ctx *ctx)
296 {
297 	struct ww_acquire_ctx *collision __diagused;
298 	int ret;
299 
300 	KASSERT(mutex_owned(&mutex->wwm_lock));
301 
302 	KASSERT((mutex->wwm_state == WW_CTX) ||
303 	    (mutex->wwm_state == WW_WANTOWN));
304 	KASSERT(mutex->wwm_u.ctx != ctx);
305 	KASSERTMSG((ctx->wwx_class == mutex->wwm_u.ctx->wwx_class),
306 	    "ww mutex class mismatch: %p != %p",
307 	    ctx->wwx_class, mutex->wwm_u.ctx->wwx_class);
308 	KASSERTMSG((mutex->wwm_u.ctx->wwx_ticket != ctx->wwx_ticket),
309 	    "ticket number reused: %"PRId64" (%p) %"PRId64" (%p)",
310 	    ctx->wwx_ticket, ctx,
311 	    mutex->wwm_u.ctx->wwx_ticket, mutex->wwm_u.ctx);
312 
313 	collision = rb_tree_insert_node(&mutex->wwm_waiters, ctx);
314 	KASSERTMSG((collision == ctx),
315 	    "ticket number reused: %"PRId64" (%p) %"PRId64" (%p)",
316 	    ctx->wwx_ticket, ctx, collision->wwx_ticket, collision);
317 
318 	do {
319 		/* XXX errno NetBSD->Linux */
320 		ret = -cv_wait_sig(&mutex->wwm_cv, &mutex->wwm_lock);
321 		if (ret == -ERESTART)
322 			ret = -ERESTARTSYS;
323 		if (ret)
324 			goto out;
325 	} while (!(((mutex->wwm_state == WW_CTX) ||
326 		    (mutex->wwm_state == WW_WANTOWN)) &&
327 		(mutex->wwm_u.ctx == ctx)));
328 
329 out:	rb_tree_remove_node(&mutex->wwm_waiters, ctx);
330 	return ret;
331 }
332 
333 static void
334 ww_mutex_lock_noctx(struct ww_mutex *mutex)
335 {
336 
337 	mutex_enter(&mutex->wwm_lock);
338 retry:	switch (mutex->wwm_state) {
339 	case WW_UNLOCKED:
340 		mutex->wwm_state = WW_OWNED;
341 		mutex->wwm_u.owner = curlwp;
342 		break;
343 	case WW_OWNED:
344 		KASSERTMSG((mutex->wwm_u.owner != curlwp),
345 		    "locking %p against myself: %p", mutex, curlwp);
346 		ww_mutex_state_wait(mutex, WW_OWNED);
347 		goto retry;
348 	case WW_CTX:
349 		KASSERT(mutex->wwm_u.ctx != NULL);
350 		mutex->wwm_state = WW_WANTOWN;
351 		/* FALLTHROUGH */
352 	case WW_WANTOWN:
353 		KASSERTMSG((mutex->wwm_u.ctx->wwx_owner != curlwp),
354 		    "locking %p against myself: %p", mutex, curlwp);
355 		ww_mutex_state_wait(mutex, WW_WANTOWN);
356 		goto retry;
357 	default:
358 		panic("wait/wound mutex %p in bad state: %d",
359 		    mutex, (int)mutex->wwm_state);
360 	}
361 	KASSERT(mutex->wwm_state == WW_OWNED);
362 	KASSERT(mutex->wwm_u.owner == curlwp);
363 	WW_LOCKED(mutex);
364 	mutex_exit(&mutex->wwm_lock);
365 }
366 
367 static int
368 ww_mutex_lock_noctx_sig(struct ww_mutex *mutex)
369 {
370 	int ret;
371 
372 	mutex_enter(&mutex->wwm_lock);
373 retry:	switch (mutex->wwm_state) {
374 	case WW_UNLOCKED:
375 		mutex->wwm_state = WW_OWNED;
376 		mutex->wwm_u.owner = curlwp;
377 		break;
378 	case WW_OWNED:
379 		KASSERTMSG((mutex->wwm_u.owner != curlwp),
380 		    "locking %p against myself: %p", mutex, curlwp);
381 		ret = ww_mutex_state_wait_sig(mutex, WW_OWNED);
382 		if (ret)
383 			goto out;
384 		goto retry;
385 	case WW_CTX:
386 		KASSERT(mutex->wwm_u.ctx != NULL);
387 		mutex->wwm_state = WW_WANTOWN;
388 		/* FALLTHROUGH */
389 	case WW_WANTOWN:
390 		KASSERTMSG((mutex->wwm_u.ctx->wwx_owner != curlwp),
391 		    "locking %p against myself: %p", mutex, curlwp);
392 		ret = ww_mutex_state_wait_sig(mutex, WW_WANTOWN);
393 		if (ret)
394 			goto out;
395 		goto retry;
396 	default:
397 		panic("wait/wound mutex %p in bad state: %d",
398 		    mutex, (int)mutex->wwm_state);
399 	}
400 	KASSERT(mutex->wwm_state == WW_OWNED);
401 	KASSERT(mutex->wwm_u.owner == curlwp);
402 	WW_LOCKED(mutex);
403 	ret = 0;
404 out:	mutex_exit(&mutex->wwm_lock);
405 	return ret;
406 }
407 
408 int
409 ww_mutex_lock(struct ww_mutex *mutex, struct ww_acquire_ctx *ctx)
410 {
411 
412 	/*
413 	 * We do not WW_WANTLOCK at the beginning because we may
414 	 * correctly already hold it, if we have a context, in which
415 	 * case we must return EALREADY to the caller.
416 	 */
417 	ASSERT_SLEEPABLE();
418 
419 	if (ctx == NULL) {
420 		WW_WANTLOCK(mutex);
421 		ww_mutex_lock_noctx(mutex);
422 		return 0;
423 	}
424 
425 	KASSERTMSG((ctx->wwx_owner == curlwp),
426 	    "ctx %p owned by %p, not self (%p)", ctx, ctx->wwx_owner, curlwp);
427 	KASSERTMSG(!ctx->wwx_acquire_done,
428 	    "ctx %p done acquiring locks, can't acquire more", ctx);
429 	KASSERTMSG((ctx->wwx_acquired != ~0U),
430 	    "ctx %p finished, can't be used any more", ctx);
431 	KASSERTMSG((ctx->wwx_class == mutex->wwm_class),
432 	    "ctx %p in class %p, mutex %p in class %p",
433 	    ctx, ctx->wwx_class, mutex, mutex->wwm_class);
434 
435 	mutex_enter(&mutex->wwm_lock);
436 retry:	switch (mutex->wwm_state) {
437 	case WW_UNLOCKED:
438 		WW_WANTLOCK(mutex);
439 		mutex->wwm_state = WW_CTX;
440 		mutex->wwm_u.ctx = ctx;
441 		goto locked;
442 	case WW_OWNED:
443 		WW_WANTLOCK(mutex);
444 		KASSERTMSG((mutex->wwm_u.owner != curlwp),
445 		    "locking %p against myself: %p", mutex, curlwp);
446 		ww_mutex_state_wait(mutex, WW_OWNED);
447 		goto retry;
448 	case WW_CTX:
449 		break;
450 	case WW_WANTOWN:
451 		ww_mutex_state_wait(mutex, WW_WANTOWN);
452 		goto retry;
453 	default:
454 		panic("wait/wound mutex %p in bad state: %d",
455 		    mutex, (int)mutex->wwm_state);
456 	}
457 
458 	KASSERT(mutex->wwm_state == WW_CTX);
459 	KASSERT(mutex->wwm_u.ctx != NULL);
460 	KASSERT((mutex->wwm_u.ctx == ctx) ||
461 	    (mutex->wwm_u.ctx->wwx_owner != curlwp));
462 
463 	if (mutex->wwm_u.ctx == ctx) {
464 		/*
465 		 * We already own it.  Yes, this can happen correctly
466 		 * for objects whose locking order is determined by
467 		 * userland.
468 		 */
469 		mutex_exit(&mutex->wwm_lock);
470 		return -EALREADY;
471 	}
472 
473 	/*
474 	 * We do not own it.  We can safely assert to LOCKDEBUG that we
475 	 * want it.
476 	 */
477 	WW_WANTLOCK(mutex);
478 
479 	if (mutex->wwm_u.ctx->wwx_ticket < ctx->wwx_ticket) {
480 		/*
481 		 * Owned by a higher-priority party.  Tell the caller
482 		 * to unlock everything and start over.
483 		 */
484 		KASSERTMSG((ctx->wwx_class == mutex->wwm_u.ctx->wwx_class),
485 		    "ww mutex class mismatch: %p != %p",
486 		    ctx->wwx_class, mutex->wwm_u.ctx->wwx_class);
487 		mutex_exit(&mutex->wwm_lock);
488 		return -EDEADLK;
489 	}
490 
491 	/*
492 	 * Owned by a lower-priority party.  Ask that party to wake us
493 	 * when it is done or it realizes it needs to back off.
494 	 */
495 	ww_mutex_lock_wait(mutex, ctx);
496 
497 locked:	KASSERT((mutex->wwm_state == WW_CTX) ||
498 	    (mutex->wwm_state == WW_WANTOWN));
499 	KASSERT(mutex->wwm_u.ctx == ctx);
500 	WW_LOCKED(mutex);
501 	ctx->wwx_acquired++;
502 	mutex_exit(&mutex->wwm_lock);
503 	return 0;
504 }
505 
506 int
507 ww_mutex_lock_interruptible(struct ww_mutex *mutex, struct ww_acquire_ctx *ctx)
508 {
509 	int ret;
510 
511 	/*
512 	 * We do not WW_WANTLOCK at the beginning because we may
513 	 * correctly already hold it, if we have a context, in which
514 	 * case we must return EALREADY to the caller.
515 	 */
516 	ASSERT_SLEEPABLE();
517 
518 	if (ctx == NULL) {
519 		WW_WANTLOCK(mutex);
520 		return ww_mutex_lock_noctx_sig(mutex);
521 	}
522 
523 	KASSERTMSG((ctx->wwx_owner == curlwp),
524 	    "ctx %p owned by %p, not self (%p)", ctx, ctx->wwx_owner, curlwp);
525 	KASSERTMSG(!ctx->wwx_acquire_done,
526 	    "ctx %p done acquiring locks, can't acquire more", ctx);
527 	KASSERTMSG((ctx->wwx_acquired != ~0U),
528 	    "ctx %p finished, can't be used any more", ctx);
529 	KASSERTMSG((ctx->wwx_class == mutex->wwm_class),
530 	    "ctx %p in class %p, mutex %p in class %p",
531 	    ctx, ctx->wwx_class, mutex, mutex->wwm_class);
532 
533 	mutex_enter(&mutex->wwm_lock);
534 retry:	switch (mutex->wwm_state) {
535 	case WW_UNLOCKED:
536 		WW_WANTLOCK(mutex);
537 		mutex->wwm_state = WW_CTX;
538 		mutex->wwm_u.ctx = ctx;
539 		goto locked;
540 	case WW_OWNED:
541 		WW_WANTLOCK(mutex);
542 		KASSERTMSG((mutex->wwm_u.owner != curlwp),
543 		    "locking %p against myself: %p", mutex, curlwp);
544 		ret = ww_mutex_state_wait_sig(mutex, WW_OWNED);
545 		if (ret)
546 			goto out;
547 		goto retry;
548 	case WW_CTX:
549 		break;
550 	case WW_WANTOWN:
551 		ret = ww_mutex_state_wait_sig(mutex, WW_WANTOWN);
552 		if (ret)
553 			goto out;
554 		goto retry;
555 	default:
556 		panic("wait/wound mutex %p in bad state: %d",
557 		    mutex, (int)mutex->wwm_state);
558 	}
559 
560 	KASSERT(mutex->wwm_state == WW_CTX);
561 	KASSERT(mutex->wwm_u.ctx != NULL);
562 	KASSERT((mutex->wwm_u.ctx == ctx) ||
563 	    (mutex->wwm_u.ctx->wwx_owner != curlwp));
564 
565 	if (mutex->wwm_u.ctx == ctx) {
566 		/*
567 		 * We already own it.  Yes, this can happen correctly
568 		 * for objects whose locking order is determined by
569 		 * userland.
570 		 */
571 		mutex_exit(&mutex->wwm_lock);
572 		return -EALREADY;
573 	}
574 
575 	/*
576 	 * We do not own it.  We can safely assert to LOCKDEBUG that we
577 	 * want it.
578 	 */
579 	WW_WANTLOCK(mutex);
580 
581 	if (mutex->wwm_u.ctx->wwx_ticket < ctx->wwx_ticket) {
582 		/*
583 		 * Owned by a higher-priority party.  Tell the caller
584 		 * to unlock everything and start over.
585 		 */
586 		KASSERTMSG((ctx->wwx_class == mutex->wwm_u.ctx->wwx_class),
587 		    "ww mutex class mismatch: %p != %p",
588 		    ctx->wwx_class, mutex->wwm_u.ctx->wwx_class);
589 		mutex_exit(&mutex->wwm_lock);
590 		return -EDEADLK;
591 	}
592 
593 	/*
594 	 * Owned by a lower-priority party.  Ask that party to wake us
595 	 * when it is done or it realizes it needs to back off.
596 	 */
597 	ret = ww_mutex_lock_wait_sig(mutex, ctx);
598 	if (ret)
599 		goto out;
600 
601 locked:	KASSERT((mutex->wwm_state == WW_CTX) ||
602 	    (mutex->wwm_state == WW_WANTOWN));
603 	KASSERT(mutex->wwm_u.ctx == ctx);
604 	WW_LOCKED(mutex);
605 	ctx->wwx_acquired++;
606 	ret = 0;
607 out:	mutex_exit(&mutex->wwm_lock);
608 	return ret;
609 }
610 
611 void
612 ww_mutex_lock_slow(struct ww_mutex *mutex, struct ww_acquire_ctx *ctx)
613 {
614 
615 	/* Caller must not try to lock against self here.  */
616 	WW_WANTLOCK(mutex);
617 	ASSERT_SLEEPABLE();
618 
619 	if (ctx == NULL) {
620 		ww_mutex_lock_noctx(mutex);
621 		return;
622 	}
623 
624 	KASSERTMSG((ctx->wwx_owner == curlwp),
625 	    "ctx %p owned by %p, not self (%p)", ctx, ctx->wwx_owner, curlwp);
626 	KASSERTMSG(!ctx->wwx_acquire_done,
627 	    "ctx %p done acquiring locks, can't acquire more", ctx);
628 	KASSERTMSG((ctx->wwx_acquired != ~0U),
629 	    "ctx %p finished, can't be used any more", ctx);
630 	KASSERTMSG((ctx->wwx_acquired == 0),
631 	    "ctx %p still holds %u locks, not allowed in slow path",
632 	    ctx, ctx->wwx_acquired);
633 	KASSERTMSG((ctx->wwx_class == mutex->wwm_class),
634 	    "ctx %p in class %p, mutex %p in class %p",
635 	    ctx, ctx->wwx_class, mutex, mutex->wwm_class);
636 
637 	mutex_enter(&mutex->wwm_lock);
638 retry:	switch (mutex->wwm_state) {
639 	case WW_UNLOCKED:
640 		mutex->wwm_state = WW_CTX;
641 		mutex->wwm_u.ctx = ctx;
642 		goto locked;
643 	case WW_OWNED:
644 		KASSERTMSG((mutex->wwm_u.owner != curlwp),
645 		    "locking %p against myself: %p", mutex, curlwp);
646 		ww_mutex_state_wait(mutex, WW_OWNED);
647 		goto retry;
648 	case WW_CTX:
649 		break;
650 	case WW_WANTOWN:
651 		ww_mutex_state_wait(mutex, WW_WANTOWN);
652 		goto retry;
653 	default:
654 		panic("wait/wound mutex %p in bad state: %d",
655 		    mutex, (int)mutex->wwm_state);
656 	}
657 
658 	KASSERT(mutex->wwm_state == WW_CTX);
659 	KASSERT(mutex->wwm_u.ctx != NULL);
660 	KASSERTMSG((mutex->wwm_u.ctx->wwx_owner != curlwp),
661 	    "locking %p against myself: %p", mutex, curlwp);
662 
663 	/*
664 	 * Owned by another party, of any priority.  Ask that party to
665 	 * wake us when it's done.
666 	 */
667 	ww_mutex_lock_wait(mutex, ctx);
668 
669 locked:	KASSERT((mutex->wwm_state == WW_CTX) ||
670 	    (mutex->wwm_state == WW_WANTOWN));
671 	KASSERT(mutex->wwm_u.ctx == ctx);
672 	WW_LOCKED(mutex);
673 	ctx->wwx_acquired++;
674 	mutex_exit(&mutex->wwm_lock);
675 }
676 
677 int
678 ww_mutex_lock_slow_interruptible(struct ww_mutex *mutex,
679     struct ww_acquire_ctx *ctx)
680 {
681 	int ret;
682 
683 	WW_WANTLOCK(mutex);
684 	ASSERT_SLEEPABLE();
685 
686 	if (ctx == NULL)
687 		return ww_mutex_lock_noctx_sig(mutex);
688 
689 	KASSERTMSG((ctx->wwx_owner == curlwp),
690 	    "ctx %p owned by %p, not self (%p)", ctx, ctx->wwx_owner, curlwp);
691 	KASSERTMSG(!ctx->wwx_acquire_done,
692 	    "ctx %p done acquiring locks, can't acquire more", ctx);
693 	KASSERTMSG((ctx->wwx_acquired != ~0U),
694 	    "ctx %p finished, can't be used any more", ctx);
695 	KASSERTMSG((ctx->wwx_acquired == 0),
696 	    "ctx %p still holds %u locks, not allowed in slow path",
697 	    ctx, ctx->wwx_acquired);
698 	KASSERTMSG((ctx->wwx_class == mutex->wwm_class),
699 	    "ctx %p in class %p, mutex %p in class %p",
700 	    ctx, ctx->wwx_class, mutex, mutex->wwm_class);
701 
702 	mutex_enter(&mutex->wwm_lock);
703 retry:	switch (mutex->wwm_state) {
704 	case WW_UNLOCKED:
705 		mutex->wwm_state = WW_CTX;
706 		mutex->wwm_u.ctx = ctx;
707 		goto locked;
708 	case WW_OWNED:
709 		KASSERTMSG((mutex->wwm_u.owner != curlwp),
710 		    "locking %p against myself: %p", mutex, curlwp);
711 		ret = ww_mutex_state_wait_sig(mutex, WW_OWNED);
712 		if (ret)
713 			goto out;
714 		goto retry;
715 	case WW_CTX:
716 		break;
717 	case WW_WANTOWN:
718 		ret = ww_mutex_state_wait_sig(mutex, WW_WANTOWN);
719 		if (ret)
720 			goto out;
721 		goto retry;
722 	default:
723 		panic("wait/wound mutex %p in bad state: %d",
724 		    mutex, (int)mutex->wwm_state);
725 	}
726 
727 	KASSERT(mutex->wwm_state == WW_CTX);
728 	KASSERT(mutex->wwm_u.ctx != NULL);
729 	KASSERTMSG((mutex->wwm_u.ctx->wwx_owner != curlwp),
730 	    "locking %p against myself: %p", mutex, curlwp);
731 
732 	/*
733 	 * Owned by another party, of any priority.  Ask that party to
734 	 * wake us when it's done.
735 	 */
736 	ret = ww_mutex_lock_wait_sig(mutex, ctx);
737 	if (ret)
738 		goto out;
739 
740 locked:	KASSERT((mutex->wwm_state == WW_CTX) ||
741 	    (mutex->wwm_state == WW_WANTOWN));
742 	KASSERT(mutex->wwm_u.ctx == ctx);
743 	WW_LOCKED(mutex);
744 	ctx->wwx_acquired++;
745 	ret = 0;
746 out:	mutex_exit(&mutex->wwm_lock);
747 	return ret;
748 }
749 
750 int
751 ww_mutex_trylock(struct ww_mutex *mutex)
752 {
753 	int ret;
754 
755 	mutex_enter(&mutex->wwm_lock);
756 	if (mutex->wwm_state == WW_UNLOCKED) {
757 		mutex->wwm_state = WW_OWNED;
758 		mutex->wwm_u.owner = curlwp;
759 		WW_WANTLOCK(mutex);
760 		WW_LOCKED(mutex);
761 		ret = 1;
762 	} else {
763 		KASSERTMSG(((mutex->wwm_state != WW_OWNED) ||
764 		    (mutex->wwm_u.owner != curlwp)),
765 		    "locking %p against myself: %p", mutex, curlwp);
766 		KASSERTMSG(((mutex->wwm_state != WW_CTX) ||
767 		    (mutex->wwm_u.ctx->wwx_owner != curlwp)),
768 		    "locking %p against myself: %p", mutex, curlwp);
769 		KASSERTMSG(((mutex->wwm_state != WW_WANTOWN) ||
770 		    (mutex->wwm_u.ctx->wwx_owner != curlwp)),
771 		    "locking %p against myself: %p", mutex, curlwp);
772 		ret = 0;
773 	}
774 	mutex_exit(&mutex->wwm_lock);
775 
776 	return ret;
777 }
778 
779 static void
780 ww_mutex_unlock_release(struct ww_mutex *mutex)
781 {
782 
783 	KASSERT(mutex_owned(&mutex->wwm_lock));
784 	KASSERT((mutex->wwm_state == WW_CTX) ||
785 	    (mutex->wwm_state == WW_WANTOWN));
786 	KASSERT(mutex->wwm_u.ctx != NULL);
787 	KASSERTMSG((mutex->wwm_u.ctx->wwx_owner == curlwp),
788 	    "ww_mutex %p ctx %p held by %p, not by self (%p)",
789 	    mutex, mutex->wwm_u.ctx, mutex->wwm_u.ctx->wwx_owner,
790 	    curlwp);
791 	KASSERT(mutex->wwm_u.ctx->wwx_acquired != ~0U);
792 	mutex->wwm_u.ctx->wwx_acquired--;
793 	mutex->wwm_u.ctx = NULL;
794 }
795 
796 void
797 ww_mutex_unlock(struct ww_mutex *mutex)
798 {
799 	struct ww_acquire_ctx *ctx;
800 
801 	mutex_enter(&mutex->wwm_lock);
802 	KASSERT(mutex->wwm_state != WW_UNLOCKED);
803 	switch (mutex->wwm_state) {
804 	case WW_UNLOCKED:
805 		panic("unlocking unlocked wait/wound mutex: %p", mutex);
806 	case WW_OWNED:
807 		/* Let the context lockers fight over it.  */
808 		mutex->wwm_u.owner = NULL;
809 		mutex->wwm_state = WW_UNLOCKED;
810 		break;
811 	case WW_CTX:
812 		ww_mutex_unlock_release(mutex);
813 		/*
814 		 * If there are any waiters with contexts, grant the
815 		 * lock to the highest-priority one.  Otherwise, just
816 		 * unlock it.
817 		 */
818 		if ((ctx = RB_TREE_MIN(&mutex->wwm_waiters)) != NULL) {
819 			mutex->wwm_state = WW_CTX;
820 			mutex->wwm_u.ctx = ctx;
821 		} else {
822 			mutex->wwm_state = WW_UNLOCKED;
823 		}
824 		break;
825 	case WW_WANTOWN:
826 		ww_mutex_unlock_release(mutex);
827 		/* Let the non-context lockers fight over it.  */
828 		mutex->wwm_state = WW_UNLOCKED;
829 		break;
830 	}
831 	WW_UNLOCKED(mutex);
832 	cv_broadcast(&mutex->wwm_cv);
833 	mutex_exit(&mutex->wwm_lock);
834 }
835