RPI-B VM panic

Alan Cox alc at rice.edu
Fri Jun 13 16:50:53 UTC 2014


On 06/12/2014 15:56, Hans Petter Selasky wrote:
> On 06/12/14 21:11, Alan Cox wrote:
>> On 06/12/2014 12:53, Hans Petter Selasky wrote:
>>> On 06/12/14 19:41, Hans Petter Selasky wrote:
>>>> On 06/12/14 19:32, Ian Lepore wrote:
>>>>> On Thu, 2014-06-12 at 19:28 +0200, Hans Petter Selasky wrote:
>>>>>> On 06/12/14 19:12, Alan Cox wrote:
>>>>>>> On 06/12/2014 01:03, Hans Petter Selasky wrote:
>>>>>>>> On 06/11/14 22:47, Alan Cox wrote:
>>>>>>>>>
>>>>>>>>> On Jun 11, 2014, at 3:45 PM, Hans Petter Selasky wrote:
>>>>>>>>>
>>>>>>>>>> On 06/11/14 22:20, Alan Cox wrote:
>>>>>>>>>>>
>>>>>>>>>>> On Jun 11, 2014, at 3:07 PM, Hans Petter Selasky wrote:
>>>>>>>>>>>
>>>>>>>>>>>> kernel:     file format elf32-littlearm
>>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> Then this problem is unrelated to the one that I just fixed.
>>>>>>>>>>> It's
>>>>>>>>>>> also not a problem that I've seen before.
>>>>>>>>>>
>>>>>>>>>> It is happening after your recent patches to -current,
>>>>>>>>>> optimising
>>>>>>>>>> the "page ordering". Happens every now and then during boot when
>>>>>>>>>> stack is growing looks like.
>>>>>>>>>
>>>>>>>>> More precisely, which commit is that?
>>>>>>>>>
>>>>>>>>
>>>>>>>>> commit 7d20e37fb658b0e2cd7f3c13dac8022e0e866a21
>>>>>>>>> Author: alc <alc at FreeBSD.org>
>>>>>>>>> Date:   Sun May 12 16:50:18 2013 +0000
>>>>>>>>>
>>>>>>>>>        Refactor vm_page_alloc()'s interactions with
>>>>>>>>> vm_reserv_alloc_page() and
>>>>>>>>>        vm_page_insert() so that (1) vm_radix_lookup_le() is never
>>>>>>>>> called
>>>>>>>>> while the
>>>>>>>>>        free page queues lock is held and (2)
>>>>>>>>> vm_radix_lookup_le() is
>>>>>>>>> called at most
>>>>>>>>>        once.  This change reduces the average time that the free
>>>>>>>>> page
>>>>>>>>> queues lock
>>>>>>>>>        is held by vm_page_alloc() as well as vm_page_alloc()'s
>>>>>>>>> average
>>>>>>>>> overall
>>>>>>>>>        running time.
>>>>>>>>>
>>>>>>>>>        Sponsored by:       EMC / Isilon Storage Division
>>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>> That's not exactly a recent commit.  It was 13 months ago.  And,
>>>>>>> this
>>>>>>> code is exercised by all page allocations except for page table
>>>>>>> pages
>>>>>>> and uma_small_alloc().
>>>>>>>
>>>>>>> What this assertion is telling us is that somewhere else we have
>>>>>>> screwed
>>>>>>> up the vm object to which we are now trying to allocate a page.
>>>>>>>
>>>>>>> Try the attached patch.  It will provide additional information the
>>>>>>> next
>>>>>>> time that the assertion fails.
>>>>>>>
>>>>>>
>>>>>> Here you go:
>>>>>>
>>>>>>> panic: vm_page_insert_after: msucc 0xc0993e50 (0) doesn't succeed
>>>>>>> pindex 4
>>>>>>> object 0xc1a2b140 type 0
>>>>>>> KDB: enter: panic
>>>>>>> [ thread pid 18 tid 100052 ]
>>>>>>> Stopped at      $d:     ldrb    r15, [r15, r15, ror r15]!
>>>>>>> db>
>>>>>
>>>>> Could this be related to changing superpages to enabled by default
>>>>> recently?  Easy to test by setting vm.pmap.sp_enabled=0 in ubldr
>>>>>
>>>>
>>>> Setting the sp_enabled to 0 does not fix the problem.
>>>>
>>>> --HPS
>>>
>>> Output from the debugger regarding the object:
>>>
>>>> panic: vm_page_insert_after: msucc 0xc0993e50 (0) doesn't succeed
>>>> pindex 4
>>>> object 0xc1a2b1e0 type 0
>>>> KDB: enter: panic
>>>
>>>> db> show vmochk
>>>> vmochk: internal obj is not in a map: ref: 1, size: 2: 0x2,
>>>> backing_object: 0
>>>> vmochk: internal obj is not in a map: ref: 1, size: 2: 0x2,
>>>> backing_object: 0
>>>
>>
>> Use the ddb command "object", not "vmochk".
>>
>>> ....
>>>
>>>> db> show vmopag
>>>
>>> ....
>>>
>>>> new object: 0xc1a2b1e0
>>>>   index(0)run(1)pa(0x1766000)
>>>>   index(1)run(1)pa(0x1e17000)
>>>>   index(2)run(2)pa(0x1772000)
>>>>   index(4)run(1)pa(0x1e6a000)
>>>>   index(5)run(2)pa(0x1775000)
>>>>   index(7)run(1)pa(0x1778000)
>>>>   index(8)run(1)pa(0x1788000)
>>>>   index(9)run(1)pa(0x17e9000)
>>>
>>> --HPS
>>>
>>>
>>>
>>
>>
>
> show object 0xc1a2b1e0
> Object 0xc1a2b1e0: type=0, size=0xa, res=10, ref=2, flags=0x3000 ruid
> 0 charge a000
>  sref=0, backing_object(0)=(0)+0x0
>
> memory:=(off=0x0,page=0x1766000),(off=0x1,page=0x1e17000),(off=0x2,page=0x1772000),(off=0x3,page=0x1773000),(off=0x4,page=0x1e6a000),(off=0x5,page=0x177500)
>
>
> ...(off=0x6,page=0x1776000),(off=0x7,page=0x1778000),(off=0x8,page=0x1788000),(off=0x9,page=0x17e9000)
>
>
>


