[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

vm_object shadow pages and task termination



Hello,

I began to investigate use of the stress-ng program to test the virtual memory system and in particular the behaviour under swap conditions. I didn't get to that goal just yet because I encountered an unrelated bug in the mach kernel exposed by stress-ng:

# stress-ng --vm 1 --vm-bytes 128K --vm-keep

This results in 1 stress-ng process, forking a child stress-ng which forks a 3rd stress-ng and begins what would normally be quite a long test run. After a few seconds I terminate all 3 processes and repeat the same stress-ng invocation. In most cases the kernel crashes immediately on the 2nd run but occasionally I might need to terminate and run a few more times. Various assertions originating in pmap.c occur.

I've spent a lot of time narrowing and debugging the fault, and I can provide more details if required, but to keep this message brief, here is a broad summary of what happens:

There  is a vm_map region of memory created by the parent process and inherited by the 2 child processes using VM_INHERIT_SHARE.

I added some validation code within pmap that I could call from the kernel debugger. After termination of the stress-ng processes this showed that there were some remaining references within the pv_head_table (i386/intel/pmap.c) to pmap_t objects that had already been destroyed. Eventually I found that the shared memory in stress-ng is managed by a vm_object having a 'shadow' vm_object and it was the pages within the shadow object that were not being unmapped before the vm_objects were terminated.

vm_object_pmap_remove() is the function called from within vm_map to clear pmap references for a shared map entry. This is the only place in mach where this function is called from. Currently it only removes pmap protection for all pages associated with the map_entry vm_object and disregards the shadow chain. I noticed that in the more general function vm_object_pmap_protect() there is code to recurse down the shadow chain and repeat the pmap deallocation performed on the main vm_object.

So in essence, I added the same shadow chain recursion functionality to vm_object_pmap_remove(). This works successfully within my test case. I am however not experienced enough with the mach code to claim this as a certain fix but offer it here for consideration. In particular I found it hard to get my head around the offset manipulations for the shadow chain. My patch includes that aspect but would need particular checking.

Regards,

Mike.

diff --git a/vm/vm_object.c b/vm/vm_object.c
index 3e6b28c4..efb169da 100644
--- a/vm/vm_object.c
+++ b/vm/vm_object.c
@@ -980,10 +980,11 @@ void vm_object_pmap_remove(
        vm_offset_t     start,
        vm_offset_t     end)
 {
-       vm_page_t       p;
+  vm_page_t    p;

-       if (object == VM_OBJECT_NULL)
-               return;
+  while (object != VM_OBJECT_NULL)
+    {
+        vm_object_t next_object;

        vm_object_lock(object);
        queue_iterate(&object->memq, p, vm_page_t, listq) {
@@ -992,7 +993,12 @@ void vm_object_pmap_remove(
                    (p->offset < end))
                        pmap_page_protect(p->phys_addr, VM_PROT_NONE);
        }
+       next_object = object->shadow;
+       start += object->shadow_offset;
+       end   += object->shadow_offset;
        vm_object_unlock(object);
+       object = next_object;
+    }
 }

 /*




Reply to: