Implement closer-to POSIX mlock semantics. The major difference is

that we do allow mlock to span unallocated regions (of course, not
mlocking them.)  We also allow mlocking of RO regions (which the old
code couldn't.)  The restriction there is that once a RO region is
wired (mlocked), it cannot be debugged (or EVER written to.)

Under normal usage, the new mlock code will be a significant improvement
over our old stuff.
This commit is contained in:
John Dyson 1996-12-14 17:54:17 +00:00
parent 97db6f8d69
commit 7aaaa4fd5d
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=20449
5 changed files with 217 additions and 9 deletions

View file

@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)vm_extern.h 8.2 (Berkeley) 1/12/94
* $Id: vm_extern.h,v 1.26 1996/09/14 11:54:54 bde Exp $
* $Id: vm_extern.h,v 1.27 1996/09/15 11:24:21 bde Exp $
*/
#ifndef _VM_EXTERN_H_
@ -80,6 +80,7 @@ int vm_fault __P((vm_map_t, vm_offset_t, vm_prot_t, boolean_t));
void vm_fault_copy_entry __P((vm_map_t, vm_map_t, vm_map_entry_t, vm_map_entry_t));
void vm_fault_unwire __P((vm_map_t, vm_offset_t, vm_offset_t));
int vm_fault_wire __P((vm_map_t, vm_offset_t, vm_offset_t));
int vm_fault_user_wire __P((vm_map_t, vm_offset_t, vm_offset_t));
int vm_fork __P((struct proc *, struct proc *));
int vm_mmap __P((vm_map_t, vm_offset_t *, vm_size_t, vm_prot_t, vm_prot_t, int, caddr_t, vm_ooffset_t));
vm_offset_t vm_page_alloc_contig __P((vm_offset_t, vm_offset_t, vm_offset_t, vm_offset_t));

View file

