NetBSD Problem Report #56788

From gson@gson.org  Sun Apr 10 11:32:58 2022
Return-Path: <gson@gson.org>
Received: from mail.netbsd.org (mail.netbsd.org [199.233.217.200])
	(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits))
	(Client CN "mail.NetBSD.org", Issuer "mail.NetBSD.org CA" (not verified))
	by mollari.NetBSD.org (Postfix) with ESMTPS id 60D641A921F
	for <gnats-bugs@gnats.NetBSD.org>; Sun, 10 Apr 2022 11:32:58 +0000 (UTC)
Message-Id: <20220410113250.64ED02546F8@guava.gson.org>
Date: Sun, 10 Apr 2022 14:32:50 +0300 (EEST)
From: gson@gson.org (Andreas Gustafsson)
Reply-To: gson@gson.org (Andreas Gustafsson)
To: gnats-bugs@NetBSD.org
Subject: Rump kernel panic: kernel diagnostic assertion "old == LOCK_LOCKED" failed
X-Send-Pr-Version: 3.95

>Number:         56788
>Category:       port-sparc
>Synopsis:       Rump kernel panic: kernel diagnostic assertion "old == LOCK_LOCKED" failed
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    port-sparc-maintainer
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sun Apr 10 11:35:00 +0000 2022
>Last-Modified:  Mon Jun 20 02:40:01 +0000 2022
>Originator:     Andreas Gustafsson
>Release:        NetBSD-current of 2011 to present
>Organization:

>Environment:
System: NetBSD
Architecture: sparc
Machine: sparc
>Description:

On the TNF sparc testbed, various networking tests randomly fail with
a rump kernel panic:

  [   1.3700050] panic: kernel diagnostic assertion "old == LOCK_LOCKED" failed: file "/tmp/build/2022.04.05.05.04.04-sparc/src/sys/rump/net/lib/libshmif/if_shmem.c", line 157

Logs from the most recent occurrences:

  http://releng.netbsd.org/b5reports/sparc/2022/2022.03.25.23.16.04/test.html#net_icmp_t_ping_ping_of_death

  http://releng.netbsd.org/b5reports/sparc/2022/2022.03.29.22.29.29/test.html#net_icmp_t_ping_pingsize

  http://releng.netbsd.org/b5reports/sparc/2022/2022.04.05.05.04.04/test.html#net_bpfilter_t_bpfilter_bpfiltermchain

This is a long-standing issue, going back at least to 2011.  I have
not seen it on architectures other than sparc.

>How-To-Repeat:

>Fix:

