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;