kern_return_t vm_fault_copy_tmp( src_object, src_offset, src_size, dst_object, dst_offset, dst_map, dst_version, interruptible ) vm_object_t src_object; vm_offset_t src_offset; vm_size_t *src_size; /* INOUT */ vm_object_t dst_object; vm_offset_t dst_offset; vm_map_t dst_map; vm_map_version_t *dst_version; boolean_t interruptible; { vm_page_t result_page; vm_prot_t prot; vm_page_t src_page; vm_page_t src_top_page; vm_offset_t src_pa_offset, src_page_offset; vm_page_t dst_page; vm_page_t dst_top_page; vm_offset_t dst_pa_offset, dst_page_offset; vm_size_t amount_done, cpy_size; vm_object_t old_copy_object; boolean_t same_page = FALSE; #define RETURN(x) \ MACRO_BEGIN \ *src_size = amount_done; \ MACRO_RETURN(x); \ MACRO_END amount_done = src_pa_offset = dst_pa_offset = 0; do { /* while (amount_done != *src_size) */ RetrySourceFault: ; cpy_size = (*src_size - amount_done); if (cpy_size > PAGE_SIZE) cpy_size = PAGE_SIZE; src_pa_offset = trunc_page(src_offset); src_page_offset = (src_offset - src_pa_offset); if (src_object == VM_OBJECT_NULL) { /* * No source object. We will just * zero-fill the page in dst_object. */ src_page = VM_PAGE_NULL; } else if ( !same_page ) { prot = VM_PROT_READ; vm_object_lock(src_object); vm_object_paging_begin(src_object); switch (vm_fault_page(src_object, src_pa_offset, VM_PROT_READ, FALSE, interruptible, &prot, &result_page, &src_top_page, FALSE, (void (*)()) 0)) { case VM_FAULT_SUCCESS: break; case VM_FAULT_RETRY: goto RetrySourceFault; case VM_FAULT_INTERRUPTED: RETURN(MACH_SEND_INTERRUPTED); case VM_FAULT_MEMORY_SHORTAGE: VM_PAGE_WAIT((void (*)()) 0); goto RetrySourceFault; case VM_FAULT_FICTITIOUS_SHORTAGE: vm_page_more_fictitious(); goto RetrySourceFault; case VM_FAULT_MEMORY_ERROR: return(KERN_MEMORY_ERROR); } src_page = result_page; assert((src_top_page == VM_PAGE_NULL) == (src_page->object == src_object)); assert ((prot & VM_PROT_READ) != VM_PROT_NONE); vm_object_unlock(src_page->object); } RetryDestinationFault: ; prot = VM_PROT_WRITE; vm_object_lock(dst_object); /* XXX Is this needed? vm_object_paging_begin(dst_object); */ dst_pa_offset = trunc_page(dst_offset); dst_page_offset = (dst_offset - dst_pa_offset); if ((dst_page = vm_page_lookup(dst_object, dst_pa_offset)) == VM_PAGE_NULL) panic("fault_copy_tmp, page null!\n"); vm_object_unlock(dst_object); /* * Copy the page, and note that it is dirty * immediately. */ if ((PAGE_SIZE - dst_page_offset) < cpy_size) cpy_size = (PAGE_SIZE - dst_page_offset); if ((PAGE_SIZE - src_page_offset) < cpy_size) cpy_size = (PAGE_SIZE - src_page_offset); /* XXX DEBUG printf("vm_fault_copy: SOURCE src_offset: %d, src_page_offset: %d\n", src_offset, src_page_offset); printf("vm_fault_copy: TARGET dst_offset: %d, dst_page_offset: %d\n", dst_offset, dst_page_offset); printf("vm_fault_copy: COPY amount_done: %d, src_size: %d, cpy_size: %d\n", amount_done, *src_size, cpy_size); */ if (src_page == VM_PAGE_NULL) vm_page_zero_fill_tmp(dst_page, dst_page_offset, cpy_size); else vm_page_copy_tmp(src_page, src_page_offset, dst_page, dst_page_offset, cpy_size); dst_page->dirty = TRUE; /* * Unlock everything, and return */ amount_done += cpy_size; src_offset += cpy_size; dst_offset += cpy_size; if (src_page != VM_PAGE_NULL && (amount_done == *src_size) || (src_pa_offset != trunc_page(src_offset))) { vm_fault_copy_cleanup(src_page, src_top_page); same_page = FALSE; } else same_page = TRUE; } while (amount_done != *src_size); RETURN(KERN_SUCCESS); #undef RETURN /*NOTREACHED*/ }