>Audit-Trail:
From: Tom Lane <tgl@sss.pgh.pa.us>
To: gnats-bugs@NetBSD.org
Cc: port-hppa-maintainer@netbsd.org
Subject: Re: port-sparc/56788 Rump kernel panic: kernel diagnostic assertion "old == LOCK_LOCKED" failed
Date: Sun, 12 Jun 2022 14:19:35 -0400

 Andreas Gustafsson writes:
 > On the TNF sparc testbed, various networking tests randomly fail with
 > a rump kernel panic:
 >  [   1.3700050] panic: kernel diagnostic assertion "old =3D=3D LOCK_LOCK=
 ED" failed: file "/tmp/build/2022.04.05.05.04.04-sparc/src/sys/rump/net/li=
 b/libshmif/if_shmem.c", line 157
 > This is a long-standing issue, going back at least to 2011.  I have
 > not seen it on architectures other than sparc.

 I see this on HPPA as well, and I concur that it seems to be the
 underlying cause of intermittent failures in various ATF net/ tests.
 For example, if I run

 $ while /usr/tests/net/icmp/t_ping floodping2
 do
 :
 done

 for awhile, many iterations produce such a report -- though t_ping
 usually claims it succeeded anyway.  Maybe it's atf-run's responsibility
 to notice rump kernel failure?

 The failing assertion is in shmif_unlockbus():

         old =3D atomic_swap_32(&busmem->shm_lock, LOCK_UNLOCKED);
         KASSERT(old =3D=3D LOCK_LOCKED);

 which for me immediately raises the suspicion that something's busted
 in either atomic_swap_32 or atomic_cas_32 (the function used earlier to
 acquire the shm_lock).  On HPPA, atomic_swap_32 is implemented atop
 atomic_cas_32, so that reduces to just one target of suspicion.  In
 kernel space, atomic_cas_32 is supposed to be implemented by _lock_cas
 in lock_stubs.S, and (on my uniprocessor machine) that is a non-atomic
 instruction sequence that is supposed to be made to act atomic by the
 RAS restart mechanism.  I can think of a few ways this might be going
 wrong:

 1. Maybe the rump kernel is linked to the userspace version of
 atomic_cas_32, so that the address range being defended by the RAS
 mechanism is the wrong one.

 2. Maybe the rump kernel fails to implement the RAS checks in the
 traps it takes.

 3. Maybe this is related to PR 56837, and there is some case where
 we can trap at _lock_cas_ras_start with tf_iioq_tail different from
 _lock_cas_ras_start + 4.

 It looks like uniprocessor SPARC also relies on RAS to make =

 atomic_cas_32 atomic, so Occam's razor suggests that the failure
 mechanism is the same on both archs, which would favor explanation
 1 or 2 over 3.  However, then we'd expect to see these on every
 arch that uses RAS for atomic_cas_32, which I think is more than
 SPARC and HPPA.

 I just managed to get a core dump out of t_ping with librumpnet_shmif.so
 attached, and it kind of looks like theory #1 might be the winner:

 (gdb) x/16i atomic_cas_32
    0xad53e0c0 <_atomic_cas_32>: addil L%2800,r19,r1
    0xad53e0c4 <_atomic_cas_32+4>:       ldw 3a4(r1),ret0
    0xad53e0c8 <_atomic_cas_32+8>:       stw rp,-14(sp)
    0xad53e0cc <_atomic_cas_32+12>:      stw,ma r4,40(sp)
    0xad53e0d0 <_atomic_cas_32+16>:      stw r19,-20(sp)
    0xad53e0d4 <_atomic_cas_32+20>:      ldw 0(ret0),r22
    0xad53e0d8 <_atomic_cas_32+24>:      b,l 0xad5375e8,r31
    0xad53e0dc <_atomic_cas_32+28>:      copy r31,rp
    0xad53e0e0 <_atomic_cas_32+32>:      ldw -54(sp),rp
    0xad53e0e4 <_atomic_cas_32+36>:      bv r0(rp)
    0xad53e0e8 <_atomic_cas_32+40>:      ldw,mb -40(sp),r4
    0xad53e0ec <_atomic_cas_16>: addil L%2800,r19,r1
    0xad53e0f0 <_atomic_cas_16+4>:       ldw 3a8(r1),ret0
    0xad53e0f4 <_atomic_cas_16+8>:       stw rp,-14(sp)
    0xad53e0f8 <_atomic_cas_16+12>:      extrw,u r24,31,16,r24
    0xad53e0fc <_atomic_cas_16+16>:      stw,ma r4,40(sp)

 This is not the code from lock_stubs.S.

 Maybe there is an arch-specific linking problem here?  Or maybe I don't
 understand how this stuff is supposed to work in a rump kernel.
 But in any case my money is on RAS not doing what it needs to.

 			regards, tom lane

From: matthew green <mrg@eterna.com.au>
To: gnats-bugs@netbsd.org
Cc: port-sparc-maintainer@netbsd.org, gnats-admin@netbsd.org,
    netbsd-bugs@netbsd.org, gson@gson.org (Andreas Gustafsson)
Subject: re: port-sparc/56788 Rump kernel panic: kernel diagnostic assertion "old == LOCK_LOCKED" failed
Date: Mon, 13 Jun 2022 10:07:12 +1000

 sys/arch/hppa/hppa/lock_stubs.S is kernel-only.  looks like
 the hppa one comes here:

 libc.a:atomic_init_testset.o:0000013c T _atomic_cas_32


 .mrg.

From: Nick Hudson <nick.hudson@gmx.co.uk>
To: matthew green <mrg@eterna.com.au>, gnats-bugs@netbsd.org
Cc: port-sparc-maintainer@netbsd.org, gnats-admin@netbsd.org,
 netbsd-bugs@netbsd.org, Andreas Gustafsson <gson@gson.org>
Subject: Re: port-sparc/56788 Rump kernel panic: kernel diagnostic assertion
 "old == LOCK_LOCKED" failed
Date: Mon, 13 Jun 2022 12:55:59 +0100

 On 13/06/2022 01:07, matthew green wrote:
 > sys/arch/hppa/hppa/lock_stubs.S is kernel-only.  looks like
 > the hppa one comes here:
 >
 > libc.a:atomic_init_testset.o:0000013c T _atomic_cas_32

 I think that some (more) magic needs to be added so that the RAS section
 of rumpns__atomic_cas_32 needs the appropriate rasctl(2) call.


 Nick

From: Tom Lane <tgl@sss.pgh.pa.us>
To: gnats-bugs@NetBSD.org, port-hppa-maintainer@netbsd.org
Cc: 
Subject: Re: port-sparc/56788 Rump kernel panic: kernel diagnostic assertion "old == LOCK_LOCKED" failed
Date: Tue, 14 Jun 2022 21:18:21 -0400

 > I think that some (more) magic needs to be added so that the RAS section
 > of rumpns__atomic_cas_32 needs the appropriate rasctl(2) call.

 Hmm.  I've not found what bit of magic prepends "rumpns_" to the symbol
 visible in the source code, but I wonder whether the RAS_ADDR() macro
 talks to it.  Maybe librump's copy of __libc_atomic_init is redundantly
 re-registering the RAS address ranges in libc's atomic_init_testset.o,
 rather than the ones in librump's copy?

 			regards, tom lane

From: Nick Hudson <nick.hudson@gmx.co.uk>
To: Tom Lane <tgl@sss.pgh.pa.us>, gnats-bugs@NetBSD.org,
 port-hppa-maintainer@netbsd.org
Cc: 
Subject: Re: port-sparc/56788 Rump kernel panic: kernel diagnostic assertion
 "old == LOCK_LOCKED" failed
Date: Wed, 15 Jun 2022 07:22:40 +0100

 On 15/06/2022 02:18, Tom Lane wrote:
 >> I think that some (more) magic needs to be added so that the RAS sectio=
 n
 >> of rumpns__atomic_cas_32 needs the appropriate rasctl(2) call.
 >
 > Hmm.  I've not found what bit of magic prepends "rumpns_" to the symbol
 > visible in the source code, but I wonder whether the RAS_ADDR() macro
 > talks to it.  Maybe librump's copy of __libc_atomic_init is redundantly
 > re-registering the RAS address ranges in libc's atomic_init_testset.o,
 > rather than the ones in librump's copy?

 who knows? I'm not a member of the magic circle

 I think this is where the symbol renaming happens

 https://nxr.netbsd.org/xref/src/sys/rump/Makefile.rump#255

 Nick

