From be0e90d31c1a4a6ca26f0910607c9e0dd5c56c09 Mon Sep 17 00:00:00 2001 From: visa Date: Sat, 30 Apr 2022 14:44:04 +0000 Subject: [PATCH] Enforce proper memory ordering in refcnt_rele() and refcnt_finalize() Make refcnt_rele() and refcnt_finalize() order memory operations so that preceding loads and stores happen before 1->0 transition. Also ensure that loads and stores that depend on the transition really begin only after the transition has occurred. Otherwise the object destructor might not see the object's latest state. OK bluhm@ --- share/man/man9/refcnt_init.9 | 15 +++++++++++++-- sys/kern/kern_synch.c | 12 ++++++++++-- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/share/man/man9/refcnt_init.9 b/share/man/man9/refcnt_init.9 index cd19b150e93..22bf643ecbf 100644 --- a/share/man/man9/refcnt_init.9 +++ b/share/man/man9/refcnt_init.9 @@ -1,4 +1,4 @@ -.\" $OpenBSD: refcnt_init.9,v 1.2 2022/03/16 14:13:01 visa Exp $ +.\" $OpenBSD: refcnt_init.9,v 1.3 2022/04/30 14:44:04 visa Exp $ .\" .\" Copyright (c) 2015 David Gwynne .\" @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: March 16 2022 $ +.Dd $Mdocdate: April 30 2022 $ .Dt REFCNT_INIT 9 .Os .Sh NAME @@ -74,6 +74,17 @@ There may only be one caller to per refcnt .Fa r . .Pp +.Fn refcnt_rele , +.Fn refcnt_rele_wake +and +.Fn refcnt_finalize +order prior memory loads and stores before the release of the reference. +The functions enforce control dependency so that after the final reference +has been released, subsequent loads and stores happen after the release. +These ensure that concurrent accesses cease before the object's destructor +runs and that the destructor sees all updates done during the lifetime +of the object. +.Pp .Fn refcnt_shared tests if the object has multiple references. .Pp diff --git a/sys/kern/kern_synch.c b/sys/kern/kern_synch.c index 243b820b1b8..218fb9d067e 100644 --- a/sys/kern/kern_synch.c +++ b/sys/kern/kern_synch.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_synch.c,v 1.185 2022/03/18 15:32:06 bluhm Exp $ */ +/* $OpenBSD: kern_synch.c,v 1.186 2022/04/30 14:44:04 visa Exp $ */ /* $NetBSD: kern_synch.c,v 1.37 1996/04/22 01:38:37 christos Exp $ */ /* @@ -822,9 +822,14 @@ refcnt_rele(struct refcnt *r) { u_int refs; + membar_exit_before_atomic(); refs = atomic_dec_int_nv(&r->r_refs); KASSERT(refs != ~0); - return (refs == 0); + if (refs == 0) { + membar_enter_after_atomic(); + return (1); + } + return (0); } void @@ -840,6 +845,7 @@ refcnt_finalize(struct refcnt *r, const char *wmesg) struct sleep_state sls; u_int refs; + membar_exit_before_atomic(); refs = atomic_dec_int_nv(&r->r_refs); KASSERT(refs != ~0); while (refs) { @@ -847,6 +853,8 @@ refcnt_finalize(struct refcnt *r, const char *wmesg) refs = atomic_load_int(&r->r_refs); sleep_finish(&sls, refs); } + /* Order subsequent loads and stores after refs == 0 load. */ + membar_sync(); } int -- 2.20.1