Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/kern kern_descrip.c: Change membar_enter to membar_acqui...
details: https://anonhg.NetBSD.org/src/rev/4b3c3e67b28c
branches: trunk
changeset: 373654:4b3c3e67b28c
user: riastradh <riastradh%NetBSD.org@localhost>
date: Thu Feb 23 03:00:15 2023 +0000
description:
kern_descrip.c: Change membar_enter to membar_acquire in fd_getfile.
membar_acquire is cheaper on many CPUs, and unlikely to be costlier
on any CPUs, than the legacy membar_enter.
Add a long comment explaining the interaction between fd_getfile and
fd_close and why membar_acquire is safe.
XXX pullup-10
diffstat:
sys/kern/kern_descrip.c | 41 ++++++++++++++++++++++++++++++++++++++---
1 files changed, 38 insertions(+), 3 deletions(-)
diffs (65 lines):
diff -r 303212cf9d69 -r 4b3c3e67b28c sys/kern/kern_descrip.c
--- a/sys/kern/kern_descrip.c Thu Feb 23 02:58:40 2023 +0000
+++ b/sys/kern/kern_descrip.c Thu Feb 23 03:00:15 2023 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: kern_descrip.c,v 1.253 2023/02/23 02:58:40 riastradh Exp $ */
+/* $NetBSD: kern_descrip.c,v 1.254 2023/02/23 03:00:15 riastradh Exp $ */
/*-
* Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -70,7 +70,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_descrip.c,v 1.253 2023/02/23 02:58:40 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_descrip.c,v 1.254 2023/02/23 03:00:15 riastradh Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -392,10 +392,45 @@
* Multi threaded: issue a memory barrier to ensure that we
* acquire the file pointer _after_ adding a reference. If
* no memory barrier, we could fetch a stale pointer.
+ *
+ * In particular, we must coordinate the following four
+ * memory operations:
+ *
+ * A. fd_close store ff->ff_file = NULL
+ * B. fd_close refcnt = atomic_dec_uint_nv(&ff->ff_refcnt)
+ * C. fd_getfile atomic_inc_uint(&ff->ff_refcnt)
+ * D. fd_getfile load fp = ff->ff_file
+ *
+ * If the order is D;A;B;C:
+ *
+ * 1. D: fp = ff->ff_file
+ * 2. A: ff->ff_file = NULL
+ * 3. B: refcnt = atomic_dec_uint_nv(&ff->ff_refcnt)
+ * 4. C: atomic_inc_uint(&ff->ff_refcnt)
+ *
+ * then fd_close determines that there are no more
+ * references and decides to free fp immediately, at
+ * the same that fd_getfile ends up with an fp that's
+ * about to be freed. *boom*
+ *
+ * By making B a release operation in fd_close, and by
+ * making C an acquire operation in fd_getfile, since
+ * they are atomic operations on the same object, which
+ * has a total modification order, we guarantee either:
+ *
+ * - B happens before C. Then since A is
+ * sequenced before B in fd_close, and C is
+ * sequenced before D in fd_getfile, we
+ * guarantee A happens before D, so fd_getfile
+ * reads a null fp and safely fails.
+ *
+ * - C happens before B. Then fd_getfile may read
+ * null or nonnull, but either way, fd_close
+ * will safely wait for references to drain.
*/
atomic_inc_uint(&ff->ff_refcnt);
#ifndef __HAVE_ATOMIC_AS_MEMBAR
- membar_enter();
+ membar_acquire();
#endif
}
Home |
Main Index |
Thread Index |
Old Index