diff options
| author | John Dyson <dyson@FreeBSD.org> | 1996-12-14 17:54:17 +0000 |
|---|---|---|
| committer | John Dyson <dyson@FreeBSD.org> | 1996-12-14 17:54:17 +0000 |
| commit | 7aaaa4fd5d96bb6673a24c41e28152cbbd46457f (patch) | |
| tree | b1d0372c1df868572557b6875727b2db2a4648f4 | |
| parent | 97db6f8d695fb585f56e2d2e754e5769dbc6b0e9 (diff) | |
Notes
| -rw-r--r-- | sys/vm/vm_extern.h | 3 | ||||
| -rw-r--r-- | sys/vm/vm_fault.c | 71 | ||||
| -rw-r--r-- | sys/vm/vm_map.c | 133 | ||||
| -rw-r--r-- | sys/vm/vm_map.h | 13 | ||||
| -rw-r--r-- | sys/vm/vm_mmap.c | 6 |
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); } |
