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
This commit is contained in:
parent
12ec7658a4
commit
2a7be1b6d1
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=131073
@ -2341,6 +2341,36 @@ 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
|
||||
@ -2348,6 +2378,8 @@ vm_map_copy_entry(
|
||||
* 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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user