Suppose an object O has two shadow objects S1, S2 mapped into processes
P1, P2. Suppose a page resident in O is mapped read-only into P1. Now
suppose that P1 writes to the page, triggering a COW fault: it allocates
a new page in S1 and copies the page, then marks it valid. If the page
in O was busy, it would have to release the map lock and sleep first.
Then, after copying the page, P1 must re-check the map lookup because
locks were dropped. Suppose the map indeed changed, so P1 has to retry
the fault.
At this point, the mapped page in O is shadowed by a valid page in S1.
If P2 exits, S2 will be deallocated, resulting in a collapse of O into
S1. In this case, P2 will free the mapped page, which is illegal; this
triggers a "freeing mapped page" assertion in invariants kernels.
Fix the problem by deferring the vm_page_valid() call which marks the
COW copy valid: only mark it once we know that the fault handler will
succeed. It's okay to leave an invalid page in the top-level object; it
will be freed when the fault is retried, and vm_object_collapse_scan()
will similarly free invalid pages in the shadow object.
Sponsored by: Innovate UK