From: Tom Lane <tgl@sss.pgh.pa.us>
To: gnats-bugs@NetBSD.org
Cc: port-hppa-maintainer@netbsd.org
Subject: Re: port-sparc/56788 Rump kernel panic: kernel diagnostic assertion "old == LOCK_LOCKED" failed
Date: Fri, 17 Jun 2022 17:46:19 -0400

 I've spent a great deal of time digging into the t_ping test case,
 and I think I see what is happening on HPPA ... but I'm not sure
 if it explains anything for SPARC.

 In the first place, my theory about bogus RAS setup is all wet.
 What's actually being used in librump for HPPA is
 sys/rump/librump/rumpkern/atomic_cas_generic.c
 which does not use the RAS mechanism.  Instead it relies on
 __cpu_simple_lock() which is a simple LDCW spinlock, which looks
 entirely bulletproof --- but by experiment, it fails intermittently
 in various t_ping test cases.  I eventually realized that each
 of the problem tests is forking a child process and then running
 rump kernels in both the parent and child processes.  The two
 kernels communicate via a memory-mapped host file (cf
 rump_pub_shmif_create) and we're trying to synchronize via
 atomic_cas_32() applied to a word in that shared memory.  That's
 fine, but what makes atomic_cas_32 actually atomic?  AFAICS, the
 LDCW spinlock storage is a static array in atomic_cas_generic.c,
 which means that *each rump kernel has its own copy* after the
 fork.  Therefore, __cpu_simple_lock() successfully interlocks
 between threads in each rump kernel, but not between threads in
 the two kernels, making atomic_cas_32() not at all atomic for
 if_shmem.c's "bus" lock.

 According to Makefile.rumpkern, atomic_cas_generic.c is used on

 .if (${MACHINE_CPU} == "arm" && "${FEAT_LDREX}" != "yes") \
     || ${MACHINE_ARCH} == "coldfire" || ${MACHINE_CPU} == "hppa" \
     || ${MACHINE_CPU} == "mips" || ${MACHINE_CPU} == "sh3" \
     || ${MACHINE_ARCH} == "vax" || ${MACHINE_ARCH} == "m68000"

 so I'd kind of expect these tests to fail on all of those arches.
 (Their spinlock mechanisms vary of course, but the problem of
 the spinlock data being process-local will be the same for all.)
 It's striking though that SPARC is not in this list.  Perhaps
 it has some related failure mechanism?  I see that
 src/common/lib/libc/arch/sparc/atomic/atomic_cas.S
 makes use of a "locktab array" that looks like it'd have the
 same problem of being process-local, but I am not sure if that
 code is used in a rump kernel, or whether it applies to the
 SPARC variant being complained of here.

 Anyway, I'm not sure that I see a practical solution to make
 these test cases work on these arches.  Potentially we could
 add a spinlock field to struct shmif_mem, but getting
 atomic_cas_32 to use it would entail some ugly API changes.
 Maybe it's better just to skip the problematic test cases
 on these arches.

 			regards, tom lane

From: Tom Lane <tgl@sss.pgh.pa.us>
To: gnats-bugs@NetBSD.org
Cc: port-hppa-maintainer@netbsd.org
Subject: Re: port-sparc/56788 Rump kernel panic: kernel diagnostic assertion "old == LOCK_LOCKED" failed
Date: Fri, 17 Jun 2022 19:47:37 -0400

 ... BTW, I now believe that this same issue affects a number of
 other test cases that have been unstable for me, including

 net/if_gif/t_gif:gif_basic_ipv6overipv6
 net/if_ipsec/t_ipsec:ipsecif_recursive_ipv6overipv4_esp_null
 net/if_lagg/t_lagg:lagg_lacp_vlan_ipv6
 net/if_lagg/t_lagg:lagg_lacp_vlanl2tp_ipv6
 net/if_wg/t_basic:wg_basic_ipv6_over_ipv6
 net/if_wg/t_basic:wg_payload_sizes_ipv4_over_ipv4
 net/if_wg/t_basic:wg_payload_sizes_ipv6_over_ipv6
 net/if_wg/t_tunnel:wg_tunnel_ipv6_over_ipv4
 net/mpls/t_ldp_regen:ldp_regen

 I see some of these also failing in the ARMv5 tests at
 https://www.netbsd.org/~martin/evbarm-atf/
 which is very likely the same issue given that old ARM is
 one of the affected arches.

 Maybe there's enough test cases here to justify a messy solution?
 I'm wondering about arranging for atomic_cas_generic.c's spinlock
 array to be kept in shared memory somehow.

 			regards, tom lane

From: matthew green <mrg@eterna.com.au>
To: gnats-bugs@netbsd.org, tgl@sss.pgh.pa.us
Cc: port-sparc-maintainer@netbsd.org, gnats-admin@netbsd.org,
    netbsd-bugs@netbsd.org, gson@gson.org (Andreas Gustafsson)
