diff options
author | green <green@FreeBSD.org> | 2004-06-24 22:43:46 +0000 |
---|---|---|
committer | green <green@FreeBSD.org> | 2004-06-24 22:43:46 +0000 |
commit | 4d32bd722dc911178dea899f447cafb400769806 (patch) | |
tree | bdf97fd80fce00db5dd8b96011e00a9f96731805 /sys/vm | |
parent | 7a9902cd18f46701f7f6aa84cb48f0f3c9b8950b (diff) | |
download | FreeBSD-src-4d32bd722dc911178dea899f447cafb400769806.zip FreeBSD-src-4d32bd722dc911178dea899f447cafb400769806.tar.gz |
Correct the tracking of various bits of the process's vmspace and vm_map
when not propogated on fork (due to minherit(2)). Consistency checks
otherwise fail when the vm_map is freed and it appears to have not been
emptied completely, causing an INVARIANTS panic in vm_map_zdtor().
PR: kern/68017
Submitted by: Mark W. Krentel <krentel@dreamscape.com>
Reviewed by: alc
Diffstat (limited to 'sys/vm')
-rw-r--r-- | sys/vm/vm_map.c | 47 |
1 files changed, 44 insertions, 3 deletions
diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c index d27df6f..df47991 100644 --- a/sys/vm/vm_map.c +++ b/sys/vm/vm_map.c @@ -2342,12 +2342,44 @@ vm_map_copy_entry( } /* + * vmspace_map_entry_forked: + * Update the newly-forked vmspace each time a map entry is inherited + * or copied. The values for vm_dsize and vm_tsize are approximate + * (and mostly-obsolete ideas in the face of mmap(2) et al.) + */ +static void +vmspace_map_entry_forked(const struct vmspace *vm1, struct vmspace *vm2, + vm_map_entry_t entry) +{ + vm_size_t entrysize; + vm_offset_t newend; + + entrysize = entry->end - entry->start; + vm2->vm_map.size += entrysize; + if (entry->eflags & (MAP_ENTRY_GROWS_DOWN | MAP_ENTRY_GROWS_UP)) { + vm2->vm_ssize += btoc(entrysize); + } else if (entry->start >= (vm_offset_t)vm1->vm_daddr && + entry->start < (vm_offset_t)vm1->vm_daddr + ctob(vm1->vm_dsize)) { + newend = min(entry->end, + (vm_offset_t)vm1->vm_daddr + ctob(vm1->vm_dsize)); + vm2->vm_dsize += btoc(newend - entry->start); + } else if (entry->start >= (vm_offset_t)vm1->vm_taddr && + entry->start < (vm_offset_t)vm1->vm_taddr + ctob(vm1->vm_tsize)) { + newend = min(entry->end, + (vm_offset_t)vm1->vm_taddr + ctob(vm1->vm_tsize)); + vm2->vm_tsize += btoc(newend - entry->start); + } +} + +/* * vmspace_fork: * Create a new process vmspace structure and vm_map * based on those of an existing process. The new map * is based on the old map, according to the inheritance * values on the regions in that map. * + * XXX It might be worth coalescing the entries added to the new vmspace. + * * The source map must not be locked. */ struct vmspace * @@ -2366,8 +2398,16 @@ vmspace_fork(struct vmspace *vm1) old_map->infork = 1; vm2 = vmspace_alloc(old_map->min_offset, old_map->max_offset); - bcopy(&vm1->vm_startcopy, &vm2->vm_startcopy, - (caddr_t) &vm1->vm_endcopy - (caddr_t) &vm1->vm_startcopy); + /* + * Using vm_{start,end}copy is invalid for more fields than + * it is valid here. For the most part, initialize size + * fields to zero and update them as map entries are copied + */ + bzero(&vm2->vm_startcopy, + (caddr_t)&vm2->vm_endcopy - (caddr_t)&vm2->vm_startcopy); + vm2->vm_taddr = vm1->vm_taddr; + vm2->vm_daddr = vm1->vm_daddr; + vm2->vm_maxsaddr = vm1->vm_maxsaddr; new_map = &vm2->vm_map; /* XXX */ new_map->timestamp = 1; @@ -2431,6 +2471,7 @@ vmspace_fork(struct vmspace *vm1) */ vm_map_entry_link(new_map, new_map->header.prev, new_entry); + vmspace_map_entry_forked(vm1, vm2, new_entry); /* * Update the physical map @@ -2452,6 +2493,7 @@ vmspace_fork(struct vmspace *vm1) new_entry->object.vm_object = NULL; vm_map_entry_link(new_map, new_map->header.prev, new_entry); + vmspace_map_entry_forked(vm1, vm2, new_entry); vm_map_copy_entry(old_map, new_map, old_entry, new_entry); break; @@ -2459,7 +2501,6 @@ vmspace_fork(struct vmspace *vm1) old_entry = old_entry->next; } - new_map->size = old_map->size; old_map->infork = 0; vm_map_unlock(old_map); |