vm5 diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c index 35552a6..26604d5 100644 --- a/sys/vm/vm_map.c +++ b/sys/vm/vm_map.c @@ -2972,6 +2972,26 @@ vmspace_map_entry_forked(const struct vmspace *vm1, struct vmspace *vm2, } } +static boolean_t +vm_map_unmark_till_entry(vm_map_t map, vm_map_entry_t stop_entry) +{ + vm_map_entry_t entry; + boolean_t need_wakeup; + + need_wakeup = FALSE; + for (entry = map->header.next; entry != stop_entry; + entry = entry->next) { + KASSERT((entry->eflags & MAP_ENTRY_IN_TRANSITION) != 0, + ("Lost IN_TRANSITION")); + entry->eflags &= ~MAP_ENTRY_IN_TRANSITION; + if (entry->eflags & MAP_ENTRY_NEEDS_WAKEUP) { + entry->eflags &= ~MAP_ENTRY_NEEDS_WAKEUP; + need_wakeup = TRUE; + } + } + return (need_wakeup); +} + /* * vmspace_fork: * Create a new process vmspace structure and vm_map @@ -2989,15 +3009,31 @@ vmspace_fork(struct vmspace *vm1, vm_ooffset_t *fork_charge) struct vmspace *vm2; vm_map_t old_map = &vm1->vm_map; vm_map_t new_map; - vm_map_entry_t old_entry; - vm_map_entry_t new_entry; + vm_map_entry_t entry, new_entry, old_entry; vm_object_t object; int locked; + boolean_t need_wakeup; - vm_map_lock(old_map); + need_wakeup = FALSE; vm2 = vmspace_alloc(old_map->min_offset, old_map->max_offset); if (vm2 == NULL) goto unlock_and_return; + +mark_in_transition: + vm_map_lock(old_map); + for (entry = old_map->header.next; entry != &old_map->header; + entry = entry->next) { + if (entry->eflags & MAP_ENTRY_IN_TRANSITION) { + need_wakeup = vm_map_unmark_till_entry(old_map, entry); + entry->eflags |= MAP_ENTRY_NEEDS_WAKEUP; + if (need_wakeup) + vm_map_wakeup(old_map); + vm_map_unlock_and_wait(old_map, 0); + goto mark_in_transition; + } + entry->eflags |= MAP_ENTRY_IN_TRANSITION; + } + vm2->vm_taddr = vm1->vm_taddr; vm2->vm_daddr = vm1->vm_daddr; vm2->vm_maxsaddr = vm1->vm_maxsaddr; @@ -3112,10 +3148,13 @@ vmspace_fork(struct vmspace *vm1, vm_ooffset_t *fork_charge) } old_entry = old_entry->next; } + need_wakeup = vm_map_unmark_till_entry(old_map, &old_map->header); unlock_and_return: vm_map_unlock(old_map); if (vm2 != NULL) vm_map_unlock(new_map); + if (need_wakeup) + vm_map_wakeup(old_map); return (vm2); }