summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_lock.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern/kern_lock.c')
-rw-r--r--sys/kern/kern_lock.c65
1 files changed, 42 insertions, 23 deletions
diff --git a/sys/kern/kern_lock.c b/sys/kern/kern_lock.c
index 8d1a219..6e5a7b3 100644
--- a/sys/kern/kern_lock.c
+++ b/sys/kern/kern_lock.c
@@ -105,7 +105,7 @@ unlock_lockmgr(struct lock_object *lock)
panic("lockmgr locks do not support sleep interlocking");
}
-#define COUNT(td, x) if ((td)) (td)->td_locks += (x)
+#define COUNT(td, x) ((td)->td_locks += (x))
#define LK_ALL (LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE | \
LK_SHARE_NONZERO | LK_WAIT_NONZERO)
@@ -194,24 +194,18 @@ _lockmgr(struct lock *lkp, u_int flags, struct mtx *interlkp,
{
int error;
- struct thread *thr;
int extflags, lockflags;
int contested = 0;
uint64_t waitstart = 0;
/*
- * Lock owner can only be curthread or, at least, NULL in order to
- * have a deadlock free implementation of the primitive.
+ * Lock owner can only be curthread in order to have a deadlock
+ * free implementation of the primitive.
*/
- KASSERT(td == NULL || td == curthread,
- ("lockmgr: owner thread (%p) cannot differ from curthread or NULL",
- td));
+ KASSERT(td == curthread,
+ ("lockmgr: owner thread (%p) cannot differ from curthread", td));
error = 0;
- if (td == NULL)
- thr = LK_KERNPROC;
- else
- thr = td;
if ((flags & LK_INTERNAL) == 0)
mtx_lock(lkp->lk_interlock);
@@ -260,7 +254,7 @@ _lockmgr(struct lock *lkp, u_int flags, struct mtx *interlkp,
* lock requests or upgrade requests ( but not the exclusive
* lock itself ).
*/
- if (lkp->lk_lockholder != thr) {
+ if (lkp->lk_lockholder != td) {
lockflags = LK_HAVE_EXCL;
if (td != NULL && !(td->td_pflags & TDP_DEADLKTREAT))
lockflags |= LK_WANT_EXCL | LK_WANT_UPGRADE;
@@ -286,10 +280,10 @@ _lockmgr(struct lock *lkp, u_int flags, struct mtx *interlkp,
/* FALLTHROUGH downgrade */
case LK_DOWNGRADE:
- KASSERT(lkp->lk_lockholder == thr && lkp->lk_exclusivecount != 0,
+ KASSERT(lkp->lk_lockholder == td && lkp->lk_exclusivecount != 0,
("lockmgr: not holding exclusive lock "
"(owner thread (%p) != thread (%p), exlcnt (%d) != 0",
- lkp->lk_lockholder, thr, lkp->lk_exclusivecount));
+ lkp->lk_lockholder, td, lkp->lk_exclusivecount));
sharelock(td, lkp, lkp->lk_exclusivecount);
COUNT(td, -lkp->lk_exclusivecount);
lkp->lk_exclusivecount = 0;
@@ -308,7 +302,7 @@ _lockmgr(struct lock *lkp, u_int flags, struct mtx *interlkp,
* after the upgrade). If we return an error, the file
* will always be unlocked.
*/
- if (lkp->lk_lockholder == thr)
+ if (lkp->lk_lockholder == td)
panic("lockmgr: upgrade exclusive lock");
if (lkp->lk_sharecount <= 0)
panic("lockmgr: upgrade without shared");
@@ -342,7 +336,7 @@ _lockmgr(struct lock *lkp, u_int flags, struct mtx *interlkp,
if (lkp->lk_exclusivecount != 0)
panic("lockmgr: non-zero exclusive count");
lkp->lk_flags |= LK_HAVE_EXCL;
- lkp->lk_lockholder = thr;
+ lkp->lk_lockholder = td;
lkp->lk_exclusivecount = 1;
COUNT(td, 1);
lock_profile_obtain_lock_success(&lkp->lk_object, contested, waitstart, file, line);
@@ -362,7 +356,7 @@ _lockmgr(struct lock *lkp, u_int flags, struct mtx *interlkp,
/* FALLTHROUGH exclusive request */
case LK_EXCLUSIVE:
- if (lkp->lk_lockholder == thr && thr != LK_KERNPROC) {
+ if (lkp->lk_lockholder == td) {
/*
* Recursive lock.
*/
@@ -400,7 +394,7 @@ _lockmgr(struct lock *lkp, u_int flags, struct mtx *interlkp,
break;
}
lkp->lk_flags |= LK_HAVE_EXCL;
- lkp->lk_lockholder = thr;
+ lkp->lk_lockholder = td;
if (lkp->lk_exclusivecount != 0)
panic("lockmgr: non-zero exclusive count");
lkp->lk_exclusivecount = 1;
@@ -413,10 +407,10 @@ _lockmgr(struct lock *lkp, u_int flags, struct mtx *interlkp,
case LK_RELEASE:
if (lkp->lk_exclusivecount != 0) {
- if (lkp->lk_lockholder != thr &&
+ if (lkp->lk_lockholder != td &&
lkp->lk_lockholder != LK_KERNPROC) {
panic("lockmgr: thread %p, not %s %p unlocking",
- thr, "exclusive lock holder",
+ td, "exclusive lock holder",
lkp->lk_lockholder);
}
if (lkp->lk_lockholder != LK_KERNPROC)
@@ -433,7 +427,7 @@ _lockmgr(struct lock *lkp, u_int flags, struct mtx *interlkp,
shareunlock(td, lkp, 1);
else {
printf("lockmgr: thread %p unlocking unheld lock\n",
- thr);
+ td);
kdb_backtrace();
}
@@ -448,14 +442,14 @@ _lockmgr(struct lock *lkp, u_int flags, struct mtx *interlkp,
* check for holding a shared lock, but at least we can
* check for an exclusive one.
*/
- if (lkp->lk_lockholder == thr)
+ if (lkp->lk_lockholder == td)
panic("lockmgr: draining against myself");
error = acquiredrain(lkp, extflags);
if (error)
break;
lkp->lk_flags |= LK_DRAINING | LK_HAVE_EXCL;
- lkp->lk_lockholder = thr;
+ lkp->lk_lockholder = td;
lkp->lk_exclusivecount = 1;
COUNT(td, 1);
#if defined(DEBUG_LOCKS)
@@ -544,6 +538,31 @@ lockdestroy(lkp)
}
/*
+ * Disown the lockmgr.
+ */
+void
+lockmgr_disown(struct lock *lkp)
+{
+ struct thread *td;
+
+ td = curthread;
+ KASSERT(lkp->lk_exclusivecount || lkp->lk_lockholder == LK_KERNPROC,
+ ("%s: %p lockmgr must be exclusively locked", __func__, lkp));
+ KASSERT(lkp->lk_lockholder == td,
+ ("%s: %p lockmgr must be locked by curthread (%p)", __func__, lkp,
+ td));
+
+ /*
+ * Drop the lock reference and switch the owner. This will result
+ * in an atomic operation like td_lock is only accessed by curthread
+ * and lk_lockholder only needs one write.
+ */
+ if (lkp->lk_lockholder == td)
+ td->td_locks--;
+ lkp->lk_lockholder = LK_KERNPROC;
+}
+
+/*
* Determine the status of a lock.
*/
int
OpenPOWER on IntegriCloud