@ -66,7 +66,7 @@
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*
* $Id: vm_fault.c,v 1.57 1996/09/08 20:44:37 dyson Exp $
* $Id: vm_fault.c,v 1.58 1996/11/30 22:41:46 dyson Exp $
*/
/*
@ -202,6 +202,32 @@ RetryFault:;
vaddr);
}
/*
* If we are user-wiring a r/w segment, and it is COW, then
* we need to do the COW operation. Note that we don't COW
* currently RO sections now, because there it is NOT desireable
* to COW .text. We simply keep .text from ever being COW'ed
* and take the heat that one cannot debug wired .text sections.
*/
if ((change_wiring == VM_FAULT_USER_WIRE) && entry->needs_copy) {
if(entry->protection & VM_PROT_WRITE) {
int tresult;
vm_map_lookup_done(map, entry);
tresult = vm_map_lookup(&map, vaddr, VM_PROT_READ|VM_PROT_WRITE,
&entry, &first_object, &first_pindex, &prot, &wired, &su);
if (tresult != KERN_SUCCESS)
return tresult;
} else {
/*
* If we don't COW now, on a user wire, the user will never
* be able to write to the mapping. If we don't make this
* restriction, the bookkeeping would be nearly impossible.
*/
entry->max_protection &= ~VM_PROT_WRITE;
}
}
vp = vnode_pager_lock(first_object);
lookup_still_valid = TRUE;
@ -839,7 +865,48 @@ vm_fault_wire(map, start, end)
*/
for (va = start; va < end; va += PAGE_SIZE) {
rv = vm_fault(map, va, VM_PROT_READ|VM_PROT_WRITE, TRUE);
rv = vm_fault(map, va, VM_PROT_READ|VM_PROT_WRITE,
VM_FAULT_CHANGE_WIRING);
if (rv) {
if (va != start)
vm_fault_unwire(map, start, va);
return (rv);
}
}
return (KERN_SUCCESS);
}
/*
* vm_fault_user_wire:
*
* Wire down a range of virtual addresses in a map. This
* is for user mode though, so we only ask for read access
* on currently read only sections.
*/
int
vm_fault_user_wire(map, start, end)
vm_map_t map;
vm_offset_t start, end;
{
register vm_offset_t va;
register pmap_t pmap;
int rv;
pmap = vm_map_pmap(map);
/*
* Inform the physical mapping system that the range of addresses may
* not fault, so that page tables and such can be locked down as well.
*/
pmap_pageable(pmap, start, end, FALSE);
/*
* We simulate a fault to get the page and enter it in the physical
* map.
*/
for (va = start; va < end; va += PAGE_SIZE) {
rv = vm_fault(map, va, VM_PROT_READ, VM_FAULT_USER_WIRE);
if (rv) {
if (va != start)
vm_fault_unwire(map, start, va);

View file

@ -61,7 +61,7 @@
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*
* $Id: vm_map.c,v 1.60 1996/12/07 06:19:37 dyson Exp $
* $Id: vm_map.c,v 1.61 1996/12/07 07:44:05 dyson Exp $
*/
/*
@ -1351,6 +1351,137 @@ vm_map_inherit(map, start, end, new_inheritance)
return (KERN_SUCCESS);
}
/*
* Implement the semantics of mlock
*/
int
vm_map_user_pageable(map, start, end, new_pageable)
register vm_map_t map;
register vm_offset_t start;
register vm_offset_t end;
register boolean_t new_pageable;
{
register vm_map_entry_t entry;
vm_map_entry_t start_entry;
register vm_offset_t failed = 0;
int rv;
vm_map_lock(map);
VM_MAP_RANGE_CHECK(map, start, end);
if (vm_map_lookup_entry(map, start, &start_entry) == FALSE) {
vm_map_unlock(map);
return (KERN_INVALID_ADDRESS);
}
if (new_pageable) {
entry = start_entry;
vm_map_clip_start(map, entry, start);
/*
* Now decrement the wiring count for each region. If a region
* becomes completely unwired, unwire its physical pages and
* mappings.
*/
lock_set_recursive(&map->lock);
entry = start_entry;
while ((entry != &map->header) && (entry->start < end)) {
if (entry->user_wired) {
vm_map_clip_end(map, entry, end);
entry->user_wired = 0;
entry->wired_count--;
if (entry->wired_count == 0)
vm_fault_unwire(map, entry->start, entry->end);
}
entry = entry->next;
}
vm_map_simplify_entry(map, start_entry);
lock_clear_recursive(&map->lock);
} else {
/*
* Because of the possiblity of blocking, etc. We restart
* through the process's map entries from beginning so that
* we don't end up depending on a map entry that could have
* changed.
*/
rescan:
entry = start_entry;
while ((entry != &map->header) && (entry->start < end)) {
if (entry->user_wired != 0) {
entry = entry->next;
continue;
}
if (entry->wired_count != 0) {
entry->wired_count++;
entry->user_wired = 1;
entry = entry->next;
continue;
}
/* Here on entry being newly wired */
if (!entry->is_a_map && !entry->is_sub_map) {
int copyflag = entry->needs_copy;
if (copyflag && ((entry->protection & VM_PROT_WRITE) != 0)) {
vm_object_shadow(&entry->object.vm_object,
&entry->offset,
OFF_TO_IDX(entry->end
- entry->start));
entry->needs_copy = FALSE;
} else if (entry->object.vm_object == NULL) {
entry->object.vm_object =
vm_object_allocate(OBJT_DEFAULT,
OFF_TO_IDX(entry->end - entry->start));
entry->offset = (vm_offset_t) 0;
}
default_pager_convert_to_swapq(entry->object.vm_object);
}
vm_map_clip_start(map, entry, start);
vm_map_clip_end(map, entry, end);
entry->wired_count++;
entry->user_wired = 1;
/* First we need to allow map modifications */
lock_set_recursive(&map->lock);
lock_write_to_read(&map->lock);
rv = vm_fault_user_wire(map, entry->start, entry->end);
if (rv) {
entry->wired_count--;
entry->user_wired = 0;
lock_clear_recursive(&map->lock);
vm_map_unlock(map);
(void) vm_map_user_pageable(map, start, entry->start, TRUE);
return rv;
}
lock_clear_recursive(&map->lock);
vm_map_unlock(map);
vm_map_lock(map);
goto rescan;
}
}
vm_map_unlock(map);
return KERN_SUCCESS;
}
/*
* vm_map_pageable:
*

View file

@ -61,7 +61,7 @@
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*
* $Id: vm_map.h,v 1.16 1996/11/30 22:41:48 dyson Exp $
* $Id: vm_map.h,v 1.17 1996/12/07 00:03:43 dyson Exp $
*/
/*
@ -108,7 +108,8 @@ struct vm_map_entry {
is_sub_map:1, /* Is "object" a submap? */
copy_on_write:1, /* is data copy-on-write */
needs_copy:1, /* does object need to be copied */
nofault:1; /* should never fault */
nofault:1, /* should never fault */
user_wired:1; /* wired by user */
/* Only in task maps: */
vm_prot_t protection; /* protection code */
vm_prot_t max_protection; /* maximum protection */
@ -210,6 +211,13 @@ typedef struct {
#define MAP_COPY_ON_WRITE 0x2
#define MAP_NOFAULT 0x4
/*
* vm_fault option flags
*/
#define VM_FAULT_NORMAL 0
#define VM_FAULT_CHANGE_WIRING 1
#define VM_FAULT_USER_WIRE 2
#ifdef KERNEL
extern vm_offset_t kentry_data;
extern vm_size_t kentry_data_size;
@ -230,6 +238,7 @@ int vm_map_lookup __P((vm_map_t *, vm_offset_t, vm_prot_t, vm_map_entry_t *, vm_
void vm_map_lookup_done __P((vm_map_t, vm_map_entry_t));
boolean_t vm_map_lookup_entry __P((vm_map_t, vm_offset_t, vm_map_entry_t *));
int vm_map_pageable __P((vm_map_t, vm_offset_t, vm_offset_t, boolean_t));
int vm_map_user_pageable __P((vm_map_t, vm_offset_t, vm_offset_t, boolean_t));
int vm_map_clean __P((vm_map_t, vm_offset_t, vm_offset_t, boolean_t, boolean_t));
int vm_map_protect __P((vm_map_t, vm_offset_t, vm_offset_t, vm_prot_t, boolean_t));
void vm_map_reference __P((vm_map_t));

View file

@ -38,7 +38,7 @@
* from: Utah $Hdr: vm_mmap.c 1.6 91/10/21$
*
* @(#)vm_mmap.c 8.4 (Berkeley) 1/12/94
* $Id: vm_mmap.c,v 1.52 1996/10/24 02:56:23 dyson Exp $
* $Id: vm_mmap.c,v 1.53 1996/10/29 22:07:11 dyson Exp $
*/
/*
@ -785,7 +785,7 @@ mlock(p, uap, retval)
return (error);
#endif
error = vm_map_pageable(&p->p_vmspace->vm_map, addr, addr + size, FALSE);
error = vm_map_user_pageable(&p->p_vmspace->vm_map, addr, addr + size, FALSE);
return (error == KERN_SUCCESS ? 0 : ENOMEM);
}
@ -823,7 +823,7 @@ munlock(p, uap, retval)
return (error);
#endif
error = vm_map_pageable(&p->p_vmspace->vm_map, addr, addr + size, TRUE);
error = vm_map_user_pageable(&p->p_vmspace->vm_map, addr, addr + size, TRUE);
return (error == KERN_SUCCESS ? 0 : ENOMEM);
}