This output shows that according to the object's list of pages there is
already a page allocated at pindex 4 (or "off=0x4" above).  If this list
is correct, and not itself corrupted, then we shouldn't be making a call
to vm_page_alloc() to allocate another page at the same pindex.

Whether it is this list of pages that is corrupted or not, this means
that the object's list of pages (shown above) and its radix tree of
pages are out of sync.

I'm curious to know what mpred is when the assertion fails.  That will
tell us something about the state of the radix tree.

I've also modified ddb's "show object" to provide an additional bit of
information.  However, it would be really nice if "show object"
displayed the state of the radix tree.


In any case,
At this point,
-------------- next part --------------
Index: vm/vm_reserv.c
===================================================================
--- vm/vm_reserv.c	(revision 267282)
+++ vm/vm_reserv.c	(working copy)
@@ -108,6 +108,46 @@ typedef	u_long		popmap_t;
 #define	NPOPMAP		howmany(VM_LEVEL_0_NPAGES, NBPOPMAP)
 
 /*
+ * Clear a bit in the population map.
+ */
+static __inline void
+popmap_clear(popmap_t popmap[], int i)
+{
+
+	popmap[i / NBPOPMAP] &= ~(1UL << (i % NBPOPMAP));
+}
+
+/*
+ * Set a bit in the population map.
+ */
+static __inline void
+popmap_set(popmap_t popmap[], int i)
+{
+
+	popmap[i / NBPOPMAP] |= 1UL << (i % NBPOPMAP);
+}
+
+/*
+ * Is a bit in the population map clear?
+ */
+static __inline boolean_t
+popmap_is_clear(popmap_t popmap[], int i)
+{
+
+	return ((popmap[i / NBPOPMAP] & (1UL << (i % NBPOPMAP))) == 0);
+}
+
+/*
+ * Is a bit in the population map set?
+ */
+static __inline boolean_t
+popmap_is_set(popmap_t popmap[], int i)
+{
+
+	return ((popmap[i / NBPOPMAP] & (1UL << (i % NBPOPMAP))) != 0);
+}
+
+/*
  * The reservation structure
  *
  * A reservation structure is constructed whenever a large physical page is
@@ -241,7 +281,7 @@ vm_reserv_depopulate(vm_reserv_t rv, int index)
 	mtx_assert(&vm_page_queue_free_mtx, MA_OWNED);
 	KASSERT(rv->object != NULL,
 	    ("vm_reserv_depopulate: reserv %p is free", rv));
-	KASSERT(isset(rv->popmap, index),
+	KASSERT(popmap_is_set(rv->popmap, index),
 	    ("vm_reserv_depopulate: reserv %p's popmap[%d] is clear", rv,
 	    index));
 	KASSERT(rv->popcnt > 0,
@@ -255,7 +295,7 @@ vm_reserv_depopulate(vm_reserv_t rv, int index)
 		    rv));
 		rv->pages->psind = 0;
 	}
-	clrbit(rv->popmap, index);
+	popmap_clear(rv->popmap, index);
 	rv->popcnt--;
 	if (rv->popcnt == 0) {
 		LIST_REMOVE(rv, objq);
@@ -302,7 +342,7 @@ vm_reserv_populate(vm_reserv_t rv, int index)
 	mtx_assert(&vm_page_queue_free_mtx, MA_OWNED);
 	KASSERT(rv->object != NULL,
 	    ("vm_reserv_populate: reserv %p is free", rv));
-	KASSERT(isclr(rv->popmap, index),
+	KASSERT(popmap_is_clear(rv->popmap, index),
 	    ("vm_reserv_populate: reserv %p's popmap[%d] is set", rv,
 	    index));
 	KASSERT(rv->popcnt < VM_LEVEL_0_NPAGES,
@@ -313,7 +353,7 @@ vm_reserv_populate(vm_reserv_t rv, int index)
 		TAILQ_REMOVE(&vm_rvq_partpop, rv, partpopq);
 		rv->inpartpopq = FALSE;
 	}
-	setbit(rv->popmap, index);
+	popmap_set(rv->popmap, index);
 	rv->popcnt++;
 	if (rv->popcnt < VM_LEVEL_0_NPAGES) {
 		rv->inpartpopq = TRUE;
@@ -503,7 +543,7 @@ found:
 		return (NULL);
 	/* Handle vm_page_rename(m, new_object, ...). */
 	for (i = 0; i < npages; i++)
-		if (isset(rv->popmap, index + i))
+		if (popmap_is_set(rv->popmap, index + i))
 			return (NULL);
 	for (i = 0; i < npages; i++)
 		vm_reserv_populate(rv, index + i);
@@ -628,7 +668,7 @@ found:
 	index = VM_RESERV_INDEX(object, pindex);
 	m = &rv->pages[index];
 	/* Handle vm_page_rename(m, new_object, ...). */
-	if (isset(rv->popmap, index))
+	if (popmap_is_set(rv->popmap, index))
 		return (NULL);
 	vm_reserv_populate(rv, index);
 	return (m);
@@ -662,9 +702,9 @@ vm_reserv_break(vm_reserv_t rv, vm_page_t m)
 		 * to the physical memory allocator.
 		 */
 		i = m - rv->pages;
-		KASSERT(isclr(rv->popmap, i),
+		KASSERT(popmap_is_clear(rv->popmap, i),
 		    ("vm_reserv_break: reserv %p's popmap is corrupted", rv));
-		setbit(rv->popmap, i);
+		popmap_set(rv->popmap, i);
 		rv->popcnt++;
 	}
 	i = hi = 0;


More information about the freebsd-arm mailing list