kernel - Fix a third missing wakeup() in kern_lock.c
authorMatthew Dillon <dillon@apollo.backplane.com>
Thu, 30 Aug 2018 05:10:49 +0000 (22:10 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Thu, 30 Aug 2018 16:10:42 +0000 (09:10 -0700)
* Fix a case where an lockmgr LK_EXCLUSIVE call with a
  timeout blocks due to existing shared locks.  If the
  timeout occurs, the exclusive lock request is backed out.

  However, if any new shared locks are attempted while
  the EXREQ was pending (due to the exclusive priority
  mechanism), those threads will block.  The backout code
  was not waking the blocked threads up for this situation.

* Fixed by issuing the wakeup() unconditionally for this
  case.  This is not a heavily traveled code path as locks
  with timeouts rarely reach the actual timeout.

sys/kern/kern_lock.c

index a65e377..91d0e0e 100644 (file)
@@ -1127,11 +1127,15 @@ undo_exreq(struct lock *lkp)
                         * is held shared.  Clear EXREQ, wakeup anyone trying
                         * to get the EXREQ bit (they have to set it
                         * themselves, EXREQ2 is an aggregation).
+                        *
+                        * We must also wakeup any shared locks blocked
+                        * by the EXREQ, so just issue the wakeup
+                        * unconditionally.  See lockmgr_shared() + 76 lines
+                        * or so.
                         */
                        ncount = count & ~(LKC_EXREQ | LKC_EXREQ2);
                        if (atomic_fcmpset_64(&lkp->lk_count, &count, ncount)) {
-                               if (count & LKC_EXREQ2)
-                                       wakeup(lkp);
+                               wakeup(lkp);
                                error = EBUSY;
                                /* count = ncount; NOT USED */
                                break;