Module Name:    src
Committed By:   riastradh
Date:           Thu Jan  8 23:35:47 UTC 2015

Modified Files:
        src/sys/external/bsd/drm2/include/linux: ww_mutex.h
        src/sys/external/bsd/drm2/linux: files.drmkms_linux
        src/sys/modules/drmkms_linux: Makefile
Added Files:
        src/sys/external/bsd/drm2/linux: linux_ww_mutex.c

Log Message:
Move Linux ww_mutex code into a .c file where it belongs.


To generate a diff of this commit:
cvs rdiff -u -r1.9 -r1.10 src/sys/external/bsd/drm2/include/linux/ww_mutex.h
cvs rdiff -u -r1.7 -r1.8 src/sys/external/bsd/drm2/linux/files.drmkms_linux
cvs rdiff -u -r0 -r1.1 src/sys/external/bsd/drm2/linux/linux_ww_mutex.c
cvs rdiff -u -r1.5 -r1.6 src/sys/modules/drmkms_linux/Makefile

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/external/bsd/drm2/include/linux/ww_mutex.h
diff -u src/sys/external/bsd/drm2/include/linux/ww_mutex.h:1.9 src/sys/external/bsd/drm2/include/linux/ww_mutex.h:1.10
--- src/sys/external/bsd/drm2/include/linux/ww_mutex.h:1.9	Thu Jan  1 01:15:42 2015
+++ src/sys/external/bsd/drm2/include/linux/ww_mutex.h	Thu Jan  8 23:35:47 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: ww_mutex.h,v 1.9 2015/01/01 01:15:42 mrg Exp $	*/
+/*	$NetBSD: ww_mutex.h,v 1.10 2015/01/08 23:35:47 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -32,10 +32,11 @@
 #ifndef _ASM_WW_MUTEX_H_
 #define _ASM_WW_MUTEX_H_
 
+#include <sys/types.h>
+#include <sys/condvar.h>
+#include <sys/mutex.h>
 #include <sys/rbtree.h>
 
-#include <linux/mutex.h>
-
 struct ww_class {
 	volatile uint64_t	wwc_ticket;
 };
@@ -54,74 +55,6 @@ struct ww_acquire_ctx {
 	struct rb_node	wwx_rb_node;
 };
 
-static inline int
-ww_acquire_ctx_compare(void *cookie __unused, const void *va, const void *vb)
-{
-	const struct ww_acquire_ctx *const ctx_a = va;
-	const struct ww_acquire_ctx *const ctx_b = vb;
-
-	if (ctx_a->wwx_ticket < ctx_b->wwx_ticket)
-		return -1;
-	if (ctx_a->wwx_ticket > ctx_b->wwx_ticket)
-		return -1;
-	return 0;
-}
-
-static inline int
-ww_acquire_ctx_compare_key(void *cookie __unused, const void *vn,
-    const void *vk)
-{
-	const struct ww_acquire_ctx *const ctx = vn;
-	const uint64_t *const ticketp = vk, ticket = *ticketp;
-
-	if (ctx->wwx_ticket < ticket)
-		return -1;
-	if (ctx->wwx_ticket > ticket)
-		return -1;
-	return 0;
-}
-
-static const rb_tree_ops_t ww_acquire_ctx_rb_ops = {
-	.rbto_compare_nodes = &ww_acquire_ctx_compare,
-	.rbto_compare_key = &ww_acquire_ctx_compare_key,
-	.rbto_node_offset = offsetof(struct ww_acquire_ctx, wwx_rb_node),
-	.rbto_context = NULL,
-};
-
-static inline void
-ww_acquire_init(struct ww_acquire_ctx *ctx, struct ww_class *class)
-{
-
-	ctx->wwx_class = class;
-	ctx->wwx_owner = curlwp;
-	ctx->wwx_ticket = atomic_inc_64_nv(&class->wwc_ticket);
-	ctx->wwx_acquired = 0;
-	ctx->wwx_acquire_done = false;
-}
-
-static inline void
-ww_acquire_done(struct ww_acquire_ctx *ctx)
-{
-
-	KASSERTMSG((ctx->wwx_owner == curlwp),
-	    "ctx %p owned by %p, not self (%p)", ctx, ctx->wwx_owner, curlwp);
-
-	ctx->wwx_acquire_done = true;
-}
-
-static inline void
-ww_acquire_fini(struct ww_acquire_ctx *ctx)
-{
-
-	KASSERTMSG((ctx->wwx_owner == curlwp),
-	    "ctx %p owned by %p, not self (%p)", ctx, ctx->wwx_owner, curlwp);
-	KASSERTMSG((ctx->wwx_acquired == 0), "ctx %p still holds %u locks",
-	    ctx, ctx->wwx_acquired);
-
-	ctx->wwx_acquired = ~0U;	/* Fail if called again. */
-	ctx->wwx_owner = NULL;
-}
-
 struct ww_mutex {
 	kmutex_t		wwm_lock;
 	enum ww_mutex_state {
@@ -139,601 +72,41 @@ struct ww_mutex {
 	kcondvar_t		wwm_cv;
 };
 
-static inline void
-ww_mutex_init(struct ww_mutex *mutex, struct ww_class *class)
-{
-
-	/*
-	 * XXX Apparently Linux takes these with spin locks held.  That
-	 * strikes me as a bad idea, but so it is...
-	 */
-	mutex_init(&mutex->wwm_lock, MUTEX_DEFAULT, IPL_VM);
-	mutex->wwm_state = WW_UNLOCKED;
-	mutex->wwm_class = class;
-	rb_tree_init(&mutex->wwm_waiters, &ww_acquire_ctx_rb_ops);
-	cv_init(&mutex->wwm_cv, "linuxwwm");
-}
-
-static inline void
-ww_mutex_destroy(struct ww_mutex *mutex)
-{
-
-	cv_destroy(&mutex->wwm_cv);
-#if 0
-	rb_tree_destroy(&mutex->wwm_waiters, &ww_acquire_ctx_rb_ops);
-#endif
-	KASSERT(mutex->wwm_state == WW_UNLOCKED);
-	mutex_destroy(&mutex->wwm_lock);
-}
+/* XXX Make the nm output a little more greppable...  */
+#define	ww_acquire_done		linux_ww_acquire_done
+#define	ww_acquire_fini		linux_ww_acquire_fini
+#define	ww_acquire_init		linux_ww_acquire_init
+#define	ww_mutex_destroy	linux_ww_mutex_destroy
+#define	ww_mutex_init		linux_ww_mutex_init
+#define	ww_mutex_is_locked	linux_ww_mutex_is_locked
+#define	ww_mutex_lock		linux_ww_mutex_lock
+#define	ww_mutex_lock_interruptible linux_ww_mutex_lock_interruptible
+#define	ww_mutex_lock_slow	linux_ww_mutex_lock_slow
+#define	ww_mutex_lock_slow_interruptible linux_ww_mutex_lock_slow_interruptible
+#define	ww_mutex_trylock	linux_ww_mutex_trylock
+#define	ww_mutex_unlock		linux_ww_mutex_unlock
+
+void	ww_acquire_init(struct ww_acquire_ctx *, struct ww_class *);
+void	ww_acquire_done(struct ww_acquire_ctx *);
+void	ww_acquire_fini(struct ww_acquire_ctx *);
+
+void	ww_mutex_init(struct ww_mutex *, struct ww_class *);
+void	ww_mutex_destroy(struct ww_mutex *);
 
 /*
- * XXX WARNING: This returns true if it is locked by ANYONE.  Does not
- * mean `Do I hold this lock?' (answering which really requires an
- * acquire context).
+ * WARNING: ww_mutex_is_locked returns true if it is locked by ANYONE.
+ * Does NOT mean `Do I hold this lock?' (answering which really
+ * requires an acquire context).
  */
-static inline bool
-ww_mutex_is_locked(struct ww_mutex *mutex)
-{
-	int locked;
-
-	mutex_enter(&mutex->wwm_lock);
-	switch (mutex->wwm_state) {
-	case WW_UNLOCKED:
-		locked = false;
-		break;
-	case WW_OWNED:
-	case WW_CTX:
-	case WW_WANTOWN:
-		locked = true;
-		break;
-	default:
-		panic("wait/wound mutex %p in bad state: %d", mutex,
-		    (int)mutex->wwm_state);
-	}
-	mutex_exit(&mutex->wwm_lock);
+bool	ww_mutex_is_locked(struct ww_mutex *);
 
-	return locked;
-}
-
-static inline void
-ww_mutex_state_wait(struct ww_mutex *mutex, enum ww_mutex_state state)
-{
-
-	KASSERT(mutex->wwm_state == state);
-	do cv_wait(&mutex->wwm_cv, &mutex->wwm_lock);
-	while (mutex->wwm_state == state);
-}
-
-static inline int
-ww_mutex_state_wait_sig(struct ww_mutex *mutex, enum ww_mutex_state state)
-{
-	int ret;
-
-	KASSERT(mutex->wwm_state == state);
-	do {
-		/* XXX errno NetBSD->Linux */
-		ret = -cv_wait_sig(&mutex->wwm_cv, &mutex->wwm_lock);
-		if (ret)
-			break;
-	} while (mutex->wwm_state == state);
-
-	return ret;
-}
-
-static inline void
-ww_mutex_lock_wait(struct ww_mutex *mutex, struct ww_acquire_ctx *ctx)
-{
-	struct ww_acquire_ctx *collision __diagused;
-
-	KASSERT(mutex_owned(&mutex->wwm_lock));
-
-	KASSERT((mutex->wwm_state == WW_CTX) ||
-	    (mutex->wwm_state == WW_WANTOWN));
-	KASSERT(mutex->wwm_u.ctx != ctx);
-	KASSERTMSG((ctx->wwx_class == mutex->wwm_u.ctx->wwx_class),
-	    "ww mutex class mismatch: %p != %p",
-	    ctx->wwx_class, mutex->wwm_u.ctx->wwx_class);
-	KASSERTMSG((mutex->wwm_u.ctx->wwx_ticket != ctx->wwx_ticket),
-	    "ticket number reused: %"PRId64" (%p) %"PRId64" (%p)",
-	    ctx->wwx_ticket, ctx,
-	    mutex->wwm_u.ctx->wwx_ticket, mutex->wwm_u.ctx);
-
-	collision = rb_tree_insert_node(&mutex->wwm_waiters, ctx);
-	KASSERTMSG((collision == ctx),
-	    "ticket number reused: %"PRId64" (%p) %"PRId64" (%p)",
-	    ctx->wwx_ticket, ctx, collision->wwx_ticket, collision);
-
-	do cv_wait(&mutex->wwm_cv, &mutex->wwm_lock);
-	while (!(((mutex->wwm_state == WW_CTX) ||
-		    (mutex->wwm_state == WW_WANTOWN)) &&
-		 (mutex->wwm_u.ctx == ctx)));
-
-	rb_tree_remove_node(&mutex->wwm_waiters, ctx);
-}
-
-static inline int
-ww_mutex_lock_wait_sig(struct ww_mutex *mutex, struct ww_acquire_ctx *ctx)
-{
-	struct ww_acquire_ctx *collision __diagused;
-	int ret;
-
-	KASSERT(mutex_owned(&mutex->wwm_lock));
-
-	KASSERT((mutex->wwm_state == WW_CTX) ||
-	    (mutex->wwm_state == WW_WANTOWN));
-	KASSERT(mutex->wwm_u.ctx != ctx);
-	KASSERTMSG((ctx->wwx_class == mutex->wwm_u.ctx->wwx_class),
-	    "ww mutex class mismatch: %p != %p",
-	    ctx->wwx_class, mutex->wwm_u.ctx->wwx_class);
-	KASSERTMSG((mutex->wwm_u.ctx->wwx_ticket != ctx->wwx_ticket),
-	    "ticket number reused: %"PRId64" (%p) %"PRId64" (%p)",
-	    ctx->wwx_ticket, ctx,
-	    mutex->wwm_u.ctx->wwx_ticket, mutex->wwm_u.ctx);
-
-	collision = rb_tree_insert_node(&mutex->wwm_waiters, ctx);
-	KASSERTMSG((collision == ctx),
-	    "ticket number reused: %"PRId64" (%p) %"PRId64" (%p)",
-	    ctx->wwx_ticket, ctx, collision->wwx_ticket, collision);
-
-	do {
-		/* XXX errno NetBSD->Linux */
-		ret = -cv_wait_sig(&mutex->wwm_cv, &mutex->wwm_lock);
-		if (ret)
-			goto out;
-	} while (!(((mutex->wwm_state == WW_CTX) ||
-		    (mutex->wwm_state == WW_WANTOWN)) &&
-		(mutex->wwm_u.ctx == ctx)));
-
-out:	rb_tree_remove_node(&mutex->wwm_waiters, ctx);
-	return ret;
-}
-
-static inline void
-ww_mutex_lock_noctx(struct ww_mutex *mutex)
-{
-
-	mutex_enter(&mutex->wwm_lock);
-retry:	switch (mutex->wwm_state) {
-	case WW_UNLOCKED:
-		mutex->wwm_state = WW_OWNED;
-		mutex->wwm_u.owner = curlwp;
-		break;
-	case WW_OWNED:
-		KASSERTMSG((mutex->wwm_u.owner != curlwp),
-		    "locking %p against myself: %p", mutex, curlwp);
-		ww_mutex_state_wait(mutex, WW_OWNED);
-		goto retry;
-	case WW_CTX:
-		KASSERT(mutex->wwm_u.ctx != NULL);
-		mutex->wwm_state = WW_WANTOWN;
-		/* FALLTHROUGH */
-	case WW_WANTOWN:
-		KASSERTMSG((mutex->wwm_u.ctx->wwx_owner != curlwp),
-		    "locking %p against myself: %p", mutex, curlwp);
-		ww_mutex_state_wait(mutex, WW_WANTOWN);
-		goto retry;
-	default:
-		panic("wait/wound mutex %p in bad state: %d",
-		    mutex, (int)mutex->wwm_state);
-	}
-	KASSERT(mutex->wwm_state == WW_OWNED);
-	KASSERT(mutex->wwm_u.owner == curlwp);
-	mutex_exit(&mutex->wwm_lock);
-}
-
-static inline int
-ww_mutex_lock_noctx_sig(struct ww_mutex *mutex)
-{
-	int ret;
-
-	mutex_enter(&mutex->wwm_lock);
-retry:	switch (mutex->wwm_state) {
-	case WW_UNLOCKED:
-		mutex->wwm_state = WW_OWNED;
-		mutex->wwm_u.owner = curlwp;
-		break;
-	case WW_OWNED:
-		KASSERTMSG((mutex->wwm_u.owner != curlwp),
-		    "locking %p against myself: %p", mutex, curlwp);
-		ret = ww_mutex_state_wait_sig(mutex, WW_OWNED);
-		if (ret)
-			goto out;
-		goto retry;
-	case WW_CTX:
-		KASSERT(mutex->wwm_u.ctx != NULL);
-		mutex->wwm_state = WW_WANTOWN;
-		/* FALLTHROUGH */
-	case WW_WANTOWN:
-		KASSERTMSG((mutex->wwm_u.ctx->wwx_owner != curlwp),
-		    "locking %p against myself: %p", mutex, curlwp);
-		ret = ww_mutex_state_wait_sig(mutex, WW_WANTOWN);
-		if (ret)
-			goto out;
-		goto retry;
-	default:
-		panic("wait/wound mutex %p in bad state: %d",
-		    mutex, (int)mutex->wwm_state);
-	}
-	KASSERT(mutex->wwm_state == WW_OWNED);
-	KASSERT(mutex->wwm_u.owner == curlwp);
-	ret = 0;
-out:	mutex_exit(&mutex->wwm_lock);
-	return ret;
-}
-
-static inline int
-ww_mutex_lock(struct ww_mutex *mutex, struct ww_acquire_ctx *ctx)
-{
-
-	ASSERT_SLEEPABLE();
-
-	if (ctx == NULL) {
-		ww_mutex_lock_noctx(mutex);
-		return 0;
-	}
-
-	KASSERTMSG((ctx->wwx_owner == curlwp),
-	    "ctx %p owned by %p, not self (%p)", ctx, ctx->wwx_owner, curlwp);
-	KASSERTMSG(!ctx->wwx_acquire_done,
-	    "ctx %p done acquiring locks, can't acquire more", ctx);
-	KASSERTMSG((ctx->wwx_acquired != ~0U),
-	    "ctx %p finished, can't be used any more", ctx);
-	KASSERTMSG((ctx->wwx_class == mutex->wwm_class),
-	    "ctx %p in class %p, mutex %p in class %p",
-	    ctx, ctx->wwx_class, mutex, mutex->wwm_class);
-
-	mutex_enter(&mutex->wwm_lock);
-retry:	switch (mutex->wwm_state) {
-	case WW_UNLOCKED:
-		mutex->wwm_state = WW_CTX;
-		mutex->wwm_u.ctx = ctx;
-		goto locked;
-	case WW_OWNED:
-		KASSERTMSG((mutex->wwm_u.owner != curlwp),
-		    "locking %p against myself: %p", mutex, curlwp);
-		ww_mutex_state_wait(mutex, WW_OWNED);
-		goto retry;
-	case WW_CTX:
-		break;
-	case WW_WANTOWN:
-		ww_mutex_state_wait(mutex, WW_WANTOWN);
-		goto retry;
-	default:
-		panic("wait/wound mutex %p in bad state: %d",
-		    mutex, (int)mutex->wwm_state);
-	}
-	KASSERT(mutex->wwm_state == WW_CTX);
-	KASSERT(mutex->wwm_u.ctx != NULL);
-	KASSERT((mutex->wwm_u.ctx == ctx) ||
-	    (mutex->wwm_u.ctx->wwx_owner != curlwp));
-	if (mutex->wwm_u.ctx == ctx) {
-		/*
-		 * We already own it.  Yes, this can happen correctly
-		 * for objects whose locking order is determined by
-		 * userland.
-		 */
-		mutex_exit(&mutex->wwm_lock);
-		return -EALREADY;
-	} else if (mutex->wwm_u.ctx->wwx_ticket < ctx->wwx_ticket) {
-		/*
-		 * Owned by a higher-priority party.  Tell the caller
-		 * to unlock everything and start over.
-		 */
-		KASSERTMSG((ctx->wwx_class == mutex->wwm_u.ctx->wwx_class),
-		    "ww mutex class mismatch: %p != %p",
-		    ctx->wwx_class, mutex->wwm_u.ctx->wwx_class);
-		mutex_exit(&mutex->wwm_lock);
-		return -EDEADLK;
-	} else {
-		/*
-		 * Owned by a lower-priority party.  Ask that party to
-		 * wake us when it is done or it realizes it needs to
-		 * back off.
-		 */
-		ww_mutex_lock_wait(mutex, ctx);
-	}
-locked:	ctx->wwx_acquired++;
-	KASSERT((mutex->wwm_state == WW_CTX) ||
-	    (mutex->wwm_state == WW_WANTOWN));
-	KASSERT(mutex->wwm_u.ctx == ctx);
-	mutex_exit(&mutex->wwm_lock);
-	return 0;
-}
-
-static inline int
-ww_mutex_lock_interruptible(struct ww_mutex *mutex, struct ww_acquire_ctx *ctx)
-{
-	int ret;
-
-	ASSERT_SLEEPABLE();
-
-	if (ctx == NULL)
-		return ww_mutex_lock_noctx_sig(mutex);
-
-	KASSERTMSG((ctx->wwx_owner == curlwp),
-	    "ctx %p owned by %p, not self (%p)", ctx, ctx->wwx_owner, curlwp);
-	KASSERTMSG(!ctx->wwx_acquire_done,
-	    "ctx %p done acquiring locks, can't acquire more", ctx);
-	KASSERTMSG((ctx->wwx_acquired != ~0U),
-	    "ctx %p finished, can't be used any more", ctx);
-	KASSERTMSG((ctx->wwx_class == mutex->wwm_class),
-	    "ctx %p in class %p, mutex %p in class %p",
-	    ctx, ctx->wwx_class, mutex, mutex->wwm_class);
-
-	mutex_enter(&mutex->wwm_lock);
-retry:	switch (mutex->wwm_state) {
-	case WW_UNLOCKED:
-		mutex->wwm_state = WW_CTX;
-		mutex->wwm_u.ctx = ctx;
-		goto locked;
-	case WW_OWNED:
-		KASSERTMSG((mutex->wwm_u.owner != curlwp),
-		    "locking %p against myself: %p", mutex, curlwp);
-		ret = ww_mutex_state_wait_sig(mutex, WW_OWNED);
-		if (ret)
-			goto out;
-		goto retry;
-	case WW_CTX:
-		break;
-	case WW_WANTOWN:
-		ret = ww_mutex_state_wait_sig(mutex, WW_WANTOWN);
-		if (ret)
-			goto out;
-		goto retry;
-	default:
-		panic("wait/wound mutex %p in bad state: %d",
-		    mutex, (int)mutex->wwm_state);
-	}
-	KASSERT(mutex->wwm_state == WW_CTX);
-	KASSERT(mutex->wwm_u.ctx != NULL);
-	KASSERT((mutex->wwm_u.ctx == ctx) ||
-	    (mutex->wwm_u.ctx->wwx_owner != curlwp));
-	if (mutex->wwm_u.ctx == ctx) {
-		/*
-		 * We already own it.  Yes, this can happen correctly
-		 * for objects whose locking order is determined by
-		 * userland.
-		 */
-		mutex_exit(&mutex->wwm_lock);
-		return -EALREADY;
-	} else if (mutex->wwm_u.ctx->wwx_ticket < ctx->wwx_ticket) {
-		/*
-		 * Owned by a higher-priority party.  Tell the caller
-		 * to unlock everything and start over.
-		 */
-		KASSERTMSG((ctx->wwx_class == mutex->wwm_u.ctx->wwx_class),
-		    "ww mutex class mismatch: %p != %p",
-		    ctx->wwx_class, mutex->wwm_u.ctx->wwx_class);
-		mutex_exit(&mutex->wwm_lock);
-		return -EDEADLK;
-	} else {
-		/*
-		 * Owned by a lower-priority party.  Ask that party to
-		 * wake us when it is done or it realizes it needs to
-		 * back off.
-		 */
-		ret = ww_mutex_lock_wait_sig(mutex, ctx);
-		if (ret)
-			goto out;
-	}
-locked:	KASSERT((mutex->wwm_state == WW_CTX) ||
-	    (mutex->wwm_state == WW_WANTOWN));
-	KASSERT(mutex->wwm_u.ctx == ctx);
-	ctx->wwx_acquired++;
-	ret = 0;
-out:	mutex_exit(&mutex->wwm_lock);
-	return ret;
-}
-
-static inline void
-ww_mutex_lock_slow(struct ww_mutex *mutex, struct ww_acquire_ctx *ctx)
-{
-
-	ASSERT_SLEEPABLE();
-
-	if (ctx == NULL) {
-		ww_mutex_lock_noctx(mutex);
-		return;
-	}
-
-	KASSERTMSG((ctx->wwx_owner == curlwp),
-	    "ctx %p owned by %p, not self (%p)", ctx, ctx->wwx_owner, curlwp);
-	KASSERTMSG(!ctx->wwx_acquire_done,
-	    "ctx %p done acquiring locks, can't acquire more", ctx);
-	KASSERTMSG((ctx->wwx_acquired != ~0U),
-	    "ctx %p finished, can't be used any more", ctx);
-	KASSERTMSG((ctx->wwx_acquired == 0),
-	    "ctx %p still holds %u locks, not allowed in slow path",
-	    ctx, ctx->wwx_acquired);
-	KASSERTMSG((ctx->wwx_class == mutex->wwm_class),
-	    "ctx %p in class %p, mutex %p in class %p",
-	    ctx, ctx->wwx_class, mutex, mutex->wwm_class);
-
-	mutex_enter(&mutex->wwm_lock);
-retry:	switch (mutex->wwm_state) {
-	case WW_UNLOCKED:
-		mutex->wwm_state = WW_CTX;
-		mutex->wwm_u.ctx = ctx;
-		goto locked;
-	case WW_OWNED:
-		KASSERTMSG((mutex->wwm_u.owner != curlwp),
-		    "locking %p against myself: %p", mutex, curlwp);
-		ww_mutex_state_wait(mutex, WW_OWNED);
-		goto retry;
-	case WW_CTX:
-		break;
-	case WW_WANTOWN:
-		ww_mutex_state_wait(mutex, WW_WANTOWN);
-		goto retry;
-	default:
-		panic("wait/wound mutex %p in bad state: %d",
-		    mutex, (int)mutex->wwm_state);
-	}
-	KASSERT(mutex->wwm_state == WW_CTX);
-	KASSERT(mutex->wwm_u.ctx != NULL);
-	KASSERTMSG((mutex->wwm_u.ctx->wwx_owner != curlwp),
-	    "locking %p against myself: %p", mutex, curlwp);
-	/*
-	 * Owned by another party, of any priority.  Ask that party to
-	 * wake us when it's done.
-	 */
-	ww_mutex_lock_wait(mutex, ctx);
-locked:	KASSERT((mutex->wwm_state == WW_CTX) ||
-	    (mutex->wwm_state == WW_WANTOWN));
-	KASSERT(mutex->wwm_u.ctx == ctx);
-	ctx->wwx_acquired++;
-	mutex_exit(&mutex->wwm_lock);
-}
-
-static inline int
-ww_mutex_lock_slow_interruptible(struct ww_mutex *mutex,
-    struct ww_acquire_ctx *ctx)
-{
-	int ret;
-
-	ASSERT_SLEEPABLE();
-
-	if (ctx == NULL)
-		return ww_mutex_lock_noctx_sig(mutex);
-
-	KASSERTMSG((ctx->wwx_owner == curlwp),
-	    "ctx %p owned by %p, not self (%p)", ctx, ctx->wwx_owner, curlwp);
-	KASSERTMSG(!ctx->wwx_acquire_done,
-	    "ctx %p done acquiring locks, can't acquire more", ctx);
-	KASSERTMSG((ctx->wwx_acquired != ~0U),
-	    "ctx %p finished, can't be used any more", ctx);
-	KASSERTMSG((ctx->wwx_acquired == 0),
-	    "ctx %p still holds %u locks, not allowed in slow path",
-	    ctx, ctx->wwx_acquired);
-	KASSERTMSG((ctx->wwx_class == mutex->wwm_class),
-	    "ctx %p in class %p, mutex %p in class %p",
-	    ctx, ctx->wwx_class, mutex, mutex->wwm_class);
-
-	mutex_enter(&mutex->wwm_lock);
-retry:	switch (mutex->wwm_state) {
-	case WW_UNLOCKED:
-		mutex->wwm_state = WW_CTX;
-		mutex->wwm_u.ctx = ctx;
-		goto locked;
-	case WW_OWNED:
-		KASSERTMSG((mutex->wwm_u.owner != curlwp),
-		    "locking %p against myself: %p", mutex, curlwp);
-		ret = ww_mutex_state_wait_sig(mutex, WW_OWNED);
-		if (ret)
-			goto out;
-		goto retry;
-	case WW_CTX:
-		break;
-	case WW_WANTOWN:
-		ret = ww_mutex_state_wait_sig(mutex, WW_WANTOWN);
-		if (ret)
-			goto out;
-		goto retry;
-	default:
-		panic("wait/wound mutex %p in bad state: %d",
-		    mutex, (int)mutex->wwm_state);
-	}
-	KASSERT(mutex->wwm_state == WW_CTX);
-	KASSERT(mutex->wwm_u.ctx != NULL);
-	KASSERTMSG((mutex->wwm_u.ctx->wwx_owner != curlwp),
-	    "locking %p against myself: %p", mutex, curlwp);
-	/*
-	 * Owned by another party, of any priority.  Ask that party to
-	 * wake us when it's done.
-	 */
-	ret = ww_mutex_lock_wait_sig(mutex, ctx);
-	if (ret)
-		goto out;
-locked:	KASSERT((mutex->wwm_state == WW_CTX) ||
-	    (mutex->wwm_state == WW_WANTOWN));
-	KASSERT(mutex->wwm_u.ctx == ctx);
-	ctx->wwx_acquired++;
-	ret = 0;
-out:	mutex_exit(&mutex->wwm_lock);
-	return ret;
-}
-
-static inline int
-ww_mutex_trylock(struct ww_mutex *mutex)
-{
-	int ret;
-
-	mutex_enter(&mutex->wwm_lock);
-	if (mutex->wwm_state == WW_UNLOCKED) {
-		mutex->wwm_state = WW_OWNED;
-		mutex->wwm_u.owner = curlwp;
-		ret = 1;
-	} else {
-		KASSERTMSG(((mutex->wwm_state != WW_OWNED) ||
-		    (mutex->wwm_u.owner != curlwp)),
-		    "locking %p against myself: %p", mutex, curlwp);
-		KASSERTMSG(((mutex->wwm_state != WW_CTX) ||
-		    (mutex->wwm_u.ctx->wwx_owner != curlwp)),
-		    "locking %p against myself: %p", mutex, curlwp);
-		KASSERTMSG(((mutex->wwm_state != WW_WANTOWN) ||
-		    (mutex->wwm_u.ctx->wwx_owner != curlwp)),
-		    "locking %p against myself: %p", mutex, curlwp);
-		ret = 0;
-	}
-	mutex_exit(&mutex->wwm_lock);
-
-	return ret;
-}
-
-static inline void
-ww_mutex_unlock_release(struct ww_mutex *mutex)
-{
-
-	KASSERT(mutex_owned(&mutex->wwm_lock));
-	KASSERT((mutex->wwm_state == WW_CTX) ||
-	    (mutex->wwm_state == WW_WANTOWN));
-	KASSERT(mutex->wwm_u.ctx != NULL);
-	KASSERTMSG((mutex->wwm_u.ctx->wwx_owner == curlwp),
-	    "ww_mutex %p ctx %p held by %p, not by self (%p)",
-	    mutex, mutex->wwm_u.ctx, mutex->wwm_u.ctx->wwx_owner,
-	    curlwp);
-	KASSERT(mutex->wwm_u.ctx->wwx_acquired != ~0U);
-	mutex->wwm_u.ctx->wwx_acquired--;
-	mutex->wwm_u.ctx = NULL;
-}
-
-static inline void
-ww_mutex_unlock(struct ww_mutex *mutex)
-{
-	struct ww_acquire_ctx *ctx;
-
-	mutex_enter(&mutex->wwm_lock);
-	KASSERT(mutex->wwm_state != WW_UNLOCKED);
-	switch (mutex->wwm_state) {
-	case WW_UNLOCKED:
-		panic("unlocking unlocked wait/wound mutex: %p", mutex);
-	case WW_OWNED:
-		/* Let the context lockers fight over it.  */
-		mutex->wwm_u.owner = NULL;
-		mutex->wwm_state = WW_UNLOCKED;
-		break;
-	case WW_CTX:
-		ww_mutex_unlock_release(mutex);
-		/*
-		 * If there are any waiters with contexts, grant the
-		 * lock to the highest-priority one.  Otherwise, just
-		 * unlock it.
-		 */
-		if ((ctx = RB_TREE_MIN(&mutex->wwm_waiters)) != NULL) {
-			mutex->wwm_state = WW_CTX;
-			mutex->wwm_u.ctx = ctx;
-		} else {
-			mutex->wwm_state = WW_UNLOCKED;
-		}
-		break;
-	case WW_WANTOWN:
-		ww_mutex_unlock_release(mutex);
-		/* Let the non-context lockers fight over it.  */
-		mutex->wwm_state = WW_UNLOCKED;
-		break;
-	}
-	cv_broadcast(&mutex->wwm_cv);
-	mutex_exit(&mutex->wwm_lock);
-}
+int	ww_mutex_lock(struct ww_mutex *, struct ww_acquire_ctx *);
+int	ww_mutex_lock_interruptible(struct ww_mutex *,
+	    struct ww_acquire_ctx *);
+void	ww_mutex_lock_slow(struct ww_mutex *, struct ww_acquire_ctx *);
+int	ww_mutex_lock_slow_interruptible(struct ww_mutex *,
+	    struct ww_acquire_ctx *);
+int	ww_mutex_trylock(struct ww_mutex *);
+void	ww_mutex_unlock(struct ww_mutex *);
 
 #endif  /* _ASM_WW_MUTEX_H_ */

Index: src/sys/external/bsd/drm2/linux/files.drmkms_linux
diff -u src/sys/external/bsd/drm2/linux/files.drmkms_linux:1.7 src/sys/external/bsd/drm2/linux/files.drmkms_linux:1.8
--- src/sys/external/bsd/drm2/linux/files.drmkms_linux:1.7	Thu Jul 17 13:52:22 2014
+++ src/sys/external/bsd/drm2/linux/files.drmkms_linux	Thu Jan  8 23:35:47 2015
@@ -1,4 +1,4 @@
-#       $NetBSD: files.drmkms_linux,v 1.7 2014/07/17 13:52:22 riastradh Exp $
+#       $NetBSD: files.drmkms_linux,v 1.8 2015/01/08 23:35:47 riastradh Exp $
 
 define	drmkms_linux: i2cexec, i2c_bitbang
 
@@ -13,3 +13,4 @@ file	external/bsd/drm2/linux/linux_list_
 file	external/bsd/drm2/linux/linux_module.c		drmkms_linux
 file	external/bsd/drm2/linux/linux_work.c		drmkms_linux
 file	external/bsd/drm2/linux/linux_writecomb.c	drmkms_linux
+file	external/bsd/drm2/linux/linux_ww_mutex.c	drmkms_linux

Index: src/sys/modules/drmkms_linux/Makefile
diff -u src/sys/modules/drmkms_linux/Makefile:1.5 src/sys/modules/drmkms_linux/Makefile:1.6
--- src/sys/modules/drmkms_linux/Makefile:1.5	Sun Sep 14 20:09:18 2014
+++ src/sys/modules/drmkms_linux/Makefile	Thu Jan  8 23:35:47 2015
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile,v 1.5 2014/09/14 20:09:18 riastradh Exp $
+# $NetBSD: Makefile,v 1.6 2015/01/08 23:35:47 riastradh Exp $
 
 .include "../Makefile.inc"
 
@@ -20,5 +20,6 @@ SRCS+=	linux_list_sort.c
 SRCS+=	linux_module.c
 SRCS+=	linux_work.c
 SRCS+=	linux_writecomb.c
+SRCS+=	linux_ww_mutex.c
 
 .include <bsd.kmodule.mk>

Added files:

Index: src/sys/external/bsd/drm2/linux/linux_ww_mutex.c
diff -u /dev/null src/sys/external/bsd/drm2/linux/linux_ww_mutex.c:1.1
--- /dev/null	Thu Jan  8 23:35:47 2015
+++ src/sys/external/bsd/drm2/linux/linux_ww_mutex.c	Thu Jan  8 23:35:47 2015
@@ -0,0 +1,707 @@
+/*	$NetBSD: linux_ww_mutex.c,v 1.1 2015/01/08 23:35:47 riastradh Exp $	*/
+
+/*-
+ * Copyright (c) 2014 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Taylor R. Campbell.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: linux_ww_mutex.c,v 1.1 2015/01/08 23:35:47 riastradh Exp $");
+
+#include <sys/types.h>
+#include <sys/atomic.h>
+#include <sys/condvar.h>
+#include <sys/lwp.h>
+#include <sys/mutex.h>
+#include <sys/rbtree.h>
+
+#include <linux/ww_mutex.h>
+
+static int
+ww_acquire_ctx_compare(void *cookie __unused, const void *va, const void *vb)
+{
+	const struct ww_acquire_ctx *const ctx_a = va;
+	const struct ww_acquire_ctx *const ctx_b = vb;
+
+	if (ctx_a->wwx_ticket < ctx_b->wwx_ticket)
+		return -1;
+	if (ctx_a->wwx_ticket > ctx_b->wwx_ticket)
+		return -1;
+	return 0;
+}
+
+static int
+ww_acquire_ctx_compare_key(void *cookie __unused, const void *vn,
+    const void *vk)
+{
+	const struct ww_acquire_ctx *const ctx = vn;
+	const uint64_t *const ticketp = vk, ticket = *ticketp;
+
+	if (ctx->wwx_ticket < ticket)
+		return -1;
+	if (ctx->wwx_ticket > ticket)
+		return -1;
+	return 0;
+}
+
+static const rb_tree_ops_t ww_acquire_ctx_rb_ops = {
+	.rbto_compare_nodes = &ww_acquire_ctx_compare,
+	.rbto_compare_key = &ww_acquire_ctx_compare_key,
+	.rbto_node_offset = offsetof(struct ww_acquire_ctx, wwx_rb_node),
+	.rbto_context = NULL,
+};
+
+void
+ww_acquire_init(struct ww_acquire_ctx *ctx, struct ww_class *class)
+{
+
+	ctx->wwx_class = class;
+	ctx->wwx_owner = curlwp;
+	ctx->wwx_ticket = atomic_inc_64_nv(&class->wwc_ticket);
+	ctx->wwx_acquired = 0;
+	ctx->wwx_acquire_done = false;
+}
+
+void
+ww_acquire_done(struct ww_acquire_ctx *ctx)
+{
+
+	KASSERTMSG((ctx->wwx_owner == curlwp),
+	    "ctx %p owned by %p, not self (%p)", ctx, ctx->wwx_owner, curlwp);
+
+	ctx->wwx_acquire_done = true;
+}
+
+void
+ww_acquire_fini(struct ww_acquire_ctx *ctx)
+{
+
+	KASSERTMSG((ctx->wwx_owner == curlwp),
+	    "ctx %p owned by %p, not self (%p)", ctx, ctx->wwx_owner, curlwp);
+	KASSERTMSG((ctx->wwx_acquired == 0), "ctx %p still holds %u locks",
+	    ctx, ctx->wwx_acquired);
+
+	ctx->wwx_acquired = ~0U;	/* Fail if called again. */
+	ctx->wwx_owner = NULL;
+}
+
+void
+ww_mutex_init(struct ww_mutex *mutex, struct ww_class *class)
+{
+
+	/*
+	 * XXX Apparently Linux takes these with spin locks held.  That
+	 * strikes me as a bad idea, but so it is...
+	 */
+	mutex_init(&mutex->wwm_lock, MUTEX_DEFAULT, IPL_VM);
+	mutex->wwm_state = WW_UNLOCKED;
+	mutex->wwm_class = class;
+	rb_tree_init(&mutex->wwm_waiters, &ww_acquire_ctx_rb_ops);
+	cv_init(&mutex->wwm_cv, "linuxwwm");
+}
+
+void
+ww_mutex_destroy(struct ww_mutex *mutex)
+{
+
+	cv_destroy(&mutex->wwm_cv);
+#if 0
+	rb_tree_destroy(&mutex->wwm_waiters, &ww_acquire_ctx_rb_ops);
+#endif
+	KASSERT(mutex->wwm_state == WW_UNLOCKED);
+	mutex_destroy(&mutex->wwm_lock);
+}
+
+/*
+ * XXX WARNING: This returns true if it is locked by ANYONE.  Does not
+ * mean `Do I hold this lock?' (answering which really requires an
+ * acquire context).
+ */
+bool
+ww_mutex_is_locked(struct ww_mutex *mutex)
+{
+	int locked;
+
+	mutex_enter(&mutex->wwm_lock);
+	switch (mutex->wwm_state) {
+	case WW_UNLOCKED:
+		locked = false;
+		break;
+	case WW_OWNED:
+	case WW_CTX:
+	case WW_WANTOWN:
+		locked = true;
+		break;
+	default:
+		panic("wait/wound mutex %p in bad state: %d", mutex,
+		    (int)mutex->wwm_state);
+	}
+	mutex_exit(&mutex->wwm_lock);
+
+	return locked;
+}
+
+static void
+ww_mutex_state_wait(struct ww_mutex *mutex, enum ww_mutex_state state)
+{
+
+	KASSERT(mutex->wwm_state == state);
+	do cv_wait(&mutex->wwm_cv, &mutex->wwm_lock);
+	while (mutex->wwm_state == state);
+}
+
+static int
+ww_mutex_state_wait_sig(struct ww_mutex *mutex, enum ww_mutex_state state)
+{
+	int ret;
+
+	KASSERT(mutex->wwm_state == state);
+	do {
+		/* XXX errno NetBSD->Linux */
+		ret = -cv_wait_sig(&mutex->wwm_cv, &mutex->wwm_lock);
+		if (ret)
+			break;
+	} while (mutex->wwm_state == state);
+
+	return ret;
+}
+
+static void
+ww_mutex_lock_wait(struct ww_mutex *mutex, struct ww_acquire_ctx *ctx)
+{
+	struct ww_acquire_ctx *collision __diagused;
+
+	KASSERT(mutex_owned(&mutex->wwm_lock));
+
+	KASSERT((mutex->wwm_state == WW_CTX) ||
+	    (mutex->wwm_state == WW_WANTOWN));
+	KASSERT(mutex->wwm_u.ctx != ctx);
+	KASSERTMSG((ctx->wwx_class == mutex->wwm_u.ctx->wwx_class),
+	    "ww mutex class mismatch: %p != %p",
+	    ctx->wwx_class, mutex->wwm_u.ctx->wwx_class);
+	KASSERTMSG((mutex->wwm_u.ctx->wwx_ticket != ctx->wwx_ticket),
+	    "ticket number reused: %"PRId64" (%p) %"PRId64" (%p)",
+	    ctx->wwx_ticket, ctx,
+	    mutex->wwm_u.ctx->wwx_ticket, mutex->wwm_u.ctx);
+
+	collision = rb_tree_insert_node(&mutex->wwm_waiters, ctx);
+	KASSERTMSG((collision == ctx),
+	    "ticket number reused: %"PRId64" (%p) %"PRId64" (%p)",
+	    ctx->wwx_ticket, ctx, collision->wwx_ticket, collision);
+
+	do cv_wait(&mutex->wwm_cv, &mutex->wwm_lock);
+	while (!(((mutex->wwm_state == WW_CTX) ||
+		    (mutex->wwm_state == WW_WANTOWN)) &&
+		 (mutex->wwm_u.ctx == ctx)));
+
+	rb_tree_remove_node(&mutex->wwm_waiters, ctx);
+}
+
+static int
+ww_mutex_lock_wait_sig(struct ww_mutex *mutex, struct ww_acquire_ctx *ctx)
+{
+	struct ww_acquire_ctx *collision __diagused;
+	int ret;
+
+	KASSERT(mutex_owned(&mutex->wwm_lock));
+
+	KASSERT((mutex->wwm_state == WW_CTX) ||
+	    (mutex->wwm_state == WW_WANTOWN));
+	KASSERT(mutex->wwm_u.ctx != ctx);
+	KASSERTMSG((ctx->wwx_class == mutex->wwm_u.ctx->wwx_class),
+	    "ww mutex class mismatch: %p != %p",
+	    ctx->wwx_class, mutex->wwm_u.ctx->wwx_class);
+	KASSERTMSG((mutex->wwm_u.ctx->wwx_ticket != ctx->wwx_ticket),
+	    "ticket number reused: %"PRId64" (%p) %"PRId64" (%p)",
+	    ctx->wwx_ticket, ctx,
+	    mutex->wwm_u.ctx->wwx_ticket, mutex->wwm_u.ctx);
+
+	collision = rb_tree_insert_node(&mutex->wwm_waiters, ctx);
+	KASSERTMSG((collision == ctx),
+	    "ticket number reused: %"PRId64" (%p) %"PRId64" (%p)",
+	    ctx->wwx_ticket, ctx, collision->wwx_ticket, collision);
+
+	do {
+		/* XXX errno NetBSD->Linux */
+		ret = -cv_wait_sig(&mutex->wwm_cv, &mutex->wwm_lock);
+		if (ret)
+			goto out;
+	} while (!(((mutex->wwm_state == WW_CTX) ||
+		    (mutex->wwm_state == WW_WANTOWN)) &&
+		(mutex->wwm_u.ctx == ctx)));
+
+out:	rb_tree_remove_node(&mutex->wwm_waiters, ctx);
+	return ret;
+}
+
+static void
+ww_mutex_lock_noctx(struct ww_mutex *mutex)
+{
+
+	mutex_enter(&mutex->wwm_lock);
+retry:	switch (mutex->wwm_state) {
+	case WW_UNLOCKED:
+		mutex->wwm_state = WW_OWNED;
+		mutex->wwm_u.owner = curlwp;
+		break;
+	case WW_OWNED:
+		KASSERTMSG((mutex->wwm_u.owner != curlwp),
+		    "locking %p against myself: %p", mutex, curlwp);
+		ww_mutex_state_wait(mutex, WW_OWNED);
+		goto retry;
+	case WW_CTX:
+		KASSERT(mutex->wwm_u.ctx != NULL);
+		mutex->wwm_state = WW_WANTOWN;
+		/* FALLTHROUGH */
+	case WW_WANTOWN:
+		KASSERTMSG((mutex->wwm_u.ctx->wwx_owner != curlwp),
+		    "locking %p against myself: %p", mutex, curlwp);
+		ww_mutex_state_wait(mutex, WW_WANTOWN);
+		goto retry;
+	default:
+		panic("wait/wound mutex %p in bad state: %d",
+		    mutex, (int)mutex->wwm_state);
+	}
+	KASSERT(mutex->wwm_state == WW_OWNED);
+	KASSERT(mutex->wwm_u.owner == curlwp);
+	mutex_exit(&mutex->wwm_lock);
+}
+
+static int
+ww_mutex_lock_noctx_sig(struct ww_mutex *mutex)
+{
+	int ret;
+
+	mutex_enter(&mutex->wwm_lock);
+retry:	switch (mutex->wwm_state) {
+	case WW_UNLOCKED:
+		mutex->wwm_state = WW_OWNED;
+		mutex->wwm_u.owner = curlwp;
+		break;
+	case WW_OWNED:
+		KASSERTMSG((mutex->wwm_u.owner != curlwp),
+		    "locking %p against myself: %p", mutex, curlwp);
+		ret = ww_mutex_state_wait_sig(mutex, WW_OWNED);
+		if (ret)
+			goto out;
+		goto retry;
+	case WW_CTX:
+		KASSERT(mutex->wwm_u.ctx != NULL);
+		mutex->wwm_state = WW_WANTOWN;
+		/* FALLTHROUGH */
+	case WW_WANTOWN:
+		KASSERTMSG((mutex->wwm_u.ctx->wwx_owner != curlwp),
+		    "locking %p against myself: %p", mutex, curlwp);
+		ret = ww_mutex_state_wait_sig(mutex, WW_WANTOWN);
+		if (ret)
+			goto out;
+		goto retry;
+	default:
+		panic("wait/wound mutex %p in bad state: %d",
+		    mutex, (int)mutex->wwm_state);
+	}
+	KASSERT(mutex->wwm_state == WW_OWNED);
+	KASSERT(mutex->wwm_u.owner == curlwp);
+	ret = 0;
+out:	mutex_exit(&mutex->wwm_lock);
+	return ret;
+}
+
+int
+ww_mutex_lock(struct ww_mutex *mutex, struct ww_acquire_ctx *ctx)
+{
+
+	ASSERT_SLEEPABLE();
+
+	if (ctx == NULL) {
+		ww_mutex_lock_noctx(mutex);
+		return 0;
+	}
+
+	KASSERTMSG((ctx->wwx_owner == curlwp),
+	    "ctx %p owned by %p, not self (%p)", ctx, ctx->wwx_owner, curlwp);
+	KASSERTMSG(!ctx->wwx_acquire_done,
+	    "ctx %p done acquiring locks, can't acquire more", ctx);
+	KASSERTMSG((ctx->wwx_acquired != ~0U),
+	    "ctx %p finished, can't be used any more", ctx);
+	KASSERTMSG((ctx->wwx_class == mutex->wwm_class),
+	    "ctx %p in class %p, mutex %p in class %p",
+	    ctx, ctx->wwx_class, mutex, mutex->wwm_class);
+
+	mutex_enter(&mutex->wwm_lock);
+retry:	switch (mutex->wwm_state) {
+	case WW_UNLOCKED:
+		mutex->wwm_state = WW_CTX;
+		mutex->wwm_u.ctx = ctx;
+		goto locked;
+	case WW_OWNED:
+		KASSERTMSG((mutex->wwm_u.owner != curlwp),
+		    "locking %p against myself: %p", mutex, curlwp);
+		ww_mutex_state_wait(mutex, WW_OWNED);
+		goto retry;
+	case WW_CTX:
+		break;
+	case WW_WANTOWN:
+		ww_mutex_state_wait(mutex, WW_WANTOWN);
+		goto retry;
+	default:
+		panic("wait/wound mutex %p in bad state: %d",
+		    mutex, (int)mutex->wwm_state);
+	}
+	KASSERT(mutex->wwm_state == WW_CTX);
+	KASSERT(mutex->wwm_u.ctx != NULL);
+	KASSERT((mutex->wwm_u.ctx == ctx) ||
+	    (mutex->wwm_u.ctx->wwx_owner != curlwp));
+	if (mutex->wwm_u.ctx == ctx) {
+		/*
+		 * We already own it.  Yes, this can happen correctly
+		 * for objects whose locking order is determined by
+		 * userland.
+		 */
+		mutex_exit(&mutex->wwm_lock);
+		return -EALREADY;
+	} else if (mutex->wwm_u.ctx->wwx_ticket < ctx->wwx_ticket) {
+		/*
+		 * Owned by a higher-priority party.  Tell the caller
+		 * to unlock everything and start over.
+		 */
+		KASSERTMSG((ctx->wwx_class == mutex->wwm_u.ctx->wwx_class),
+		    "ww mutex class mismatch: %p != %p",
+		    ctx->wwx_class, mutex->wwm_u.ctx->wwx_class);
+		mutex_exit(&mutex->wwm_lock);
+		return -EDEADLK;
+	} else {
+		/*
+		 * Owned by a lower-priority party.  Ask that party to
+		 * wake us when it is done or it realizes it needs to
+		 * back off.
+		 */
+		ww_mutex_lock_wait(mutex, ctx);
+	}
+locked:	ctx->wwx_acquired++;
+	KASSERT((mutex->wwm_state == WW_CTX) ||
+	    (mutex->wwm_state == WW_WANTOWN));
+	KASSERT(mutex->wwm_u.ctx == ctx);
+	mutex_exit(&mutex->wwm_lock);
+	return 0;
+}
+
+int
+ww_mutex_lock_interruptible(struct ww_mutex *mutex, struct ww_acquire_ctx *ctx)
+{
+	int ret;
+
+	ASSERT_SLEEPABLE();
+
+	if (ctx == NULL)
+		return ww_mutex_lock_noctx_sig(mutex);
+
+	KASSERTMSG((ctx->wwx_owner == curlwp),
+	    "ctx %p owned by %p, not self (%p)", ctx, ctx->wwx_owner, curlwp);
+	KASSERTMSG(!ctx->wwx_acquire_done,
+	    "ctx %p done acquiring locks, can't acquire more", ctx);
+	KASSERTMSG((ctx->wwx_acquired != ~0U),
+	    "ctx %p finished, can't be used any more", ctx);
+	KASSERTMSG((ctx->wwx_class == mutex->wwm_class),
+	    "ctx %p in class %p, mutex %p in class %p",
+	    ctx, ctx->wwx_class, mutex, mutex->wwm_class);
+
+	mutex_enter(&mutex->wwm_lock);
+retry:	switch (mutex->wwm_state) {
+	case WW_UNLOCKED:
+		mutex->wwm_state = WW_CTX;
+		mutex->wwm_u.ctx = ctx;
+		goto locked;
+	case WW_OWNED:
+		KASSERTMSG((mutex->wwm_u.owner != curlwp),
+		    "locking %p against myself: %p", mutex, curlwp);
+		ret = ww_mutex_state_wait_sig(mutex, WW_OWNED);
+		if (ret)
+			goto out;
+		goto retry;
+	case WW_CTX:
+		break;
+	case WW_WANTOWN:
+		ret = ww_mutex_state_wait_sig(mutex, WW_WANTOWN);
+		if (ret)
+			goto out;
+		goto retry;
+	default:
+		panic("wait/wound mutex %p in bad state: %d",
+		    mutex, (int)mutex->wwm_state);
+	}
+	KASSERT(mutex->wwm_state == WW_CTX);
+	KASSERT(mutex->wwm_u.ctx != NULL);
+	KASSERT((mutex->wwm_u.ctx == ctx) ||
+	    (mutex->wwm_u.ctx->wwx_owner != curlwp));
+	if (mutex->wwm_u.ctx == ctx) {
+		/*
+		 * We already own it.  Yes, this can happen correctly
+		 * for objects whose locking order is determined by
+		 * userland.
+		 */
+		mutex_exit(&mutex->wwm_lock);
+		return -EALREADY;
+	} else if (mutex->wwm_u.ctx->wwx_ticket < ctx->wwx_ticket) {
+		/*
+		 * Owned by a higher-priority party.  Tell the caller
+		 * to unlock everything and start over.
+		 */
+		KASSERTMSG((ctx->wwx_class == mutex->wwm_u.ctx->wwx_class),
+		    "ww mutex class mismatch: %p != %p",
+		    ctx->wwx_class, mutex->wwm_u.ctx->wwx_class);
+		mutex_exit(&mutex->wwm_lock);
+		return -EDEADLK;
+	} else {
+		/*
+		 * Owned by a lower-priority party.  Ask that party to
+		 * wake us when it is done or it realizes it needs to
+		 * back off.
+		 */
+		ret = ww_mutex_lock_wait_sig(mutex, ctx);
+		if (ret)
+			goto out;
+	}
+locked:	KASSERT((mutex->wwm_state == WW_CTX) ||
+	    (mutex->wwm_state == WW_WANTOWN));
+	KASSERT(mutex->wwm_u.ctx == ctx);
+	ctx->wwx_acquired++;
+	ret = 0;
+out:	mutex_exit(&mutex->wwm_lock);
+	return ret;
+}
+
+void
+ww_mutex_lock_slow(struct ww_mutex *mutex, struct ww_acquire_ctx *ctx)
+{
+
+	ASSERT_SLEEPABLE();
+
+	if (ctx == NULL) {
+		ww_mutex_lock_noctx(mutex);
+		return;
+	}
+
+	KASSERTMSG((ctx->wwx_owner == curlwp),
+	    "ctx %p owned by %p, not self (%p)", ctx, ctx->wwx_owner, curlwp);
+	KASSERTMSG(!ctx->wwx_acquire_done,
+	    "ctx %p done acquiring locks, can't acquire more", ctx);
+	KASSERTMSG((ctx->wwx_acquired != ~0U),
+	    "ctx %p finished, can't be used any more", ctx);
+	KASSERTMSG((ctx->wwx_acquired == 0),
+	    "ctx %p still holds %u locks, not allowed in slow path",
+	    ctx, ctx->wwx_acquired);
+	KASSERTMSG((ctx->wwx_class == mutex->wwm_class),
+	    "ctx %p in class %p, mutex %p in class %p",
+	    ctx, ctx->wwx_class, mutex, mutex->wwm_class);
+
+	mutex_enter(&mutex->wwm_lock);
+retry:	switch (mutex->wwm_state) {
+	case WW_UNLOCKED:
+		mutex->wwm_state = WW_CTX;
+		mutex->wwm_u.ctx = ctx;
+		goto locked;
+	case WW_OWNED:
+		KASSERTMSG((mutex->wwm_u.owner != curlwp),
+		    "locking %p against myself: %p", mutex, curlwp);
+		ww_mutex_state_wait(mutex, WW_OWNED);
+		goto retry;
+	case WW_CTX:
+		break;
+	case WW_WANTOWN:
+		ww_mutex_state_wait(mutex, WW_WANTOWN);
+		goto retry;
+	default:
+		panic("wait/wound mutex %p in bad state: %d",
+		    mutex, (int)mutex->wwm_state);
+	}
+	KASSERT(mutex->wwm_state == WW_CTX);
+	KASSERT(mutex->wwm_u.ctx != NULL);
+	KASSERTMSG((mutex->wwm_u.ctx->wwx_owner != curlwp),
+	    "locking %p against myself: %p", mutex, curlwp);
+	/*
+	 * Owned by another party, of any priority.  Ask that party to
+	 * wake us when it's done.
+	 */
+	ww_mutex_lock_wait(mutex, ctx);
+locked:	KASSERT((mutex->wwm_state == WW_CTX) ||
+	    (mutex->wwm_state == WW_WANTOWN));
+	KASSERT(mutex->wwm_u.ctx == ctx);
+	ctx->wwx_acquired++;
+	mutex_exit(&mutex->wwm_lock);
+}
+
+int
+ww_mutex_lock_slow_interruptible(struct ww_mutex *mutex,
+    struct ww_acquire_ctx *ctx)
+{
+	int ret;
+
+	ASSERT_SLEEPABLE();
+
+	if (ctx == NULL)
+		return ww_mutex_lock_noctx_sig(mutex);
+
+	KASSERTMSG((ctx->wwx_owner == curlwp),
+	    "ctx %p owned by %p, not self (%p)", ctx, ctx->wwx_owner, curlwp);
+	KASSERTMSG(!ctx->wwx_acquire_done,
+	    "ctx %p done acquiring locks, can't acquire more", ctx);
+	KASSERTMSG((ctx->wwx_acquired != ~0U),
+	    "ctx %p finished, can't be used any more", ctx);
+	KASSERTMSG((ctx->wwx_acquired == 0),
+	    "ctx %p still holds %u locks, not allowed in slow path",
+	    ctx, ctx->wwx_acquired);
+	KASSERTMSG((ctx->wwx_class == mutex->wwm_class),
+	    "ctx %p in class %p, mutex %p in class %p",
+	    ctx, ctx->wwx_class, mutex, mutex->wwm_class);
+
+	mutex_enter(&mutex->wwm_lock);
+retry:	switch (mutex->wwm_state) {
+	case WW_UNLOCKED:
+		mutex->wwm_state = WW_CTX;
+		mutex->wwm_u.ctx = ctx;
+		goto locked;
+	case WW_OWNED:
+		KASSERTMSG((mutex->wwm_u.owner != curlwp),
+		    "locking %p against myself: %p", mutex, curlwp);
+		ret = ww_mutex_state_wait_sig(mutex, WW_OWNED);
+		if (ret)
+			goto out;
+		goto retry;
+	case WW_CTX:
+		break;
+	case WW_WANTOWN:
+		ret = ww_mutex_state_wait_sig(mutex, WW_WANTOWN);
+		if (ret)
+			goto out;
+		goto retry;
+	default:
+		panic("wait/wound mutex %p in bad state: %d",
+		    mutex, (int)mutex->wwm_state);
+	}
+	KASSERT(mutex->wwm_state == WW_CTX);
+	KASSERT(mutex->wwm_u.ctx != NULL);
+	KASSERTMSG((mutex->wwm_u.ctx->wwx_owner != curlwp),
+	    "locking %p against myself: %p", mutex, curlwp);
+	/*
+	 * Owned by another party, of any priority.  Ask that party to
+	 * wake us when it's done.
+	 */
+	ret = ww_mutex_lock_wait_sig(mutex, ctx);
+	if (ret)
+		goto out;
+locked:	KASSERT((mutex->wwm_state == WW_CTX) ||
+	    (mutex->wwm_state == WW_WANTOWN));
+	KASSERT(mutex->wwm_u.ctx == ctx);
+	ctx->wwx_acquired++;
+	ret = 0;
+out:	mutex_exit(&mutex->wwm_lock);
+	return ret;
+}
+
+int
+ww_mutex_trylock(struct ww_mutex *mutex)
+{
+	int ret;
+
+	mutex_enter(&mutex->wwm_lock);
+	if (mutex->wwm_state == WW_UNLOCKED) {
+		mutex->wwm_state = WW_OWNED;
+		mutex->wwm_u.owner = curlwp;
+		ret = 1;
+	} else {
+		KASSERTMSG(((mutex->wwm_state != WW_OWNED) ||
+		    (mutex->wwm_u.owner != curlwp)),
+		    "locking %p against myself: %p", mutex, curlwp);
+		KASSERTMSG(((mutex->wwm_state != WW_CTX) ||
+		    (mutex->wwm_u.ctx->wwx_owner != curlwp)),
+		    "locking %p against myself: %p", mutex, curlwp);
+		KASSERTMSG(((mutex->wwm_state != WW_WANTOWN) ||
+		    (mutex->wwm_u.ctx->wwx_owner != curlwp)),
+		    "locking %p against myself: %p", mutex, curlwp);
+		ret = 0;
+	}
+	mutex_exit(&mutex->wwm_lock);
+
+	return ret;
+}
+
+static void
+ww_mutex_unlock_release(struct ww_mutex *mutex)
+{
+
+	KASSERT(mutex_owned(&mutex->wwm_lock));
+	KASSERT((mutex->wwm_state == WW_CTX) ||
+	    (mutex->wwm_state == WW_WANTOWN));
+	KASSERT(mutex->wwm_u.ctx != NULL);
+	KASSERTMSG((mutex->wwm_u.ctx->wwx_owner == curlwp),
+	    "ww_mutex %p ctx %p held by %p, not by self (%p)",
+	    mutex, mutex->wwm_u.ctx, mutex->wwm_u.ctx->wwx_owner,
+	    curlwp);
+	KASSERT(mutex->wwm_u.ctx->wwx_acquired != ~0U);
+	mutex->wwm_u.ctx->wwx_acquired--;
+	mutex->wwm_u.ctx = NULL;
+}
+
+void
+ww_mutex_unlock(struct ww_mutex *mutex)
+{
+	struct ww_acquire_ctx *ctx;
+
+	mutex_enter(&mutex->wwm_lock);
+	KASSERT(mutex->wwm_state != WW_UNLOCKED);
+	switch (mutex->wwm_state) {
+	case WW_UNLOCKED:
+		panic("unlocking unlocked wait/wound mutex: %p", mutex);
+	case WW_OWNED:
+		/* Let the context lockers fight over it.  */
+		mutex->wwm_u.owner = NULL;
+		mutex->wwm_state = WW_UNLOCKED;
+		break;
+	case WW_CTX:
+		ww_mutex_unlock_release(mutex);
+		/*
+		 * If there are any waiters with contexts, grant the
+		 * lock to the highest-priority one.  Otherwise, just
+		 * unlock it.
+		 */
+		if ((ctx = RB_TREE_MIN(&mutex->wwm_waiters)) != NULL) {
+			mutex->wwm_state = WW_CTX;
+			mutex->wwm_u.ctx = ctx;
+		} else {
+			mutex->wwm_state = WW_UNLOCKED;
+		}
+		break;
+	case WW_WANTOWN:
+		ww_mutex_unlock_release(mutex);
+		/* Let the non-context lockers fight over it.  */
+		mutex->wwm_state = WW_UNLOCKED;
+		break;
+	}
+	cv_broadcast(&mutex->wwm_cv);
+	mutex_exit(&mutex->wwm_lock);
+}

Reply via email to