On 11/09/22(Sun) 12:26, Martin Pieuchot wrote:
> Diff below adds a minimalist set of assertions to ensure proper locks
> are held in uvm_mapanon() and uvm_unmap_remove() which are the guts of
> mmap(2) for anons and munmap(2).
> 
> Please test it with WITNESS enabled and report back.

New version of the diff that includes a lock/unlock dance  in 
uvm_map_teardown().  While grabbing this lock should not be strictly
necessary because no other reference to the map should exist when the
reaper is holding it, it helps make progress with asserts.  Grabbing
the lock is easy and it can also save us a lot of time if there is any
reference counting bugs (like we've discovered w/ vnode and swapping).

Please test and report back.

Index: uvm/uvm_addr.c
===================================================================
RCS file: /cvs/src/sys/uvm/uvm_addr.c,v
retrieving revision 1.31
diff -u -p -r1.31 uvm_addr.c
--- uvm/uvm_addr.c      21 Feb 2022 10:26:20 -0000      1.31
+++ uvm/uvm_addr.c      20 Oct 2022 14:09:30 -0000
@@ -416,6 +416,8 @@ uvm_addr_invoke(struct vm_map *map, stru
            !(hint >= uaddr->uaddr_minaddr && hint < uaddr->uaddr_maxaddr))
                return ENOMEM;
 
+       vm_map_assert_anylock(map);
+
        error = (*uaddr->uaddr_functions->uaddr_select)(map, uaddr,
            entry_out, addr_out, sz, align, offset, prot, hint);
 
Index: uvm/uvm_fault.c
===================================================================
RCS file: /cvs/src/sys/uvm/uvm_fault.c,v
retrieving revision 1.132
diff -u -p -r1.132 uvm_fault.c
--- uvm/uvm_fault.c     31 Aug 2022 01:27:04 -0000      1.132
+++ uvm/uvm_fault.c     20 Oct 2022 14:09:30 -0000
@@ -1626,6 +1626,7 @@ uvm_fault_unwire_locked(vm_map_t map, va
        struct vm_page *pg;
 
        KASSERT((map->flags & VM_MAP_INTRSAFE) == 0);
+       vm_map_assert_anylock(map);
 
        /*
         * we assume that the area we are unwiring has actually been wired
Index: uvm/uvm_map.c
===================================================================
RCS file: /cvs/src/sys/uvm/uvm_map.c,v
retrieving revision 1.298
diff -u -p -r1.298 uvm_map.c
--- uvm/uvm_map.c       16 Oct 2022 16:16:37 -0000      1.298
+++ uvm/uvm_map.c       20 Oct 2022 14:09:31 -0000
@@ -491,6 +491,8 @@ uvmspace_dused(struct vm_map *map, vaddr
        vaddr_t stack_begin, stack_end; /* Position of stack. */
 
        KASSERT(map->flags & VM_MAP_ISVMSPACE);
+       vm_map_assert_anylock(map);
+
        vm = (struct vmspace *)map;
        stack_begin = MIN((vaddr_t)vm->vm_maxsaddr, (vaddr_t)vm->vm_minsaddr);
        stack_end = MAX((vaddr_t)vm->vm_maxsaddr, (vaddr_t)vm->vm_minsaddr);
@@ -570,6 +572,8 @@ uvm_map_isavail(struct vm_map *map, stru
        if (addr + sz < addr)
                return 0;
 
+       vm_map_assert_anylock(map);
+
        /*
         * Kernel memory above uvm_maxkaddr is considered unavailable.
         */
@@ -1457,6 +1461,8 @@ uvm_map_mkentry(struct vm_map *map, stru
        entry->guard = 0;
        entry->fspace = 0;
 
+       vm_map_assert_wrlock(map);
+
        /* Reset free space in first. */
        free = uvm_map_uaddr_e(map, first);
        uvm_mapent_free_remove(map, free, first);
@@ -1584,6 +1590,8 @@ boolean_t
 uvm_map_lookup_entry(struct vm_map *map, vaddr_t address,
     struct vm_map_entry **entry)
 {
+       vm_map_assert_anylock(map);
+
        *entry = uvm_map_entrybyaddr(&map->addr, address);
        return *entry != NULL && !UVM_ET_ISHOLE(*entry) &&
            (*entry)->start <= address && (*entry)->end > address;
@@ -1704,6 +1712,8 @@ uvm_map_is_stack_remappable(struct vm_ma
        vaddr_t end = addr + sz;
        struct vm_map_entry *first, *iter, *prev = NULL;
 
+       vm_map_assert_anylock(map);
+
        if (!uvm_map_lookup_entry(map, addr, &first)) {
                printf("map stack 0x%lx-0x%lx of map %p failed: no mapping\n",
                    addr, end, map);
@@ -1868,6 +1878,8 @@ uvm_mapent_mkfree(struct vm_map *map, st
        vaddr_t                  addr;  /* Start of freed range. */
        vaddr_t                  end;   /* End of freed range. */
 
+       UVM_MAP_REQ_WRITE(map);
+
        prev = *prev_ptr;
        if (prev == entry)
                *prev_ptr = prev = NULL;
@@ -1996,10 +2008,7 @@ uvm_unmap_remove(struct vm_map *map, vad
        if (start >= end)
                return 0;
 
-       if ((map->flags & VM_MAP_INTRSAFE) == 0)
-               splassert(IPL_NONE);
-       else
-               splassert(IPL_VM);
+       vm_map_assert_wrlock(map);
 
        /* Find first affected entry. */
        entry = uvm_map_entrybyaddr(&map->addr, start);
@@ -2526,6 +2535,8 @@ uvm_map_teardown(struct vm_map *map)
 
        KASSERT((map->flags & VM_MAP_INTRSAFE) == 0);
 
+       vm_map_lock(map);
+
        /* Remove address selectors. */
        uvm_addr_destroy(map->uaddr_exe);
        map->uaddr_exe = NULL;
@@ -2567,6 +2578,8 @@ uvm_map_teardown(struct vm_map *map)
                entry = TAILQ_NEXT(entry, dfree.deadq);
        }
 
+       vm_map_unlock(map);
+
 #ifdef VMMAP_DEBUG
        numt = numq = 0;
        RBT_FOREACH(entry, uvm_map_addr, &map->addr)
@@ -4071,6 +4084,8 @@ uvm_map_checkprot(struct vm_map *map, va
 {
        struct vm_map_entry *entry;
 
+       vm_map_assert_anylock(map);
+
        if (start < map->min_offset || end > map->max_offset || start > end)
                return FALSE;
        if (start == end)
@@ -4969,6 +4984,7 @@ uvm_map_freelist_update(struct vm_map *m
     vaddr_t b_start, vaddr_t b_end, vaddr_t s_start, vaddr_t s_end, int flags)
 {
        KDASSERT(b_end >= b_start && s_end >= s_start);
+       vm_map_assert_wrlock(map);
 
        /* Clear all free lists. */
        uvm_map_freelist_update_clear(map, dead);
@@ -5028,6 +5044,8 @@ uvm_map_fix_space(struct vm_map *map, st
        KDASSERT((entry != NULL && VMMAP_FREE_END(entry) == min) ||
            min == map->min_offset);
 
+       UVM_MAP_REQ_WRITE(map);
+
        /*
         * During the function, entfree will always point at the uaddr state
         * for entry.
@@ -5391,6 +5409,27 @@ vm_map_unbusy_ln(struct vm_map *map, cha
        mtx_leave(&map->flags_lock);
        if (oflags & VM_MAP_WANTLOCK)
                wakeup(&map->flags);
+}
+
+void
+vm_map_assert_anylock_ln(struct vm_map *map, char *file, int line)
+{
+       LPRINTF(("map assert read or write locked: %p (at %s %d)\n", map, file, 
line));
+       if ((map->flags & VM_MAP_INTRSAFE) == 0)
+               rw_assert_anylock(&map->lock);
+       else
+               MUTEX_ASSERT_LOCKED(&map->mtx);
+}
+
+void
+vm_map_assert_wrlock_ln(struct vm_map *map, char *file, int line)
+{
+       LPRINTF(("map assert write locked: %p (at %s %d)\n", map, file, line));
+       if ((map->flags & VM_MAP_INTRSAFE) == 0) {
+               splassert(IPL_NONE);
+               rw_assert_wrlock(&map->lock);
+       } else
+               MUTEX_ASSERT_LOCKED(&map->mtx);
 }
 
 #ifndef SMALL_KERNEL
Index: uvm/uvm_map.h
===================================================================
RCS file: /cvs/src/sys/uvm/uvm_map.h,v
retrieving revision 1.78
diff -u -p -r1.78 uvm_map.h
--- uvm/uvm_map.h       16 Oct 2022 16:16:37 -0000      1.78
+++ uvm/uvm_map.h       20 Oct 2022 14:09:31 -0000
@@ -420,6 +420,8 @@ void                vm_map_downgrade_ln(struct vm_map*
 void           vm_map_upgrade_ln(struct vm_map*, char*, int);
 void           vm_map_busy_ln(struct vm_map*, char*, int);
 void           vm_map_unbusy_ln(struct vm_map*, char*, int);
+void           vm_map_assert_anylock_ln(struct vm_map*, char*, int);
+void           vm_map_assert_wrlock_ln(struct vm_map*, char*, int);
 
 #ifdef DIAGNOSTIC
 #define vm_map_lock_try(map)   vm_map_lock_try_ln(map, __FILE__, __LINE__)
@@ -431,6 +433,10 @@ void               vm_map_unbusy_ln(struct vm_map*, c
 #define vm_map_upgrade(map)    vm_map_upgrade_ln(map, __FILE__, __LINE__)
 #define vm_map_busy(map)       vm_map_busy_ln(map, __FILE__, __LINE__)
 #define vm_map_unbusy(map)     vm_map_unbusy_ln(map, __FILE__, __LINE__)
+#define vm_map_assert_anylock(map)     \
+               vm_map_assert_anylock_ln(map, __FILE__, __LINE__)
+#define vm_map_assert_wrlock(map)      \
+               vm_map_assert_wrlock_ln(map, __FILE__, __LINE__)
 #else
 #define vm_map_lock_try(map)   vm_map_lock_try_ln(map, NULL, 0)
 #define vm_map_lock(map)       vm_map_lock_ln(map, NULL, 0)
@@ -441,6 +447,8 @@ void                vm_map_unbusy_ln(struct vm_map*, c
 #define vm_map_upgrade(map)    vm_map_upgrade_ln(map, NULL, 0)
 #define vm_map_busy(map)       vm_map_busy_ln(map, NULL, 0)
 #define vm_map_unbusy(map)     vm_map_unbusy_ln(map, NULL, 0)
+#define vm_map_assert_anylock(map)     vm_map_assert_anylock_ln(map, NULL, 0)
+#define vm_map_assert_wrlock(map)      vm_map_assert_wrlock_ln(map, NULL, 0)
 #endif
 
 void           uvm_map_lock_entry(struct vm_map_entry *);

Reply via email to