Module Name:    src
Committed By:   pgoyette
Date:           Fri May 12 22:12:23 UTC 2017

Modified Files:
        src/sys/kern [prg-localcount2]: subr_localcount.c

Log Message:
When we're draining the localcount's references, transfer the local
CPU's reference count to the global total, and then zero it.  Any
further calls to localcount_release() will adjust only the global
counter.

Avoids a race condition which depends on having localcount_release()
being aware of whether the local CPU's contribution has already been
accounted for.  Thanks to Kengo NAKAHARA for bringing up the question,
and to riastradh@ for the solution.


To generate a diff of this commit:
cvs rdiff -u -r1.1.6.4 -r1.1.6.5 src/sys/kern/subr_localcount.c

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

Modified files:

Index: src/sys/kern/subr_localcount.c
diff -u src/sys/kern/subr_localcount.c:1.1.6.4 src/sys/kern/subr_localcount.c:1.1.6.5
--- src/sys/kern/subr_localcount.c:1.1.6.4	Thu May 11 21:31:12 2017
+++ src/sys/kern/subr_localcount.c	Fri May 12 22:12:23 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: subr_localcount.c,v 1.1.6.4 2017/05/11 21:31:12 pgoyette Exp $	*/
+/*	$NetBSD: subr_localcount.c,v 1.1.6.5 2017/05/12 22:12:23 pgoyette Exp $	*/
 
 /*-
  * Copyright (c) 2016 The NetBSD Foundation, Inc.
@@ -44,7 +44,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: subr_localcount.c,v 1.1.6.4 2017/05/11 21:31:12 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: subr_localcount.c,v 1.1.6.5 2017/05/12 22:12:23 pgoyette Exp $");
 
 #include <sys/param.h>
 #include <sys/localcount.h>
@@ -148,6 +148,14 @@ localcount_fini(struct localcount *lc)
 	percpu_free(lc->lc_percpu, sizeof(uint64_t));
 }
 
+/*
+ * localcount_xc(cookie0, cookie1)
+ *
+ *	Accumulate and transfer the per-CPU reference counts to a
+ *	global total, resetting the per-CPU counter to zero.  Once
+ *	localcount_drain() has started, we only maintain the total
+ *	count in localcount_release().
+ */
 static void
 localcount_xc(void *cookie0, void *cookie1)
 {
@@ -158,6 +166,7 @@ localcount_xc(void *cookie0, void *cooki
 	mutex_enter(interlock);
 	localp = percpu_getref(lc->lc_percpu);
 	*lc->lc_totalp += *localp;
+	*localp -= *localp;		/* ie, *localp = 0; */
 	percpu_putref(lc->lc_percpu);
 	mutex_exit(interlock);
 }
@@ -235,9 +244,7 @@ localcount_release(struct localcount *lc
 		 * the last reference.
 		 */
 		mutex_enter(interlock);
-		localcount_adjust(lc, -1);
-		*lc->lc_totalp -= 1;
-		if (*lc->lc_totalp == 0)
+		if (--*lc->lc_totalp == 0)
 			cv_broadcast(cv);
 		mutex_exit(interlock);
 		goto out;

Reply via email to