aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorJohn Dyson <dyson@FreeBSD.org>1996-12-14 17:54:17 +0000
committerJohn Dyson <dyson@FreeBSD.org>1996-12-14 17:54:17 +0000
commit7aaaa4fd5d96bb6673a24c41e28152cbbd46457f (patch)
treeb1d0372c1df868572557b6875727b2db2a4648f4 /sys
parent97db6f8d695fb585f56e2d2e754e5769dbc6b0e9 (diff)
downloadsrc-7aaaa4fd5d96bb6673a24c41e28152cbbd46457f.tar.gz
src-7aaaa4fd5d96bb6673a24c41e28152cbbd46457f.zip
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.
Notes
Notes: svn path=/head/; revision=20449
Diffstat (limited to 'sys')
-rw-r--r--sys/vm/vm_extern.h3
-rw-r--r--sys/vm/vm_fault.c71
-rw-r--r--sys/vm/vm_map.c133
-rw-r--r--sys/vm/vm_map.h13
-rw-r--r--sys/vm/vm_mmap.c6
5 files changed, 217 insertions, 9 deletions
diff --git a/sys/vm/vm_extern.h b/sys/vm/vm_extern.h
index 5a706917de74..3d5a33527852 100644
--- a/sys/vm/vm_extern.h
+++ b/sys/vm/vm_extern.h
@@ -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));
diff --git a/sys/vm/vm_fault.c b/sys/vm/vm_fault.c
index f395d9701d7c..ff6482477dcb 100644
--- a/sys/vm/vm_fault.c
+++ b/sys/vm/vm_fault.c
@@ -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);
diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c
index 52553cbad0df..fb1bb508b7b2 100644
--- a/sys/vm/vm_map.c
+++ b/sys/vm/vm_map.c
@@ -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 $
*/
/*
@@ -1352,6 +1352,137 @@ vm_map_inherit(map, start, end, new_inheritance)
}
/*
+ * 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:
*
* Sets the pageability of the specified address
diff --git a/sys/vm/vm_map.h b/sys/vm/vm_map.h
index af36fb4a5d7b..c1450f1914cc 100644
--- a/sys/vm/vm_map.h
+++ b/sys/vm/vm_map.h
@@ -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));
diff --git a/sys/vm/vm_mmap.c b/sys/vm/vm_mmap.c
index 6bfece3d51a9..3fe3b019879b 100644
--- a/sys/vm/vm_mmap.c
+++ b/sys/vm/vm_mmap.c
@@ -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);
}