Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 26 Sep 2017 23:24:15 +0000 (UTC)
From:      John Baldwin <jhb@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r324039 - head/sys/ufs/ffs
Message-ID:  <201709262324.v8QNOFCZ009598@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jhb
Date: Tue Sep 26 23:24:15 2017
New Revision: 324039
URL: https://svnweb.freebsd.org/changeset/base/324039

Log:
  Don't defer wakeup()s for completed journal workitems.
  
  Normally wakeups() are performed for completed softupdates work items
  in workitem_free() before the underlying memory is free()'d.
  complete_jseg() was clearing the "wakeup needed" flag in work items to
  defer the wakeup until the end of each loop iteration.  However, this
  resulted in the item being free'd before it's address was used with
  wakeup().  As a result, another part of the kernel could allocate this
  memory from malloc() and use it as a wait channel for a different
  "event" with a different lock.  This triggered an assertion failure
  when the lock passed to sleepq_add() did not match the existing lock
  associated with the sleep queue.  Fix this by removing the code to
  defer the wakeup in complete_jseg() allowing the wakeup to occur
  slightly earlier in workitem_free() before free() is called.
  
  The main reason I can think of for deferring a wakeup() would be to
  avoid waking up a waiter while holding a lock that the waiter would
  need.  However, no locks are dropped in between the wakeup() in
  workitem_free() and the end of the loop in complete_jseg() as far as I
  can tell.
  
  In general I think it is not safe to do a wakeup() after free() as one
  cannot control how other parts of the kernel that might reuse the
  address for a different wait channel will handle spurious wakeups.
  
  Reported by:	pho
  Reviewed by:	kib
  MFC after:	2 weeks
  Differential Revision:	https://reviews.freebsd.org/D12494

Modified:
  head/sys/ufs/ffs/ffs_softdep.c

Modified: head/sys/ufs/ffs/ffs_softdep.c
==============================================================================
--- head/sys/ufs/ffs/ffs_softdep.c	Tue Sep 26 23:23:58 2017	(r324038)
+++ head/sys/ufs/ffs/ffs_softdep.c	Tue Sep 26 23:24:15 2017	(r324039)
@@ -3596,15 +3596,13 @@ complete_jseg(jseg)
 {
 	struct worklist *wk;
 	struct jmvref *jmvref;
-	int waiting;
 #ifdef INVARIANTS
 	int i = 0;
 #endif
 
 	while ((wk = LIST_FIRST(&jseg->js_entries)) != NULL) {
 		WORKLIST_REMOVE(wk);
-		waiting = wk->wk_state & IOWAITING;
-		wk->wk_state &= ~(INPROGRESS | IOWAITING);
+		wk->wk_state &= ~INPROGRESS;
 		wk->wk_state |= COMPLETE;
 		KASSERT(i++ < jseg->js_cnt,
 		    ("handle_written_jseg: overflow %d >= %d",
@@ -3645,8 +3643,6 @@ complete_jseg(jseg)
 			    TYPENAME(wk->wk_type));
 			/* NOTREACHED */
 		}
-		if (waiting)
-			wakeup(wk);
 	}
 	/* Release the self reference so the structure may be freed. */
 	rele_jseg(jseg);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201709262324.v8QNOFCZ009598>