Subject: re: port-sparc/56788 Rump kernel panic: kernel diagnostic assertion "old == LOCK_LOCKED" failed
Date: Sat, 18 Jun 2022 13:33:35 +1000

 nice work Tom.

 >  It's striking though that SPARC is not in this list.  Perhaps
 >  it has some related failure mechanism?  I see that
 >  src/common/lib/libc/arch/sparc/atomic/atomic_cas.S
 >  makes use of a "locktab array" that looks like it'd have the
 >  same problem of being process-local, but I am not sure if that
 >  code is used in a rump kernel, or whether it applies to the
 >  SPARC variant being complained of here.

 yeah - sparc uses a similar mechanism last i looked at this,
 and tried to figured out why rump_server and more would not
 exit on sparc, and it always came down to mutexes not working
 like you're described here, but i didn't think about shared
 process spaces not being shared now.

 we knew this was a problem with some code bases (eg, related
 to shared futexes), but i did not know this was used by our
 own code/tests.


 .mrg.

From: Tom Lane <tgl@sss.pgh.pa.us>
To: gnats-bugs@NetBSD.org
Cc: port-hppa-maintainer@netbsd.org
Subject: Re: port-sparc/56788 Rump kernel panic: kernel diagnostic assertion "old == LOCK_LOCKED" failed
Date: Sun, 19 Jun 2022 22:36:31 -0400

 ------- =_aaaaaaaaaa0
 Content-Type: text/plain; charset="us-ascii"
 Content-ID: <2324668.1655692526.1@sss.pgh.pa.us>

 I wrote:
 > I'm wondering about arranging for atomic_cas_generic.c's spinlock
 > array to be kept in shared memory somehow.

 Attached is a very dirty proof-of-concept patch that does the above.
 The good news is that it seems to completely resolve the t_ping test
 failures for me.  The bad news is that (1) there's a lot of work
 left to make this committable, and (2) for me, it doesn't seem to
 fix any other tests besides t_ping.  (2) suggests that the path of
 least resistance is to just disable that test on affected arches.
 OTOH, it seems likely that more tests will hit this in future,
 so maybe it's worth doing the requisite amount of work for.

 I don't have the ability to take this any further, but if someone
 else wants to, what remains to be done includes:

 * It's not clear to me how to handle the fact that
 make_atomic_cas_globally_atomic() is only needed on some arches.
 I'm sure there's a convention for that, I just don't know it.

 * This probably violates a lot of other NetBSD style as well.

 * I've not done anything about the SPARC situation.  Probably
 atomic_cas.S could be adapted to use a similar mechanism, but
 maybe it'd be better to start using atomic_cas_generic.c
 in the SPARC rump kernel?

 			regards, tom lane


 ------- =_aaaaaaaaaa0
 Content-Type: text/x-diff; name="global-atomic-cas.patch";
 	charset="us-ascii"
 Content-ID: <2324668.1655692526.2@sss.pgh.pa.us>
 Content-Description: global-atomic-cas.patch
 Content-Transfer-Encoding: quoted-printable

 Index: lib/librumpuser/rumpuser_mem.c
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
 RCS file: /cvsroot/src/lib/librumpuser/rumpuser_mem.c,v
 retrieving revision 1.2
 diff -u -r1.2 rumpuser_mem.c
 --- lib/librumpuser/rumpuser_mem.c	24 Aug 2014 14:37:31 -0000	1.2
 +++ lib/librumpuser/rumpuser_mem.c	20 Jun 2022 02:16:10 -0000
 @@ -102,6 +102,44 @@
  	ET(rv);
  }
  =

 +int
 +rumpuser_filemmap(void *prefaddr, int fd, size_t size, int alignbit,
 +	int exec, void **memp)
 +{
 +	void *mem;
 +	int prot, rv;
 +
 +	if (ftruncate(fd, size) =3D=3D -1) {
 +		rv =3D errno;
 +		ET(rv);
 +	}
 +
 +#ifndef MAP_ALIGNED
 +#define MAP_ALIGNED(a) 0
 +	if (alignbit)
 +		fprintf(stderr, "rumpuser_filemmap: warning, requested "
 +		    "alignment not supported by hypervisor\n");
 +#endif
 +
 +#if defined(__sun__) && !defined(MAP_FILE)
 +#define MAP_FILE 0
 +#endif
 +
 +	prot =3D PROT_READ|PROT_WRITE;
 +	if (exec)
 +		prot |=3D PROT_EXEC;
 +	mem =3D mmap(prefaddr, size, prot,
 +		MAP_FILE | MAP_SHARED | MAP_ALIGNED(alignbit), fd, 0);
 +	if (mem =3D=3D MAP_FAILED) {
 +		rv =3D errno;
 +	} else {
 +		*memp =3D mem;
 +		rv =3D 0;
 +	}
 +
 +	ET(rv);
 +}
 +
  void
  rumpuser_unmap(void *addr, size_t len)
  {
 Index: sys/rump/include/rump/rumpuser.h
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
 RCS file: /cvsroot/src/sys/rump/include/rump/rumpuser.h,v
 retrieving revision 1.116
 diff -u -r1.116 rumpuser.h
 --- sys/rump/include/rump/rumpuser.h	22 Mar 2020 13:30:10 -0000	1.116
 +++ sys/rump/include/rump/rumpuser.h	20 Jun 2022 02:16:12 -0000
 @@ -74,6 +74,7 @@
  int rumpuser_malloc(size_t, int, void **);
  void rumpuser_free(void *, size_t);
  int rumpuser_anonmmap(void *, size_t, int, int, void **);
 +int rumpuser_filemmap(void *, int, size_t, int, int, void **);
  void  rumpuser_unmap(void *, size_t);
  =

  /*
 Index: sys/rump/librump/rumpkern/atomic_cas_generic.c
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
 RCS file: /cvsroot/src/sys/rump/librump/rumpkern/atomic_cas_generic.c,v
 retrieving revision 1.3
 diff -u -r1.3 atomic_cas_generic.c
 --- sys/rump/librump/rumpkern/atomic_cas_generic.c	14 Mar 2021 22:56:39 -0=
 000	1.3
 +++ sys/rump/librump/rumpkern/atomic_cas_generic.c	20 Jun 2022 02:16:12 -0=
 000
 @@ -33,6 +33,13 @@
   * This is basically common/lib/libc/atomic/atomic_init_testset.c
   * which always assumes MP and never uses RAS.  This is used only on
   * some archs.  See Makefile.rumpkern for more information.
 + *
 + * We provide atomicity by using spinlocks; to avoid unnecessary contenti=
 on,
 + * one of several spinlocks is chosen based on the address of the target =
 word.
 + * Ordinarily, we only need to interlock between threads in a single proc=
 ess,
 + * so that a plain static array of spinlocks is fine.  But some tests req=
 uire
 + * interlocking between threads in different processes.  To support that,
 + * we can move the spinlock array into shared memory.
   */
  =

  #include "atomic_op_namespace.h"
 @@ -40,12 +47,26 @@
  #include <sys/types.h>
  #include <sys/atomic.h>
  #include <sys/lock.h>
 +#include <sys/errno.h>
 +
 +#include <rump/rump.h>
 +#include <rump/rumpuser.h>
 +
 +struct atomic_locks_shmem {
 +    __cpu_simple_lock_t shared_atomic_locks[128];
 +    int atomic_locks_magic;
 +#define ATOMIC_LOCKS_MAGIC 0x58274727
 +};
 +
 +static int make_one_spinlock_file(const char *path, =

 +		       __cpu_simple_lock_t **atomic_locks_ptr);
  =

  #define	I2	__SIMPLELOCK_UNLOCKED, __SIMPLELOCK_UNLOCKED,
  #define	I16	I2 I2 I2 I2 I2 I2 I2 I2
  #define	I128	I16 I16 I16 I16 I16 I16 I16 I16
  =

 -static __cpu_simple_lock_t atomic_locks32[128] =3D { I128 };
 +static __cpu_simple_lock_t static_atomic_locks32[128] =3D { I128 };
 +static __cpu_simple_lock_t *atomic_locks32 =3D static_atomic_locks32;
  =

  uint32_t
  _atomic_cas_32(volatile uint32_t *ptr, uint32_t old, uint32_t new)
 @@ -53,6 +74,14 @@
  	__cpu_simple_lock_t *lock;
  	uint32_t ret;
  =

 +	/*
 +	 * Note that we use only the low-order 10 bits of the ptr to choose a
 +	 * spinlock.  If the target word is in shared memory, it's possible that
 +	 * different processes would have it mapped at different addresses.  But
 +	 * so long as all processes map the shared memory on a VM page boundary,
 +	 * and the page size is at least 1KB, we'll choose the same spinlock in
 +	 * all processes.
 +	 */
  	lock =3D &atomic_locks32[((uintptr_t)ptr >> 3) & 127];
  	__cpu_simple_lock(lock);
  	ret =3D *ptr;
 @@ -70,7 +99,8 @@
  __strong_alias(_atomic_cas_32_ni,_atomic_cas_32)
  =

  #ifdef _LP64
 -static __cpu_simple_lock_t atomic_locks64[128] =3D { I128 };
 +static __cpu_simple_lock_t static_atomic_locks64[128] =3D { I128 };
 +static __cpu_simple_lock_t *atomic_locks64 =3D static_atomic_locks64;
  =

  uint64_t
  _atomic_cas_64(volatile uint64_t *ptr, uint64_t old, uint64_t new)
 @@ -78,7 +108,8 @@
  	__cpu_simple_lock_t *lock;
  	uint64_t ret;
  =

 -	lock =3D &atomic_locks64[((uintptr_t)ptr >> 4) & 127];
 +	/* See comment above about using only 10 bits of the ptr */
 +	lock =3D &atomic_locks64[((uintptr_t)ptr >> 3) & 127];
  	__cpu_simple_lock(lock);
  	ret =3D *ptr;
  	if (__predict_true(ret =3D=3D old)) {
 @@ -124,3 +155,106 @@
  atomic_op_alias(atomic_cas_ptr_ni,_atomic_cas_32)
  __strong_alias(_atomic_cas_ptr_ni,_atomic_cas_32)
  #endif
 +
 +/*
 + * Move the atomic_cas_generic spinlocks into shared memory,
 + * so that atomicity is guaranteed across multiple processes.
 + * This is a no-op if it was already done in this process.
 + * Returns 0 if okay, else an errno code.
 + */
 +extern int make_atomic_cas_globally_atomic(void); /* XXX where to put thi=
 s? */
 +
 +int
 +make_atomic_cas_globally_atomic(void)
 +{
 +	int error;
 +
 +	if (atomic_locks32 =3D=3D static_atomic_locks32) {
 +		error =3D make_one_spinlock_file("netbsd-atomic-cas-32-spinlocks",
 +					       &atomic_locks32);
 +		if (error)
 +			return error;
 +	}
 +#ifdef _LP64
 +	if (atomic_locks64 =3D=3D static_atomic_locks64) {
 +		error =3D make_one_spinlock_file("netbsd-atomic-cas-64-spinlocks",
 +					       &atomic_locks64);
 +		if (error)
 +			return error;
 +	}
 +#endif
 +	return 0;
 +}
 +
 +static int
 +make_one_spinlock_file(const char *path, =

 +		       __cpu_simple_lock_t **atomic_locks_ptr)
 +{
 +	bool created_it =3D false;
 +	int memfd =3D -1; /* XXXgcc */
 +	void *mem;
 +	struct atomic_locks_shmem *almem;
 +	int error;
 +
 +	/*
 +	 * Create or open the backing file, detecting if we created it.
 +	 *
 +	 * XXX there's no provision to remove it at shutdown.  This doesn't
 +	 * matter in typical use under atf-run, and even when not doing that,
 +	 * it's not terribly harmful if the file stays around.  One might
 +	 * need to manually remove it if a rump kernel crashes while holding
 +	 * one of the spinlocks, but that should be mighty rare.
 +	 */
 +	while ((error =3D rumpuser_open(path,
 +				      RUMPUSER_OPEN_RDWR, &memfd)) !=3D 0)
 +	{
 +	    if (error !=3D ENOENT)
 +		return error;
 +	    error =3D rumpuser_open(path,
 +		RUMPUSER_OPEN_RDWR | RUMPUSER_OPEN_CREATE | RUMPUSER_OPEN_EXCL,
 +		&memfd);
 +	    if (error) {
 +		if (error !=3D EEXIST)
 +		    return error;
 +		continue;	/* try again to open without creating */
 +	    }
 +	    created_it =3D true;
 +	    break;
 +	}
 +
 +	/* Map it */
 +	error =3D rumpuser_filemmap(NULL, memfd, sizeof(*almem), 0, 0, &mem);
 +	if (error) {
 +		rumpuser_close(memfd);
 +		/* XXX unlink if created_it? */
 +		return error;
 +	}
 +	almem =3D mem;
 +
 +	/*
 +	 * If we created it, initialize the shared spinlocks.  Otherwise,
 +	 * wait if necessary for the creator to do so.
 +	 */
 +	if (created_it) {
 +	    KASSERT(almem->atomic_locks_magic =3D=3D 0);
 +	    for (int i =3D 0; i < 128; i++)
 +		__cpu_simple_lock_init(&almem->shared_atomic_locks[i]);
 +	    almem->atomic_locks_magic =3D ATOMIC_LOCKS_MAGIC;
 +	} else {
 +	    while (almem->atomic_locks_magic !=3D ATOMIC_LOCKS_MAGIC)
 +		(void) rumpuser_clock_sleep(RUMPUSER_CLOCK_RELWALL,
 +					    0, 10000000);
 +	}
 +
 +	/*
 +	 * Now replace the pointer to the static spinlock array with the
 +	 * address of the shared spinlocks array.  This is a bit shaky
 +	 * because in principle some other threads in our own process could
 +	 * be contending for a lock, and this could transiently let them both
 +	 * think they got it.  In practice this function should only be
 +	 * called during fairly early initialization, so the risk seems low.
 +	 */
 +	*atomic_locks_ptr =3D almem->shared_atomic_locks;
 +
 +	return 0;
 +}
 Index: sys/rump/net/lib/libshmif/if_shmem.c
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
 RCS file: /cvsroot/src/sys/rump/net/lib/libshmif/if_shmem.c,v
 retrieving revision 1.84
 diff -u -r1.84 if_shmem.c
 --- sys/rump/net/lib/libshmif/if_shmem.c	9 Apr 2022 23:45:02 -0000	1.84
 +++ sys/rump/net/lib/libshmif/if_shmem.c	20 Jun 2022 02:16:12 -0000
 @@ -56,6 +56,8 @@
  =

  #include "shmif_user.h"
  =

 +extern int make_atomic_cas_globally_atomic(void); /* XXX where to put thi=
 s? */
 +
  static int shmif_clone(struct if_clone *, int);
  static int shmif_unclone(struct ifnet *);
  =

 @@ -240,6 +242,10 @@
  	void *mem;
  	int error;
  =

 +	error =3D make_atomic_cas_globally_atomic();
 +	if (error)
 +		return error;
 +
  	error =3D rumpcomp_shmif_mmap(memfd, BUSMEM_SIZE, &mem);
  	if (error)
  		return error;

 ------- =_aaaaaaaaaa0--

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.46 2020/01/03 16:35:01 leot Exp $
$NetBSD: gnats_config.sh,v 1.9 2014/08/02 14:16:04 spz Exp $
Copyright © 1994-2020 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.