-/*
- * Routine: vm_pageout_setup
- * Purpose:
- * Set up a page for pageout (clean & flush).
- *
- * Move the page to a new object, as part of which it will be
- * sent to its memory manager in a memory_object_data_write or
- * memory_object_initialize message.
- *
- * The "new_object" and "new_offset" arguments
- * indicate where the page should be moved.
- *
- * In/Out conditions:
- * The page in question must not be on any pageout queues,
- * and must be busy. The object to which it belongs
- * must be unlocked, and the caller must hold a paging
- * reference to it. The new_object must not be locked.
- *
- * This routine returns a pointer to a place-holder page,
- * inserted at the same offset, to block out-of-order
- * requests for the page. The place-holder page must
- * be freed after the data_write or initialize message
- * has been sent.
- *
- * The original page is put on a paging queue and marked
- * not busy on exit.
- */
-vm_page_t
-vm_pageout_setup(
- register vm_page_t m,
- register vm_object_t new_object,
- vm_object_offset_t new_offset)
-{
- register vm_object_t old_object = m->object;
- vm_object_offset_t paging_offset;
- vm_object_offset_t offset;
- register vm_page_t holding_page;
- register vm_page_t new_m;
- boolean_t need_to_wire = FALSE;
-
-
- XPR(XPR_VM_PAGEOUT,
- "vm_pageout_setup, obj 0x%X off 0x%X page 0x%X new obj 0x%X offset 0x%X\n",
- (integer_t)m->object, (integer_t)m->offset,
- (integer_t)m, (integer_t)new_object,
- (integer_t)new_offset);
- assert(m && m->busy && !m->absent && !m->fictitious && !m->error &&
- !m->restart);
-
- assert(m->dirty || m->precious);
-
- /*
- * Create a place-holder page where the old one was, to prevent
- * attempted pageins of this page while we're unlocked.
- */
- VM_PAGE_GRAB_FICTITIOUS(holding_page);
-
- vm_object_lock(old_object);
-
- offset = m->offset;
- paging_offset = offset + old_object->paging_offset;
-
- if (old_object->pager_trusted) {
- /*
- * This pager is trusted, so we can clean this page
- * in place. Leave it in the old object, and mark it
- * cleaning & pageout.
- */
- new_m = holding_page;
- holding_page = VM_PAGE_NULL;
-
- /*
- * Set up new page to be private shadow of real page.
- */
- new_m->phys_page = m->phys_page;
- new_m->fictitious = FALSE;
- new_m->pageout = TRUE;
-
- /*
- * Mark real page as cleaning (indicating that we hold a
- * paging reference to be released via m_o_d_r_c) and
- * pageout (indicating that the page should be freed
- * when the pageout completes).
- */
- pmap_clear_modify(m->phys_page);
- vm_page_lock_queues();
- new_m->private = TRUE;
- vm_page_wire(new_m);
- m->cleaning = TRUE;
- m->pageout = TRUE;
-
- vm_page_wire(m);
- assert(m->wire_count == 1);
- vm_page_unlock_queues();
-
- m->dirty = TRUE;
- m->precious = FALSE;
- m->page_lock = VM_PROT_NONE;
- m->unusual = FALSE;
- m->unlock_request = VM_PROT_NONE;
- } else {
- /*
- * Cannot clean in place, so rip the old page out of the
- * object, and stick the holding page in. Set new_m to the
- * page in the new object.
- */
- vm_page_lock_queues();
- VM_PAGE_QUEUES_REMOVE(m);
- vm_page_remove(m);
-
- vm_page_insert(holding_page, old_object, offset);
- vm_page_unlock_queues();
-
- m->dirty = TRUE;
- m->precious = FALSE;
- new_m = m;
- new_m->page_lock = VM_PROT_NONE;
- new_m->unlock_request = VM_PROT_NONE;
-
- if (old_object->internal)
- need_to_wire = TRUE;
- }
- /*
- * Record that this page has been written out
- */
-#if MACH_PAGEMAP
- vm_external_state_set(old_object->existence_map, offset);
-#endif /* MACH_PAGEMAP */
-
- vm_object_unlock(old_object);
-
- vm_object_lock(new_object);
-
- /*
- * Put the page into the new object. If it is a not wired
- * (if it's the real page) it will be activated.
- */
-
- vm_page_lock_queues();
- vm_page_insert(new_m, new_object, new_offset);
- if (need_to_wire)
- vm_page_wire(new_m);
- else
- vm_page_activate(new_m);
- PAGE_WAKEUP_DONE(new_m);
- vm_page_unlock_queues();
-
- vm_object_unlock(new_object);
-
- /*
- * Return the placeholder page to simplify cleanup.
- */
- return (holding_page);
-}
-