summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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);
}