On 06/08/21(Fri) 08:08, Theo Buehler wrote:
> > The diff below fixes this by setting the "source" amap lock to the newly
> > allocated one.  This is not strictly necessary on OpenBSD since the amap
> > is only inserted on the global list at the end of amap copy, but this
> > satisfies the locking requirement of amap_wipeout() and is IMHO the
> > simplest solution.  This has also the advantage of reducing the
> > differences with NetBSD.
> 
> This diff causes a reproducible hang with mount_mfs(8) on my laptop. I
> use an mfs noperm partition as described in
> https://www.openbsd.org/faq/faq5.html#Release
> 
> $ tail -1 /etc/fstab
> swap /dest mfs rw,nosuid,noperm,-P/var/dest,-s1.5G,noauto 0 0
> 
> If I run 'top -S -s.1' on an otherwise idle system and do 'mount /dest',
> I see two mount_mfs(8) processes spin in fltamap and the pagedaemon is
> spinning in pgdaemon before the system locks up completely (this takes
> something between 1 and 20 seconds to happen).

I couldn't reproduce this hang here.  Do you also see it with the
smaller fix below?

Index: uvm/uvm_amap.c
===================================================================
RCS file: /cvs/src/sys/uvm/uvm_amap.c,v
retrieving revision 1.89
diff -u -p -r1.89 uvm_amap.c
--- uvm/uvm_amap.c      26 Mar 2021 13:40:05 -0000      1.89
+++ uvm/uvm_amap.c      30 Aug 2021 08:31:21 -0000
@@ -618,6 +618,13 @@ amap_copy(struct vm_map *map, struct vm_
                return;
        srcamap = entry->aref.ar_amap;
 
+       /*
+        * Make the new amap share the source amap's lock, and then lock
+        * both.
+        */
+       amap->am_lock = srcamap->am_lock;
+       rw_obj_hold(amap->am_lock);
+
        amap_lock(srcamap);
 
        /*
@@ -655,7 +662,7 @@ amap_copy(struct vm_map *map, struct vm_
 
                chunk = amap_chunk_get(amap, lcv, 1, PR_NOWAIT);
                if (chunk == NULL) {
-                       amap_unlock(srcamap);
+                       /* amap_wipeout() releases the lock. */
                        amap->am_ref = 0;
                        amap_wipeout(amap);
                        return;
@@ -695,10 +702,10 @@ amap_copy(struct vm_map *map, struct vm_
         * If we referenced any anons, then share the source amap's lock.
         * Otherwise, we have nothing in common, so allocate a new one.
         */
-       KASSERT(amap->am_lock == NULL);
-       if (amap->am_nused != 0) {
-               amap->am_lock = srcamap->am_lock;
-               rw_obj_hold(amap->am_lock);
+       KASSERT(amap->am_lock == srcamap->am_lock);
+       if (amap->am_nused == 0) {
+               rw_obj_free(amap->am_lock);
+               amap->am_lock = NULL;
        }
        amap_unlock(srcamap);
 

Reply via email to