xref: /freebsd/sys/vm/vm_map.c (revision 1d284e00b5614c6e5e17ea40f9be0fd612398055)
1df8bae1dSRodney W. Grimes /*
2df8bae1dSRodney W. Grimes  * Copyright (c) 1991, 1993
3df8bae1dSRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
4df8bae1dSRodney W. Grimes  *
5df8bae1dSRodney W. Grimes  * This code is derived from software contributed to Berkeley by
6df8bae1dSRodney W. Grimes  * The Mach Operating System project at Carnegie-Mellon University.
7df8bae1dSRodney W. Grimes  *
8df8bae1dSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
9df8bae1dSRodney W. Grimes  * modification, are permitted provided that the following conditions
10df8bae1dSRodney W. Grimes  * are met:
11df8bae1dSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
12df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
13df8bae1dSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
14df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
15df8bae1dSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
16df8bae1dSRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
175929bcfaSPhilippe Charnier  *    must display the following acknowledgement:
18df8bae1dSRodney W. Grimes  *	This product includes software developed by the University of
19df8bae1dSRodney W. Grimes  *	California, Berkeley and its contributors.
20df8bae1dSRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
21df8bae1dSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
22df8bae1dSRodney W. Grimes  *    without specific prior written permission.
23df8bae1dSRodney W. Grimes  *
24df8bae1dSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27df8bae1dSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
35df8bae1dSRodney W. Grimes  *
363c4dd356SDavid Greenman  *	from: @(#)vm_map.c	8.3 (Berkeley) 1/12/94
37df8bae1dSRodney W. Grimes  *
38df8bae1dSRodney W. Grimes  *
39df8bae1dSRodney W. Grimes  * Copyright (c) 1987, 1990 Carnegie-Mellon University.
40df8bae1dSRodney W. Grimes  * All rights reserved.
41df8bae1dSRodney W. Grimes  *
42df8bae1dSRodney W. Grimes  * Authors: Avadis Tevanian, Jr., Michael Wayne Young
43df8bae1dSRodney W. Grimes  *
44df8bae1dSRodney W. Grimes  * Permission to use, copy, modify and distribute this software and
45df8bae1dSRodney W. Grimes  * its documentation is hereby granted, provided that both the copyright
46df8bae1dSRodney W. Grimes  * notice and this permission notice appear in all copies of the
47df8bae1dSRodney W. Grimes  * software, derivative works or modified versions, and any portions
48df8bae1dSRodney W. Grimes  * thereof, and that both notices appear in supporting documentation.
49df8bae1dSRodney W. Grimes  *
50df8bae1dSRodney W. Grimes  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
51df8bae1dSRodney W. Grimes  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
52df8bae1dSRodney W. Grimes  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
53df8bae1dSRodney W. Grimes  *
54df8bae1dSRodney W. Grimes  * Carnegie Mellon requests users of this software to return to
55df8bae1dSRodney W. Grimes  *
56df8bae1dSRodney W. Grimes  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
57df8bae1dSRodney W. Grimes  *  School of Computer Science
58df8bae1dSRodney W. Grimes  *  Carnegie Mellon University
59df8bae1dSRodney W. Grimes  *  Pittsburgh PA 15213-3890
60df8bae1dSRodney W. Grimes  *
61df8bae1dSRodney W. Grimes  * any improvements or extensions that they make and grant Carnegie the
62df8bae1dSRodney W. Grimes  * rights to redistribute these changes.
633c4dd356SDavid Greenman  *
64c3aac50fSPeter Wemm  * $FreeBSD$
65df8bae1dSRodney W. Grimes  */
66df8bae1dSRodney W. Grimes 
67df8bae1dSRodney W. Grimes /*
68df8bae1dSRodney W. Grimes  *	Virtual memory mapping module.
69df8bae1dSRodney W. Grimes  */
70df8bae1dSRodney W. Grimes 
71df8bae1dSRodney W. Grimes #include <sys/param.h>
72df8bae1dSRodney W. Grimes #include <sys/systm.h>
7361d80e90SJohn Baldwin #include <sys/ktr.h>
74fb919e4dSMark Murray #include <sys/lock.h>
75fb919e4dSMark Murray #include <sys/mutex.h>
76b5e8ce9fSBruce Evans #include <sys/proc.h>
77efeaf95aSDavid Greenman #include <sys/vmmeter.h>
78867a482dSJohn Dyson #include <sys/mman.h>
791efb74fbSJohn Dyson #include <sys/vnode.h>
802267af78SJulian Elischer #include <sys/resourcevar.h>
8105ba50f5SJake Burkholder #include <sys/sysent.h>
823db161e0SMatthew Dillon #include <sys/shm.h>
83df8bae1dSRodney W. Grimes 
84df8bae1dSRodney W. Grimes #include <vm/vm.h>
85efeaf95aSDavid Greenman #include <vm/vm_param.h>
86efeaf95aSDavid Greenman #include <vm/pmap.h>
87efeaf95aSDavid Greenman #include <vm/vm_map.h>
88df8bae1dSRodney W. Grimes #include <vm/vm_page.h>
89df8bae1dSRodney W. Grimes #include <vm/vm_object.h>
9047221757SJohn Dyson #include <vm/vm_pager.h>
9126f9a767SRodney W. Grimes #include <vm/vm_kern.h>
92efeaf95aSDavid Greenman #include <vm/vm_extern.h>
9321cd6e62SSeigo Tanimura #include <vm/swap_pager.h>
94670d17b5SJeff Roberson #include <vm/uma.h>
95df8bae1dSRodney W. Grimes 
96df8bae1dSRodney W. Grimes /*
97df8bae1dSRodney W. Grimes  *	Virtual memory maps provide for the mapping, protection,
98df8bae1dSRodney W. Grimes  *	and sharing of virtual memory objects.  In addition,
99df8bae1dSRodney W. Grimes  *	this module provides for an efficient virtual copy of
100df8bae1dSRodney W. Grimes  *	memory from one map to another.
101df8bae1dSRodney W. Grimes  *
102df8bae1dSRodney W. Grimes  *	Synchronization is required prior to most operations.
103df8bae1dSRodney W. Grimes  *
104df8bae1dSRodney W. Grimes  *	Maps consist of an ordered doubly-linked list of simple
105df8bae1dSRodney W. Grimes  *	entries; a single hint is used to speed up lookups.
106df8bae1dSRodney W. Grimes  *
107956f3135SPhilippe Charnier  *	Since portions of maps are specified by start/end addresses,
108df8bae1dSRodney W. Grimes  *	which may not align with existing map entries, all
109df8bae1dSRodney W. Grimes  *	routines merely "clip" entries to these start/end values.
110df8bae1dSRodney W. Grimes  *	[That is, an entry is split into two, bordering at a
111df8bae1dSRodney W. Grimes  *	start or end value.]  Note that these clippings may not
112df8bae1dSRodney W. Grimes  *	always be necessary (as the two resulting entries are then
113df8bae1dSRodney W. Grimes  *	not changed); however, the clipping is done for convenience.
114df8bae1dSRodney W. Grimes  *
115df8bae1dSRodney W. Grimes  *	As mentioned above, virtual copy operations are performed
116ad5fca3bSAlan Cox  *	by copying VM object references from one map to
117df8bae1dSRodney W. Grimes  *	another, and then marking both regions as copy-on-write.
118df8bae1dSRodney W. Grimes  */
119df8bae1dSRodney W. Grimes 
120df8bae1dSRodney W. Grimes /*
121df8bae1dSRodney W. Grimes  *	vm_map_startup:
122df8bae1dSRodney W. Grimes  *
123df8bae1dSRodney W. Grimes  *	Initialize the vm_map module.  Must be called before
124df8bae1dSRodney W. Grimes  *	any other vm_map routines.
125df8bae1dSRodney W. Grimes  *
126df8bae1dSRodney W. Grimes  *	Map and entry structures are allocated from the general
127df8bae1dSRodney W. Grimes  *	purpose memory pool with some exceptions:
128df8bae1dSRodney W. Grimes  *
129df8bae1dSRodney W. Grimes  *	- The kernel map and kmem submap are allocated statically.
130df8bae1dSRodney W. Grimes  *	- Kernel map entries are allocated out of a static pool.
131df8bae1dSRodney W. Grimes  *
132df8bae1dSRodney W. Grimes  *	These restrictions are necessary since malloc() uses the
133df8bae1dSRodney W. Grimes  *	maps and requires map entries.
134df8bae1dSRodney W. Grimes  */
135df8bae1dSRodney W. Grimes 
1363a92e5d5SAlan Cox static struct mtx map_sleep_mtx;
1378355f576SJeff Roberson static uma_zone_t mapentzone;
1388355f576SJeff Roberson static uma_zone_t kmapentzone;
1398355f576SJeff Roberson static uma_zone_t mapzone;
1408355f576SJeff Roberson static uma_zone_t vmspace_zone;
1418355f576SJeff Roberson static struct vm_object kmapentobj;
1428355f576SJeff Roberson static void vmspace_zinit(void *mem, int size);
1438355f576SJeff Roberson static void vmspace_zfini(void *mem, int size);
1448355f576SJeff Roberson static void vm_map_zinit(void *mem, int size);
1458355f576SJeff Roberson static void vm_map_zfini(void *mem, int size);
1468355f576SJeff Roberson static void _vm_map_init(vm_map_t map, vm_offset_t min, vm_offset_t max);
1471fc43fd1SAlan Cox 
1488355f576SJeff Roberson #ifdef INVARIANTS
1498355f576SJeff Roberson static void vm_map_zdtor(void *mem, int size, void *arg);
1508355f576SJeff Roberson static void vmspace_zdtor(void *mem, int size, void *arg);
1518355f576SJeff Roberson #endif
152b18bfc3dSJohn Dyson 
1530d94caffSDavid Greenman void
1541b40f8c0SMatthew Dillon vm_map_startup(void)
155df8bae1dSRodney W. Grimes {
1563a92e5d5SAlan Cox 	mtx_init(&map_sleep_mtx, "vm map sleep mutex", NULL, MTX_DEF);
1578355f576SJeff Roberson 	mapzone = uma_zcreate("MAP", sizeof(struct vm_map), NULL,
1588355f576SJeff Roberson #ifdef INVARIANTS
1598355f576SJeff Roberson 	    vm_map_zdtor,
1608355f576SJeff Roberson #else
1618355f576SJeff Roberson 	    NULL,
1628355f576SJeff Roberson #endif
1638355f576SJeff Roberson 	    vm_map_zinit, vm_map_zfini, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
1648355f576SJeff Roberson 	uma_prealloc(mapzone, MAX_KMAP);
165670d17b5SJeff Roberson 	kmapentzone = uma_zcreate("KMAP ENTRY", sizeof(struct vm_map_entry),
16618aa2de5SJeff Roberson 	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR,
16718aa2de5SJeff Roberson 	    UMA_ZONE_MTXCLASS | UMA_ZONE_VM);
168670d17b5SJeff Roberson 	uma_prealloc(kmapentzone, MAX_KMAPENT);
169670d17b5SJeff Roberson 	mapentzone = uma_zcreate("MAP ENTRY", sizeof(struct vm_map_entry),
170670d17b5SJeff Roberson 	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
1718355f576SJeff Roberson 	uma_prealloc(mapentzone, MAX_MAPENT);
172df8bae1dSRodney W. Grimes }
173df8bae1dSRodney W. Grimes 
1748355f576SJeff Roberson static void
1758355f576SJeff Roberson vmspace_zfini(void *mem, int size)
1768355f576SJeff Roberson {
1778355f576SJeff Roberson 	struct vmspace *vm;
1788355f576SJeff Roberson 
1798355f576SJeff Roberson 	vm = (struct vmspace *)mem;
1808355f576SJeff Roberson 
1818355f576SJeff Roberson 	vm_map_zfini(&vm->vm_map, sizeof(vm->vm_map));
1828355f576SJeff Roberson }
1838355f576SJeff Roberson 
1848355f576SJeff Roberson static void
1858355f576SJeff Roberson vmspace_zinit(void *mem, int size)
1868355f576SJeff Roberson {
1878355f576SJeff Roberson 	struct vmspace *vm;
1888355f576SJeff Roberson 
1898355f576SJeff Roberson 	vm = (struct vmspace *)mem;
1908355f576SJeff Roberson 
1918355f576SJeff Roberson 	vm_map_zinit(&vm->vm_map, sizeof(vm->vm_map));
1928355f576SJeff Roberson }
1938355f576SJeff Roberson 
1948355f576SJeff Roberson static void
1958355f576SJeff Roberson vm_map_zfini(void *mem, int size)
1968355f576SJeff Roberson {
1978355f576SJeff Roberson 	vm_map_t map;
1988355f576SJeff Roberson 
1998355f576SJeff Roberson 	map = (vm_map_t)mem;
20036daaecdSAlan Cox 	mtx_destroy(&map->system_mtx);
2018355f576SJeff Roberson 	lockdestroy(&map->lock);
2028355f576SJeff Roberson }
2038355f576SJeff Roberson 
2048355f576SJeff Roberson static void
2058355f576SJeff Roberson vm_map_zinit(void *mem, int size)
2068355f576SJeff Roberson {
2078355f576SJeff Roberson 	vm_map_t map;
2088355f576SJeff Roberson 
2098355f576SJeff Roberson 	map = (vm_map_t)mem;
2108355f576SJeff Roberson 	map->nentries = 0;
2118355f576SJeff Roberson 	map->size = 0;
2128355f576SJeff Roberson 	map->infork = 0;
213d923c598SAlan Cox 	mtx_init(&map->system_mtx, "system map", NULL, MTX_DEF | MTX_DUPOK);
214515630b1SAlan Cox 	lockinit(&map->lock, PVM, "thrd_sleep", 0, LK_NOPAUSE);
2158355f576SJeff Roberson }
2168355f576SJeff Roberson 
2178355f576SJeff Roberson #ifdef INVARIANTS
2188355f576SJeff Roberson static void
2198355f576SJeff Roberson vmspace_zdtor(void *mem, int size, void *arg)
2208355f576SJeff Roberson {
2218355f576SJeff Roberson 	struct vmspace *vm;
2228355f576SJeff Roberson 
2238355f576SJeff Roberson 	vm = (struct vmspace *)mem;
2248355f576SJeff Roberson 
2258355f576SJeff Roberson 	vm_map_zdtor(&vm->vm_map, sizeof(vm->vm_map), arg);
2268355f576SJeff Roberson }
2278355f576SJeff Roberson static void
2288355f576SJeff Roberson vm_map_zdtor(void *mem, int size, void *arg)
2298355f576SJeff Roberson {
2308355f576SJeff Roberson 	vm_map_t map;
2318355f576SJeff Roberson 
2328355f576SJeff Roberson 	map = (vm_map_t)mem;
2338355f576SJeff Roberson 	KASSERT(map->nentries == 0,
2348355f576SJeff Roberson 	    ("map %p nentries == %d on free.",
2358355f576SJeff Roberson 	    map, map->nentries));
2368355f576SJeff Roberson 	KASSERT(map->size == 0,
2378355f576SJeff Roberson 	    ("map %p size == %lu on free.",
2389eb6e519SJeff Roberson 	    map, (unsigned long)map->size));
2398355f576SJeff Roberson 	KASSERT(map->infork == 0,
2408355f576SJeff Roberson 	    ("map %p infork == %d on free.",
2418355f576SJeff Roberson 	    map, map->infork));
2428355f576SJeff Roberson }
2438355f576SJeff Roberson #endif	/* INVARIANTS */
2448355f576SJeff Roberson 
245df8bae1dSRodney W. Grimes /*
246df8bae1dSRodney W. Grimes  * Allocate a vmspace structure, including a vm_map and pmap,
247df8bae1dSRodney W. Grimes  * and initialize those structures.  The refcnt is set to 1.
248df8bae1dSRodney W. Grimes  * The remaining fields must be initialized by the caller.
249df8bae1dSRodney W. Grimes  */
250df8bae1dSRodney W. Grimes struct vmspace *
2512d8acc0fSJohn Dyson vmspace_alloc(min, max)
252df8bae1dSRodney W. Grimes 	vm_offset_t min, max;
253df8bae1dSRodney W. Grimes {
254c0877f10SJohn Dyson 	struct vmspace *vm;
2550d94caffSDavid Greenman 
2560cddd8f0SMatthew Dillon 	GIANT_REQUIRED;
257a163d034SWarner Losh 	vm = uma_zalloc(vmspace_zone, M_WAITOK);
25821c641b2SJohn Baldwin 	CTR1(KTR_VM, "vmspace_alloc: %p", vm);
2598355f576SJeff Roberson 	_vm_map_init(&vm->vm_map, min, max);
260b1028ad1SLuoqi Chen 	pmap_pinit(vmspace_pmap(vm));
261b1028ad1SLuoqi Chen 	vm->vm_map.pmap = vmspace_pmap(vm);		/* XXX */
262df8bae1dSRodney W. Grimes 	vm->vm_refcnt = 1;
2632d8acc0fSJohn Dyson 	vm->vm_shm = NULL;
264389d2b6eSMatthew Dillon 	vm->vm_exitingcnt = 0;
265df8bae1dSRodney W. Grimes 	return (vm);
266df8bae1dSRodney W. Grimes }
267df8bae1dSRodney W. Grimes 
268df8bae1dSRodney W. Grimes void
2691b40f8c0SMatthew Dillon vm_init2(void)
2701b40f8c0SMatthew Dillon {
2719e7c1bceSPeter Wemm 	uma_zone_set_obj(kmapentzone, &kmapentobj, lmin(cnt.v_page_count,
27222a97b04SAlan Cox 	    (VM_MAX_KERNEL_ADDRESS - KERNBASE) / PAGE_SIZE) / 8);
2738355f576SJeff Roberson 	vmspace_zone = uma_zcreate("VMSPACE", sizeof(struct vmspace), NULL,
2748355f576SJeff Roberson #ifdef INVARIANTS
2758355f576SJeff Roberson 	    vmspace_zdtor,
2768355f576SJeff Roberson #else
2778355f576SJeff Roberson 	    NULL,
2788355f576SJeff Roberson #endif
2798355f576SJeff Roberson 	    vmspace_zinit, vmspace_zfini, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
280ba9be04cSJohn Dyson 	pmap_init2();
2813075778bSJohn Dyson }
2823075778bSJohn Dyson 
283582ec34cSAlfred Perlstein static __inline void
284582ec34cSAlfred Perlstein vmspace_dofree(struct vmspace *vm)
285df8bae1dSRodney W. Grimes {
28621c641b2SJohn Baldwin 	CTR1(KTR_VM, "vmspace_free: %p", vm);
2873db161e0SMatthew Dillon 
2883db161e0SMatthew Dillon 	/*
2893db161e0SMatthew Dillon 	 * Make sure any SysV shm is freed, it might not have been in
2903db161e0SMatthew Dillon 	 * exit1().
2913db161e0SMatthew Dillon 	 */
2923db161e0SMatthew Dillon 	shmexit(vm);
2933db161e0SMatthew Dillon 
29430dcfc09SJohn Dyson 	/*
295df8bae1dSRodney W. Grimes 	 * Lock the map, to wait out all other references to it.
2960d94caffSDavid Greenman 	 * Delete all of the mappings and pages they hold, then call
2970d94caffSDavid Greenman 	 * the pmap module to reclaim anything left.
298df8bae1dSRodney W. Grimes 	 */
299df8bae1dSRodney W. Grimes 	vm_map_lock(&vm->vm_map);
300df8bae1dSRodney W. Grimes 	(void) vm_map_delete(&vm->vm_map, vm->vm_map.min_offset,
301df8bae1dSRodney W. Grimes 	    vm->vm_map.max_offset);
302a1f6d91cSDavid Greenman 	vm_map_unlock(&vm->vm_map);
3038355f576SJeff Roberson 
304b1028ad1SLuoqi Chen 	pmap_release(vmspace_pmap(vm));
3058355f576SJeff Roberson 	uma_zfree(vmspace_zone, vm);
306df8bae1dSRodney W. Grimes }
307582ec34cSAlfred Perlstein 
308582ec34cSAlfred Perlstein void
309582ec34cSAlfred Perlstein vmspace_free(struct vmspace *vm)
310582ec34cSAlfred Perlstein {
311582ec34cSAlfred Perlstein 	GIANT_REQUIRED;
312582ec34cSAlfred Perlstein 
313582ec34cSAlfred Perlstein 	if (vm->vm_refcnt == 0)
314582ec34cSAlfred Perlstein 		panic("vmspace_free: attempt to free already freed vmspace");
315582ec34cSAlfred Perlstein 
316389d2b6eSMatthew Dillon 	if (--vm->vm_refcnt == 0 && vm->vm_exitingcnt == 0)
317582ec34cSAlfred Perlstein 		vmspace_dofree(vm);
318582ec34cSAlfred Perlstein }
319582ec34cSAlfred Perlstein 
320582ec34cSAlfred Perlstein void
321582ec34cSAlfred Perlstein vmspace_exitfree(struct proc *p)
322582ec34cSAlfred Perlstein {
323334f7061SPeter Wemm 	struct vmspace *vm;
324582ec34cSAlfred Perlstein 
325334f7061SPeter Wemm 	GIANT_REQUIRED;
326334f7061SPeter Wemm 	vm = p->p_vmspace;
327334f7061SPeter Wemm 	p->p_vmspace = NULL;
328389d2b6eSMatthew Dillon 
329389d2b6eSMatthew Dillon 	/*
330389d2b6eSMatthew Dillon 	 * cleanup by parent process wait()ing on exiting child.  vm_refcnt
331389d2b6eSMatthew Dillon 	 * may not be 0 (e.g. fork() and child exits without exec()ing).
332389d2b6eSMatthew Dillon 	 * exitingcnt may increment above 0 and drop back down to zero
333389d2b6eSMatthew Dillon 	 * several times while vm_refcnt is held non-zero.  vm_refcnt
334389d2b6eSMatthew Dillon 	 * may also increment above 0 and drop back down to zero several
335389d2b6eSMatthew Dillon 	 * times while vm_exitingcnt is held non-zero.
336389d2b6eSMatthew Dillon 	 *
337389d2b6eSMatthew Dillon 	 * The last wait on the exiting child's vmspace will clean up
338389d2b6eSMatthew Dillon 	 * the remainder of the vmspace.
339389d2b6eSMatthew Dillon 	 */
340389d2b6eSMatthew Dillon 	if (--vm->vm_exitingcnt == 0 && vm->vm_refcnt == 0)
341334f7061SPeter Wemm 		vmspace_dofree(vm);
342334f7061SPeter Wemm }
343df8bae1dSRodney W. Grimes 
344df8bae1dSRodney W. Grimes /*
345ff2b5645SMatthew Dillon  * vmspace_swap_count() - count the approximate swap useage in pages for a
346ff2b5645SMatthew Dillon  *			  vmspace.
347ff2b5645SMatthew Dillon  *
34872d97679SDavid Schultz  *	The map must be locked.
34972d97679SDavid Schultz  *
350ff2b5645SMatthew Dillon  *	Swap useage is determined by taking the proportional swap used by
351ff2b5645SMatthew Dillon  *	VM objects backing the VM map.  To make up for fractional losses,
352ff2b5645SMatthew Dillon  *	if the VM object has any swap use at all the associated map entries
353ff2b5645SMatthew Dillon  *	count for at least 1 swap page.
354ff2b5645SMatthew Dillon  */
355ff2b5645SMatthew Dillon int
356ff2b5645SMatthew Dillon vmspace_swap_count(struct vmspace *vmspace)
357ff2b5645SMatthew Dillon {
358ff2b5645SMatthew Dillon 	vm_map_t map = &vmspace->vm_map;
359ff2b5645SMatthew Dillon 	vm_map_entry_t cur;
360ff2b5645SMatthew Dillon 	int count = 0;
361ff2b5645SMatthew Dillon 
362ff2b5645SMatthew Dillon 	for (cur = map->header.next; cur != &map->header; cur = cur->next) {
363ff2b5645SMatthew Dillon 		vm_object_t object;
364ff2b5645SMatthew Dillon 
365ff2b5645SMatthew Dillon 		if ((cur->eflags & MAP_ENTRY_IS_SUB_MAP) == 0 &&
366ff2b5645SMatthew Dillon 		    (object = cur->object.vm_object) != NULL &&
367ff2b5645SMatthew Dillon 		    object->type == OBJT_SWAP
368ff2b5645SMatthew Dillon 		) {
369ff2b5645SMatthew Dillon 			int n = (cur->end - cur->start) / PAGE_SIZE;
370ff2b5645SMatthew Dillon 
371ff2b5645SMatthew Dillon 			if (object->un_pager.swp.swp_bcount) {
372ef6a93efSMatthew Dillon 				count += object->un_pager.swp.swp_bcount *
373ef6a93efSMatthew Dillon 				    SWAP_META_PAGES * n / object->size + 1;
374ff2b5645SMatthew Dillon 			}
375ff2b5645SMatthew Dillon 		}
376ff2b5645SMatthew Dillon 	}
377ff2b5645SMatthew Dillon 	return (count);
378ff2b5645SMatthew Dillon }
379ff2b5645SMatthew Dillon 
3801b40f8c0SMatthew Dillon void
381780b1c09SAlan Cox _vm_map_lock(vm_map_t map, const char *file, int line)
3821b40f8c0SMatthew Dillon {
383bc91c510SAlan Cox 	int error;
384bc91c510SAlan Cox 
38593bc4879SAlan Cox 	if (map->system_map)
38636daaecdSAlan Cox 		_mtx_lock_flags(&map->system_mtx, 0, file, line);
38736daaecdSAlan Cox 	else {
388bc91c510SAlan Cox 		error = lockmgr(&map->lock, LK_EXCLUSIVE, NULL, curthread);
389bc91c510SAlan Cox 		KASSERT(error == 0, ("%s: failed to get lock", __func__));
39036daaecdSAlan Cox 	}
3911b40f8c0SMatthew Dillon 	map->timestamp++;
3921b40f8c0SMatthew Dillon }
3931b40f8c0SMatthew Dillon 
3941b40f8c0SMatthew Dillon void
395780b1c09SAlan Cox _vm_map_unlock(vm_map_t map, const char *file, int line)
3960e0af8ecSBrian Feldman {
397bc91c510SAlan Cox 
39836daaecdSAlan Cox 	if (map->system_map)
39936daaecdSAlan Cox 		_mtx_unlock_flags(&map->system_mtx, 0, file, line);
40036daaecdSAlan Cox 	else
401bc91c510SAlan Cox 		lockmgr(&map->lock, LK_RELEASE, NULL, curthread);
4020e0af8ecSBrian Feldman }
4030e0af8ecSBrian Feldman 
4040e0af8ecSBrian Feldman void
405780b1c09SAlan Cox _vm_map_lock_read(vm_map_t map, const char *file, int line)
4060e0af8ecSBrian Feldman {
407bc91c510SAlan Cox 	int error;
408bc91c510SAlan Cox 
40993bc4879SAlan Cox 	if (map->system_map)
41036daaecdSAlan Cox 		_mtx_lock_flags(&map->system_mtx, 0, file, line);
41136daaecdSAlan Cox 	else {
412bc91c510SAlan Cox 		error = lockmgr(&map->lock, LK_EXCLUSIVE, NULL, curthread);
413bc91c510SAlan Cox 		KASSERT(error == 0, ("%s: failed to get lock", __func__));
4140e0af8ecSBrian Feldman 	}
41536daaecdSAlan Cox }
4160e0af8ecSBrian Feldman 
4170e0af8ecSBrian Feldman void
418780b1c09SAlan Cox _vm_map_unlock_read(vm_map_t map, const char *file, int line)
4190e0af8ecSBrian Feldman {
420bc91c510SAlan Cox 
42136daaecdSAlan Cox 	if (map->system_map)
42236daaecdSAlan Cox 		_mtx_unlock_flags(&map->system_mtx, 0, file, line);
42336daaecdSAlan Cox 	else
424bc91c510SAlan Cox 		lockmgr(&map->lock, LK_RELEASE, NULL, curthread);
42525adb370SBrian Feldman }
42625adb370SBrian Feldman 
427d974f03cSAlan Cox int
428780b1c09SAlan Cox _vm_map_trylock(vm_map_t map, const char *file, int line)
429d974f03cSAlan Cox {
43025adb370SBrian Feldman 	int error;
43125adb370SBrian Feldman 
43236daaecdSAlan Cox 	error = map->system_map ?
43336daaecdSAlan Cox 	    !_mtx_trylock(&map->system_mtx, 0, file, line) :
43436daaecdSAlan Cox 	    lockmgr(&map->lock, LK_EXCLUSIVE | LK_NOWAIT, NULL, curthread);
4353a92e5d5SAlan Cox 	if (error == 0)
4363a92e5d5SAlan Cox 		map->timestamp++;
437bc91c510SAlan Cox 	return (error == 0);
4380e0af8ecSBrian Feldman }
4390e0af8ecSBrian Feldman 
4400e0af8ecSBrian Feldman int
44172d97679SDavid Schultz _vm_map_trylock_read(vm_map_t map, const char *file, int line)
44272d97679SDavid Schultz {
44372d97679SDavid Schultz 	int error;
44472d97679SDavid Schultz 
44572d97679SDavid Schultz 	error = map->system_map ?
44672d97679SDavid Schultz 	    !_mtx_trylock(&map->system_mtx, 0, file, line) :
44772d97679SDavid Schultz 	    lockmgr(&map->lock, LK_EXCLUSIVE | LK_NOWAIT, NULL, curthread);
44872d97679SDavid Schultz 	return (error == 0);
44972d97679SDavid Schultz }
45072d97679SDavid Schultz 
45172d97679SDavid Schultz int
452780b1c09SAlan Cox _vm_map_lock_upgrade(vm_map_t map, const char *file, int line)
4530e0af8ecSBrian Feldman {
454bc91c510SAlan Cox 
45536daaecdSAlan Cox 	if (map->system_map) {
45636daaecdSAlan Cox #ifdef INVARIANTS
45736daaecdSAlan Cox 		_mtx_assert(&map->system_mtx, MA_OWNED, file, line);
45836daaecdSAlan Cox #endif
45936daaecdSAlan Cox 	} else
460bc91c510SAlan Cox 		KASSERT(lockstatus(&map->lock, curthread) == LK_EXCLUSIVE,
461bc91c510SAlan Cox 		    ("%s: lock not held", __func__));
462bc91c510SAlan Cox 	map->timestamp++;
463bc91c510SAlan Cox 	return (0);
4640e0af8ecSBrian Feldman }
4650e0af8ecSBrian Feldman 
4660e0af8ecSBrian Feldman void
467780b1c09SAlan Cox _vm_map_lock_downgrade(vm_map_t map, const char *file, int line)
4681b40f8c0SMatthew Dillon {
469bc91c510SAlan Cox 
47036daaecdSAlan Cox 	if (map->system_map) {
47136daaecdSAlan Cox #ifdef INVARIANTS
47236daaecdSAlan Cox 		_mtx_assert(&map->system_mtx, MA_OWNED, file, line);
47336daaecdSAlan Cox #endif
47436daaecdSAlan Cox 	} else
475bc91c510SAlan Cox 		KASSERT(lockstatus(&map->lock, curthread) == LK_EXCLUSIVE,
476bc91c510SAlan Cox 		    ("%s: lock not held", __func__));
47725adb370SBrian Feldman }
47825adb370SBrian Feldman 
479acd9a301SAlan Cox /*
480acd9a301SAlan Cox  *	vm_map_unlock_and_wait:
481acd9a301SAlan Cox  */
4829688f931SAlan Cox int
483acd9a301SAlan Cox vm_map_unlock_and_wait(vm_map_t map, boolean_t user_wait)
484acd9a301SAlan Cox {
485acd9a301SAlan Cox 
4863a92e5d5SAlan Cox 	mtx_lock(&map_sleep_mtx);
487acd9a301SAlan Cox 	vm_map_unlock(map);
4883a92e5d5SAlan Cox 	return (msleep(&map->root, &map_sleep_mtx, PDROP | PVM, "vmmaps", 0));
489acd9a301SAlan Cox }
490acd9a301SAlan Cox 
491acd9a301SAlan Cox /*
492acd9a301SAlan Cox  *	vm_map_wakeup:
493acd9a301SAlan Cox  */
4949688f931SAlan Cox void
495acd9a301SAlan Cox vm_map_wakeup(vm_map_t map)
496acd9a301SAlan Cox {
497acd9a301SAlan Cox 
498b49ecb86SAlan Cox 	/*
4993a92e5d5SAlan Cox 	 * Acquire and release map_sleep_mtx to prevent a wakeup()
5003a92e5d5SAlan Cox 	 * from being performed (and lost) between the vm_map_unlock()
5013a92e5d5SAlan Cox 	 * and the msleep() in vm_map_unlock_and_wait().
502b49ecb86SAlan Cox 	 */
5033a92e5d5SAlan Cox 	mtx_lock(&map_sleep_mtx);
5043a92e5d5SAlan Cox 	mtx_unlock(&map_sleep_mtx);
505acd9a301SAlan Cox 	wakeup(&map->root);
506acd9a301SAlan Cox }
507acd9a301SAlan Cox 
5081b40f8c0SMatthew Dillon long
5091b40f8c0SMatthew Dillon vmspace_resident_count(struct vmspace *vmspace)
5101b40f8c0SMatthew Dillon {
5111b40f8c0SMatthew Dillon 	return pmap_resident_count(vmspace_pmap(vmspace));
5121b40f8c0SMatthew Dillon }
5131b40f8c0SMatthew Dillon 
514ff2b5645SMatthew Dillon /*
515df8bae1dSRodney W. Grimes  *	vm_map_create:
516df8bae1dSRodney W. Grimes  *
517df8bae1dSRodney W. Grimes  *	Creates and returns a new empty VM map with
518df8bae1dSRodney W. Grimes  *	the given physical map structure, and having
519df8bae1dSRodney W. Grimes  *	the given lower and upper address bounds.
520df8bae1dSRodney W. Grimes  */
5210d94caffSDavid Greenman vm_map_t
5221b40f8c0SMatthew Dillon vm_map_create(pmap_t pmap, vm_offset_t min, vm_offset_t max)
523df8bae1dSRodney W. Grimes {
524c0877f10SJohn Dyson 	vm_map_t result;
525df8bae1dSRodney W. Grimes 
526a163d034SWarner Losh 	result = uma_zalloc(mapzone, M_WAITOK);
52721c641b2SJohn Baldwin 	CTR1(KTR_VM, "vm_map_create: %p", result);
5288355f576SJeff Roberson 	_vm_map_init(result, min, max);
529df8bae1dSRodney W. Grimes 	result->pmap = pmap;
530df8bae1dSRodney W. Grimes 	return (result);
531df8bae1dSRodney W. Grimes }
532df8bae1dSRodney W. Grimes 
533df8bae1dSRodney W. Grimes /*
534df8bae1dSRodney W. Grimes  * Initialize an existing vm_map structure
535df8bae1dSRodney W. Grimes  * such as that in the vmspace structure.
536df8bae1dSRodney W. Grimes  * The pmap is set elsewhere.
537df8bae1dSRodney W. Grimes  */
5388355f576SJeff Roberson static void
5398355f576SJeff Roberson _vm_map_init(vm_map_t map, vm_offset_t min, vm_offset_t max)
540df8bae1dSRodney W. Grimes {
54121c641b2SJohn Baldwin 
542df8bae1dSRodney W. Grimes 	map->header.next = map->header.prev = &map->header;
5439688f931SAlan Cox 	map->needs_wakeup = FALSE;
5443075778bSJohn Dyson 	map->system_map = 0;
545df8bae1dSRodney W. Grimes 	map->min_offset = min;
546df8bae1dSRodney W. Grimes 	map->max_offset = max;
547df8bae1dSRodney W. Grimes 	map->first_free = &map->header;
5484e94f402SAlan Cox 	map->root = NULL;
549df8bae1dSRodney W. Grimes 	map->timestamp = 0;
550df8bae1dSRodney W. Grimes }
551df8bae1dSRodney W. Grimes 
552a18b1f1dSJason Evans void
5538355f576SJeff Roberson vm_map_init(vm_map_t map, vm_offset_t min, vm_offset_t max)
554a18b1f1dSJason Evans {
5558355f576SJeff Roberson 	_vm_map_init(map, min, max);
556d923c598SAlan Cox 	mtx_init(&map->system_mtx, "system map", NULL, MTX_DEF | MTX_DUPOK);
557515630b1SAlan Cox 	lockinit(&map->lock, PVM, "thrd_sleep", 0, LK_NOPAUSE);
558a18b1f1dSJason Evans }
559a18b1f1dSJason Evans 
560df8bae1dSRodney W. Grimes /*
561b18bfc3dSJohn Dyson  *	vm_map_entry_dispose:	[ internal use only ]
562b18bfc3dSJohn Dyson  *
563b18bfc3dSJohn Dyson  *	Inverse of vm_map_entry_create.
564b18bfc3dSJohn Dyson  */
56562487bb4SJohn Dyson static void
5661b40f8c0SMatthew Dillon vm_map_entry_dispose(vm_map_t map, vm_map_entry_t entry)
567b18bfc3dSJohn Dyson {
5682b4a2c27SAlan Cox 	uma_zfree(map->system_map ? kmapentzone : mapentzone, entry);
569b18bfc3dSJohn Dyson }
570b18bfc3dSJohn Dyson 
571b18bfc3dSJohn Dyson /*
572df8bae1dSRodney W. Grimes  *	vm_map_entry_create:	[ internal use only ]
573df8bae1dSRodney W. Grimes  *
574df8bae1dSRodney W. Grimes  *	Allocates a VM map entry for insertion.
575b28cb1caSAlfred Perlstein  *	No entry fields are filled in.
576df8bae1dSRodney W. Grimes  */
577f708ef1bSPoul-Henning Kamp static vm_map_entry_t
5781b40f8c0SMatthew Dillon vm_map_entry_create(vm_map_t map)
579df8bae1dSRodney W. Grimes {
5801f6889a1SMatthew Dillon 	vm_map_entry_t new_entry;
5811f6889a1SMatthew Dillon 
5822b4a2c27SAlan Cox 	if (map->system_map)
5832b4a2c27SAlan Cox 		new_entry = uma_zalloc(kmapentzone, M_NOWAIT);
5842b4a2c27SAlan Cox 	else
585a163d034SWarner Losh 		new_entry = uma_zalloc(mapentzone, M_WAITOK);
5861f6889a1SMatthew Dillon 	if (new_entry == NULL)
5871f6889a1SMatthew Dillon 		panic("vm_map_entry_create: kernel resources exhausted");
5881f6889a1SMatthew Dillon 	return (new_entry);
589df8bae1dSRodney W. Grimes }
590df8bae1dSRodney W. Grimes 
591df8bae1dSRodney W. Grimes /*
592794316a8SAlan Cox  *	vm_map_entry_set_behavior:
593794316a8SAlan Cox  *
594794316a8SAlan Cox  *	Set the expected access behavior, either normal, random, or
595794316a8SAlan Cox  *	sequential.
596794316a8SAlan Cox  */
597794316a8SAlan Cox static __inline void
598794316a8SAlan Cox vm_map_entry_set_behavior(vm_map_entry_t entry, u_char behavior)
599794316a8SAlan Cox {
600794316a8SAlan Cox 	entry->eflags = (entry->eflags & ~MAP_ENTRY_BEHAV_MASK) |
601794316a8SAlan Cox 	    (behavior & MAP_ENTRY_BEHAV_MASK);
602794316a8SAlan Cox }
603794316a8SAlan Cox 
604794316a8SAlan Cox /*
6054e94f402SAlan Cox  *	vm_map_entry_splay:
6064e94f402SAlan Cox  *
6074e94f402SAlan Cox  *	Implements Sleator and Tarjan's top-down splay algorithm.  Returns
6084e94f402SAlan Cox  *	the vm_map_entry containing the given address.  If, however, that
6094e94f402SAlan Cox  *	address is not found in the vm_map, returns a vm_map_entry that is
6104e94f402SAlan Cox  *	adjacent to the address, coming before or after it.
6114e94f402SAlan Cox  */
6124e94f402SAlan Cox static vm_map_entry_t
6134e94f402SAlan Cox vm_map_entry_splay(vm_offset_t address, vm_map_entry_t root)
6144e94f402SAlan Cox {
6154e94f402SAlan Cox 	struct vm_map_entry dummy;
6164e94f402SAlan Cox 	vm_map_entry_t lefttreemax, righttreemin, y;
6174e94f402SAlan Cox 
6184e94f402SAlan Cox 	if (root == NULL)
6194e94f402SAlan Cox 		return (root);
6204e94f402SAlan Cox 	lefttreemax = righttreemin = &dummy;
62161c075b6SAlan Cox 	for (;; root = y) {
6224e94f402SAlan Cox 		if (address < root->start) {
62361c075b6SAlan Cox 			if ((y = root->left) == NULL)
6244e94f402SAlan Cox 				break;
62561c075b6SAlan Cox 			if (address < y->start) {
6264e94f402SAlan Cox 				/* Rotate right. */
6274e94f402SAlan Cox 				root->left = y->right;
6284e94f402SAlan Cox 				y->right = root;
6294e94f402SAlan Cox 				root = y;
63061c075b6SAlan Cox 				if ((y = root->left) == NULL)
6314e94f402SAlan Cox 					break;
6324e94f402SAlan Cox 			}
6334e94f402SAlan Cox 			/* Link into the new root's right tree. */
6344e94f402SAlan Cox 			righttreemin->left = root;
6354e94f402SAlan Cox 			righttreemin = root;
6364e94f402SAlan Cox 		} else if (address >= root->end) {
63761c075b6SAlan Cox 			if ((y = root->right) == NULL)
6384e94f402SAlan Cox 				break;
63961c075b6SAlan Cox 			if (address >= y->end) {
6404e94f402SAlan Cox 				/* Rotate left. */
6414e94f402SAlan Cox 				root->right = y->left;
6424e94f402SAlan Cox 				y->left = root;
6434e94f402SAlan Cox 				root = y;
64461c075b6SAlan Cox 				if ((y = root->right) == NULL)
6454e94f402SAlan Cox 					break;
6464e94f402SAlan Cox 			}
6474e94f402SAlan Cox 			/* Link into the new root's left tree. */
6484e94f402SAlan Cox 			lefttreemax->right = root;
6494e94f402SAlan Cox 			lefttreemax = root;
6504e94f402SAlan Cox 		} else
6514e94f402SAlan Cox 			break;
6524e94f402SAlan Cox 	}
6534e94f402SAlan Cox 	/* Assemble the new root. */
6544e94f402SAlan Cox 	lefttreemax->right = root->left;
6554e94f402SAlan Cox 	righttreemin->left = root->right;
6564e94f402SAlan Cox 	root->left = dummy.right;
6574e94f402SAlan Cox 	root->right = dummy.left;
6584e94f402SAlan Cox 	return (root);
6594e94f402SAlan Cox }
6604e94f402SAlan Cox 
6614e94f402SAlan Cox /*
662df8bae1dSRodney W. Grimes  *	vm_map_entry_{un,}link:
663df8bae1dSRodney W. Grimes  *
664df8bae1dSRodney W. Grimes  *	Insert/remove entries from maps.
665df8bae1dSRodney W. Grimes  */
6664e94f402SAlan Cox static void
66799c81ca9SAlan Cox vm_map_entry_link(vm_map_t map,
66899c81ca9SAlan Cox 		  vm_map_entry_t after_where,
66999c81ca9SAlan Cox 		  vm_map_entry_t entry)
67099c81ca9SAlan Cox {
67121c641b2SJohn Baldwin 
67221c641b2SJohn Baldwin 	CTR4(KTR_VM,
67321c641b2SJohn Baldwin 	    "vm_map_entry_link: map %p, nentries %d, entry %p, after %p", map,
67421c641b2SJohn Baldwin 	    map->nentries, entry, after_where);
67599c81ca9SAlan Cox 	map->nentries++;
67699c81ca9SAlan Cox 	entry->prev = after_where;
67799c81ca9SAlan Cox 	entry->next = after_where->next;
67899c81ca9SAlan Cox 	entry->next->prev = entry;
67999c81ca9SAlan Cox 	after_where->next = entry;
6804e94f402SAlan Cox 
6814e94f402SAlan Cox 	if (after_where != &map->header) {
6824e94f402SAlan Cox 		if (after_where != map->root)
6834e94f402SAlan Cox 			vm_map_entry_splay(after_where->start, map->root);
6844e94f402SAlan Cox 		entry->right = after_where->right;
6854e94f402SAlan Cox 		entry->left = after_where;
6864e94f402SAlan Cox 		after_where->right = NULL;
6874e94f402SAlan Cox 	} else {
6884e94f402SAlan Cox 		entry->right = map->root;
6894e94f402SAlan Cox 		entry->left = NULL;
6904e94f402SAlan Cox 	}
6914e94f402SAlan Cox 	map->root = entry;
692df8bae1dSRodney W. Grimes }
69399c81ca9SAlan Cox 
6944e94f402SAlan Cox static void
69599c81ca9SAlan Cox vm_map_entry_unlink(vm_map_t map,
69699c81ca9SAlan Cox 		    vm_map_entry_t entry)
69799c81ca9SAlan Cox {
6984e94f402SAlan Cox 	vm_map_entry_t next, prev, root;
69999c81ca9SAlan Cox 
7004e94f402SAlan Cox 	if (entry != map->root)
7014e94f402SAlan Cox 		vm_map_entry_splay(entry->start, map->root);
7024e94f402SAlan Cox 	if (entry->left == NULL)
7034e94f402SAlan Cox 		root = entry->right;
7044e94f402SAlan Cox 	else {
7054e94f402SAlan Cox 		root = vm_map_entry_splay(entry->start, entry->left);
7064e94f402SAlan Cox 		root->right = entry->right;
7074e94f402SAlan Cox 	}
7084e94f402SAlan Cox 	map->root = root;
7094e94f402SAlan Cox 
7104e94f402SAlan Cox 	prev = entry->prev;
7114e94f402SAlan Cox 	next = entry->next;
71299c81ca9SAlan Cox 	next->prev = prev;
71399c81ca9SAlan Cox 	prev->next = next;
71499c81ca9SAlan Cox 	map->nentries--;
71521c641b2SJohn Baldwin 	CTR3(KTR_VM, "vm_map_entry_unlink: map %p, nentries %d, entry %p", map,
71621c641b2SJohn Baldwin 	    map->nentries, entry);
717df8bae1dSRodney W. Grimes }
718df8bae1dSRodney W. Grimes 
719df8bae1dSRodney W. Grimes /*
720df8bae1dSRodney W. Grimes  *	vm_map_lookup_entry:	[ internal use only ]
721df8bae1dSRodney W. Grimes  *
722df8bae1dSRodney W. Grimes  *	Finds the map entry containing (or
723df8bae1dSRodney W. Grimes  *	immediately preceding) the specified address
724df8bae1dSRodney W. Grimes  *	in the given map; the entry is returned
725df8bae1dSRodney W. Grimes  *	in the "entry" parameter.  The boolean
726df8bae1dSRodney W. Grimes  *	result indicates whether the address is
727df8bae1dSRodney W. Grimes  *	actually contained in the map.
728df8bae1dSRodney W. Grimes  */
7290d94caffSDavid Greenman boolean_t
7301b40f8c0SMatthew Dillon vm_map_lookup_entry(
7311b40f8c0SMatthew Dillon 	vm_map_t map,
7321b40f8c0SMatthew Dillon 	vm_offset_t address,
7331b40f8c0SMatthew Dillon 	vm_map_entry_t *entry)	/* OUT */
734df8bae1dSRodney W. Grimes {
735c0877f10SJohn Dyson 	vm_map_entry_t cur;
736df8bae1dSRodney W. Grimes 
7374e94f402SAlan Cox 	cur = vm_map_entry_splay(address, map->root);
7384e94f402SAlan Cox 	if (cur == NULL)
7394e94f402SAlan Cox 		*entry = &map->header;
7404e94f402SAlan Cox 	else {
7414e94f402SAlan Cox 		map->root = cur;
742df8bae1dSRodney W. Grimes 
743df8bae1dSRodney W. Grimes 		if (address >= cur->start) {
744df8bae1dSRodney W. Grimes 			*entry = cur;
7454e94f402SAlan Cox 			if (cur->end > address)
746df8bae1dSRodney W. Grimes 				return (TRUE);
7474e94f402SAlan Cox 		} else
748df8bae1dSRodney W. Grimes 			*entry = cur->prev;
7494e94f402SAlan Cox 	}
750df8bae1dSRodney W. Grimes 	return (FALSE);
751df8bae1dSRodney W. Grimes }
752df8bae1dSRodney W. Grimes 
753df8bae1dSRodney W. Grimes /*
75430dcfc09SJohn Dyson  *	vm_map_insert:
75530dcfc09SJohn Dyson  *
75630dcfc09SJohn Dyson  *	Inserts the given whole VM object into the target
75730dcfc09SJohn Dyson  *	map at the specified address range.  The object's
75830dcfc09SJohn Dyson  *	size should match that of the address range.
75930dcfc09SJohn Dyson  *
76030dcfc09SJohn Dyson  *	Requires that the map be locked, and leaves it so.
7612aaeadf8SMatthew Dillon  *
7622aaeadf8SMatthew Dillon  *	If object is non-NULL, ref count must be bumped by caller
7632aaeadf8SMatthew Dillon  *	prior to making call to account for the new entry.
76430dcfc09SJohn Dyson  */
76530dcfc09SJohn Dyson int
766b9dcd593SBruce Evans vm_map_insert(vm_map_t map, vm_object_t object, vm_ooffset_t offset,
767b9dcd593SBruce Evans 	      vm_offset_t start, vm_offset_t end, vm_prot_t prot, vm_prot_t max,
768b9dcd593SBruce Evans 	      int cow)
76930dcfc09SJohn Dyson {
770c0877f10SJohn Dyson 	vm_map_entry_t new_entry;
771c0877f10SJohn Dyson 	vm_map_entry_t prev_entry;
77230dcfc09SJohn Dyson 	vm_map_entry_t temp_entry;
7739730a5daSPaul Saab 	vm_eflags_t protoeflags;
77430dcfc09SJohn Dyson 
77530dcfc09SJohn Dyson 	/*
77630dcfc09SJohn Dyson 	 * Check that the start and end points are not bogus.
77730dcfc09SJohn Dyson 	 */
77830dcfc09SJohn Dyson 	if ((start < map->min_offset) || (end > map->max_offset) ||
77930dcfc09SJohn Dyson 	    (start >= end))
78030dcfc09SJohn Dyson 		return (KERN_INVALID_ADDRESS);
78130dcfc09SJohn Dyson 
78230dcfc09SJohn Dyson 	/*
78330dcfc09SJohn Dyson 	 * Find the entry prior to the proposed starting address; if it's part
78430dcfc09SJohn Dyson 	 * of an existing entry, this range is bogus.
78530dcfc09SJohn Dyson 	 */
78630dcfc09SJohn Dyson 	if (vm_map_lookup_entry(map, start, &temp_entry))
78730dcfc09SJohn Dyson 		return (KERN_NO_SPACE);
78830dcfc09SJohn Dyson 
78930dcfc09SJohn Dyson 	prev_entry = temp_entry;
79030dcfc09SJohn Dyson 
79130dcfc09SJohn Dyson 	/*
79230dcfc09SJohn Dyson 	 * Assert that the next entry doesn't overlap the end point.
79330dcfc09SJohn Dyson 	 */
79430dcfc09SJohn Dyson 	if ((prev_entry->next != &map->header) &&
79530dcfc09SJohn Dyson 	    (prev_entry->next->start < end))
79630dcfc09SJohn Dyson 		return (KERN_NO_SPACE);
79730dcfc09SJohn Dyson 
798afa07f7eSJohn Dyson 	protoeflags = 0;
799afa07f7eSJohn Dyson 
800afa07f7eSJohn Dyson 	if (cow & MAP_COPY_ON_WRITE)
801e5f13bddSAlan Cox 		protoeflags |= MAP_ENTRY_COW|MAP_ENTRY_NEEDS_COPY;
802afa07f7eSJohn Dyson 
8034e045f93SAlan Cox 	if (cow & MAP_NOFAULT) {
804afa07f7eSJohn Dyson 		protoeflags |= MAP_ENTRY_NOFAULT;
805afa07f7eSJohn Dyson 
8064e045f93SAlan Cox 		KASSERT(object == NULL,
8074e045f93SAlan Cox 			("vm_map_insert: paradoxical MAP_NOFAULT request"));
8084e045f93SAlan Cox 	}
8094f79d873SMatthew Dillon 	if (cow & MAP_DISABLE_SYNCER)
8104f79d873SMatthew Dillon 		protoeflags |= MAP_ENTRY_NOSYNC;
8119730a5daSPaul Saab 	if (cow & MAP_DISABLE_COREDUMP)
8129730a5daSPaul Saab 		protoeflags |= MAP_ENTRY_NOCOREDUMP;
8134f79d873SMatthew Dillon 
8141d284e00SAlan Cox 	if (object != NULL) {
81530dcfc09SJohn Dyson 		/*
8161d284e00SAlan Cox 		 * OBJ_ONEMAPPING must be cleared unless this mapping
8171d284e00SAlan Cox 		 * is trivially proven to be the only mapping for any
8181d284e00SAlan Cox 		 * of the object's pages.  (Object granularity
8191d284e00SAlan Cox 		 * reference counting is insufficient to recognize
8201d284e00SAlan Cox 		 * aliases with precision.)
82130dcfc09SJohn Dyson 		 */
8221d284e00SAlan Cox 		if (object != kmem_object)
8231d284e00SAlan Cox 			mtx_lock(&Giant);
8241d284e00SAlan Cox 		VM_OBJECT_LOCK(object);
8251d284e00SAlan Cox 		if (object->ref_count > 1 || object->shadow_count != 0)
8262aaeadf8SMatthew Dillon 			vm_object_clear_flag(object, OBJ_ONEMAPPING);
8271d284e00SAlan Cox 		VM_OBJECT_UNLOCK(object);
8281d284e00SAlan Cox 		if (object != kmem_object)
8291d284e00SAlan Cox 			mtx_unlock(&Giant);
8304e045f93SAlan Cox 	}
8314e045f93SAlan Cox 	else if ((prev_entry != &map->header) &&
8324e045f93SAlan Cox 		 (prev_entry->eflags == protoeflags) &&
8338cc7e047SJohn Dyson 		 (prev_entry->end == start) &&
8344e045f93SAlan Cox 		 (prev_entry->wired_count == 0) &&
8354e045f93SAlan Cox 		 ((prev_entry->object.vm_object == NULL) ||
8368cc7e047SJohn Dyson 		  vm_object_coalesce(prev_entry->object.vm_object,
83730dcfc09SJohn Dyson 				     OFF_TO_IDX(prev_entry->offset),
8388cc7e047SJohn Dyson 				     (vm_size_t)(prev_entry->end - prev_entry->start),
839cdc2c291SJohn Dyson 				     (vm_size_t)(end - prev_entry->end)))) {
84030dcfc09SJohn Dyson 		/*
8412aaeadf8SMatthew Dillon 		 * We were able to extend the object.  Determine if we
8422aaeadf8SMatthew Dillon 		 * can extend the previous map entry to include the
8432aaeadf8SMatthew Dillon 		 * new range as well.
84430dcfc09SJohn Dyson 		 */
8458cc7e047SJohn Dyson 		if ((prev_entry->inheritance == VM_INHERIT_DEFAULT) &&
8468cc7e047SJohn Dyson 		    (prev_entry->protection == prot) &&
8478cc7e047SJohn Dyson 		    (prev_entry->max_protection == max)) {
84830dcfc09SJohn Dyson 			map->size += (end - prev_entry->end);
84930dcfc09SJohn Dyson 			prev_entry->end = end;
8504e71e795SMatthew Dillon 			vm_map_simplify_entry(map, prev_entry);
85130dcfc09SJohn Dyson 			return (KERN_SUCCESS);
85230dcfc09SJohn Dyson 		}
8538cc7e047SJohn Dyson 
8542aaeadf8SMatthew Dillon 		/*
8552aaeadf8SMatthew Dillon 		 * If we can extend the object but cannot extend the
8562aaeadf8SMatthew Dillon 		 * map entry, we have to create a new map entry.  We
8572aaeadf8SMatthew Dillon 		 * must bump the ref count on the extended object to
8584e71e795SMatthew Dillon 		 * account for it.  object may be NULL.
8592aaeadf8SMatthew Dillon 		 */
8602aaeadf8SMatthew Dillon 		object = prev_entry->object.vm_object;
8612aaeadf8SMatthew Dillon 		offset = prev_entry->offset +
8622aaeadf8SMatthew Dillon 			(prev_entry->end - prev_entry->start);
8638cc7e047SJohn Dyson 		vm_object_reference(object);
864b18bfc3dSJohn Dyson 	}
8652aaeadf8SMatthew Dillon 
8662aaeadf8SMatthew Dillon 	/*
8672aaeadf8SMatthew Dillon 	 * NOTE: if conditionals fail, object can be NULL here.  This occurs
8682aaeadf8SMatthew Dillon 	 * in things like the buffer map where we manage kva but do not manage
8692aaeadf8SMatthew Dillon 	 * backing objects.
8702aaeadf8SMatthew Dillon 	 */
8718cc7e047SJohn Dyson 
87230dcfc09SJohn Dyson 	/*
87330dcfc09SJohn Dyson 	 * Create a new entry
87430dcfc09SJohn Dyson 	 */
87530dcfc09SJohn Dyson 	new_entry = vm_map_entry_create(map);
87630dcfc09SJohn Dyson 	new_entry->start = start;
87730dcfc09SJohn Dyson 	new_entry->end = end;
87830dcfc09SJohn Dyson 
879afa07f7eSJohn Dyson 	new_entry->eflags = protoeflags;
88030dcfc09SJohn Dyson 	new_entry->object.vm_object = object;
88130dcfc09SJohn Dyson 	new_entry->offset = offset;
8822267af78SJulian Elischer 	new_entry->avail_ssize = 0;
8832267af78SJulian Elischer 
88430dcfc09SJohn Dyson 	new_entry->inheritance = VM_INHERIT_DEFAULT;
88530dcfc09SJohn Dyson 	new_entry->protection = prot;
88630dcfc09SJohn Dyson 	new_entry->max_protection = max;
88730dcfc09SJohn Dyson 	new_entry->wired_count = 0;
888e5f251d2SAlan Cox 
88930dcfc09SJohn Dyson 	/*
89030dcfc09SJohn Dyson 	 * Insert the new entry into the list
89130dcfc09SJohn Dyson 	 */
89230dcfc09SJohn Dyson 	vm_map_entry_link(map, prev_entry, new_entry);
89330dcfc09SJohn Dyson 	map->size += new_entry->end - new_entry->start;
89430dcfc09SJohn Dyson 
89530dcfc09SJohn Dyson 	/*
89630dcfc09SJohn Dyson 	 * Update the free space hint
89730dcfc09SJohn Dyson 	 */
89867bf6868SJohn Dyson 	if ((map->first_free == prev_entry) &&
8994f79d873SMatthew Dillon 	    (prev_entry->end >= new_entry->start)) {
90030dcfc09SJohn Dyson 		map->first_free = new_entry;
9014f79d873SMatthew Dillon 	}
90230dcfc09SJohn Dyson 
9031a484d28SMatthew Dillon #if 0
9041a484d28SMatthew Dillon 	/*
9051a484d28SMatthew Dillon 	 * Temporarily removed to avoid MAP_STACK panic, due to
9061a484d28SMatthew Dillon 	 * MAP_STACK being a huge hack.  Will be added back in
9071a484d28SMatthew Dillon 	 * when MAP_STACK (and the user stack mapping) is fixed.
9081a484d28SMatthew Dillon 	 */
9094e71e795SMatthew Dillon 	/*
9104e71e795SMatthew Dillon 	 * It may be possible to simplify the entry
9114e71e795SMatthew Dillon 	 */
9124e71e795SMatthew Dillon 	vm_map_simplify_entry(map, new_entry);
9131a484d28SMatthew Dillon #endif
9144e71e795SMatthew Dillon 
9154f79d873SMatthew Dillon 	if (cow & (MAP_PREFAULT|MAP_PREFAULT_PARTIAL)) {
91640974827SAlan Cox 		mtx_lock(&Giant);
917e972780aSAlan Cox 		pmap_object_init_pt(map->pmap, start,
918e972780aSAlan Cox 				    object, OFF_TO_IDX(offset), end - start,
919e972780aSAlan Cox 				    cow & MAP_PREFAULT_PARTIAL);
92040974827SAlan Cox 		mtx_unlock(&Giant);
9214f79d873SMatthew Dillon 	}
922e972780aSAlan Cox 
92330dcfc09SJohn Dyson 	return (KERN_SUCCESS);
92430dcfc09SJohn Dyson }
92530dcfc09SJohn Dyson 
92630dcfc09SJohn Dyson /*
927df8bae1dSRodney W. Grimes  * Find sufficient space for `length' bytes in the given map, starting at
928df8bae1dSRodney W. Grimes  * `start'.  The map must be locked.  Returns 0 on success, 1 on no space.
929df8bae1dSRodney W. Grimes  */
930df8bae1dSRodney W. Grimes int
9311b40f8c0SMatthew Dillon vm_map_findspace(
9321b40f8c0SMatthew Dillon 	vm_map_t map,
9331b40f8c0SMatthew Dillon 	vm_offset_t start,
9341b40f8c0SMatthew Dillon 	vm_size_t length,
9351b40f8c0SMatthew Dillon 	vm_offset_t *addr)
936df8bae1dSRodney W. Grimes {
937c0877f10SJohn Dyson 	vm_map_entry_t entry, next;
938c0877f10SJohn Dyson 	vm_offset_t end;
939df8bae1dSRodney W. Grimes 
940df8bae1dSRodney W. Grimes 	if (start < map->min_offset)
941df8bae1dSRodney W. Grimes 		start = map->min_offset;
942df8bae1dSRodney W. Grimes 	if (start > map->max_offset)
943df8bae1dSRodney W. Grimes 		return (1);
944df8bae1dSRodney W. Grimes 
945df8bae1dSRodney W. Grimes 	/*
9460d94caffSDavid Greenman 	 * Look for the first possible address; if there's already something
9470d94caffSDavid Greenman 	 * at this address, we have to start after it.
948df8bae1dSRodney W. Grimes 	 */
949df8bae1dSRodney W. Grimes 	if (start == map->min_offset) {
95067bf6868SJohn Dyson 		if ((entry = map->first_free) != &map->header)
951df8bae1dSRodney W. Grimes 			start = entry->end;
952df8bae1dSRodney W. Grimes 	} else {
953df8bae1dSRodney W. Grimes 		vm_map_entry_t tmp;
9540d94caffSDavid Greenman 
955df8bae1dSRodney W. Grimes 		if (vm_map_lookup_entry(map, start, &tmp))
956df8bae1dSRodney W. Grimes 			start = tmp->end;
957df8bae1dSRodney W. Grimes 		entry = tmp;
958df8bae1dSRodney W. Grimes 	}
959df8bae1dSRodney W. Grimes 
960df8bae1dSRodney W. Grimes 	/*
9610d94caffSDavid Greenman 	 * Look through the rest of the map, trying to fit a new region in the
9620d94caffSDavid Greenman 	 * gap between existing regions, or after the very last region.
963df8bae1dSRodney W. Grimes 	 */
964df8bae1dSRodney W. Grimes 	for (;; start = (entry = next)->end) {
965df8bae1dSRodney W. Grimes 		/*
966df8bae1dSRodney W. Grimes 		 * Find the end of the proposed new region.  Be sure we didn't
967df8bae1dSRodney W. Grimes 		 * go beyond the end of the map, or wrap around the address;
968df8bae1dSRodney W. Grimes 		 * if so, we lose.  Otherwise, if this is the last entry, or
969df8bae1dSRodney W. Grimes 		 * if the proposed new region fits before the next entry, we
970df8bae1dSRodney W. Grimes 		 * win.
971df8bae1dSRodney W. Grimes 		 */
972df8bae1dSRodney W. Grimes 		end = start + length;
973df8bae1dSRodney W. Grimes 		if (end > map->max_offset || end < start)
974df8bae1dSRodney W. Grimes 			return (1);
975df8bae1dSRodney W. Grimes 		next = entry->next;
976df8bae1dSRodney W. Grimes 		if (next == &map->header || next->start >= end)
977df8bae1dSRodney W. Grimes 			break;
978df8bae1dSRodney W. Grimes 	}
979df8bae1dSRodney W. Grimes 	*addr = start;
98099448ed1SJohn Dyson 	if (map == kernel_map) {
98199448ed1SJohn Dyson 		vm_offset_t ksize;
98299448ed1SJohn Dyson 		if ((ksize = round_page(start + length)) > kernel_vm_end) {
98399448ed1SJohn Dyson 			pmap_growkernel(ksize);
98499448ed1SJohn Dyson 		}
98599448ed1SJohn Dyson 	}
986df8bae1dSRodney W. Grimes 	return (0);
987df8bae1dSRodney W. Grimes }
988df8bae1dSRodney W. Grimes 
989df8bae1dSRodney W. Grimes /*
990df8bae1dSRodney W. Grimes  *	vm_map_find finds an unallocated region in the target address
991df8bae1dSRodney W. Grimes  *	map with the given length.  The search is defined to be
992df8bae1dSRodney W. Grimes  *	first-fit from the specified address; the region found is
993df8bae1dSRodney W. Grimes  *	returned in the same parameter.
994df8bae1dSRodney W. Grimes  *
9952aaeadf8SMatthew Dillon  *	If object is non-NULL, ref count must be bumped by caller
9962aaeadf8SMatthew Dillon  *	prior to making call to account for the new entry.
997df8bae1dSRodney W. Grimes  */
998df8bae1dSRodney W. Grimes int
999b9dcd593SBruce Evans vm_map_find(vm_map_t map, vm_object_t object, vm_ooffset_t offset,
1000b9dcd593SBruce Evans 	    vm_offset_t *addr,	/* IN/OUT */
1001b9dcd593SBruce Evans 	    vm_size_t length, boolean_t find_space, vm_prot_t prot,
1002b9dcd593SBruce Evans 	    vm_prot_t max, int cow)
1003df8bae1dSRodney W. Grimes {
1004c0877f10SJohn Dyson 	vm_offset_t start;
10058d6e8edeSDavid Greenman 	int result, s = 0;
1006df8bae1dSRodney W. Grimes 
1007df8bae1dSRodney W. Grimes 	start = *addr;
10088d6e8edeSDavid Greenman 
100908442f8aSBosko Milekic 	if (map == kmem_map)
1010b18bfc3dSJohn Dyson 		s = splvm();
10118d6e8edeSDavid Greenman 
1012bea41bcfSDavid Greenman 	vm_map_lock(map);
1013df8bae1dSRodney W. Grimes 	if (find_space) {
1014df8bae1dSRodney W. Grimes 		if (vm_map_findspace(map, start, length, addr)) {
1015df8bae1dSRodney W. Grimes 			vm_map_unlock(map);
101608442f8aSBosko Milekic 			if (map == kmem_map)
10178d6e8edeSDavid Greenman 				splx(s);
1018df8bae1dSRodney W. Grimes 			return (KERN_NO_SPACE);
1019df8bae1dSRodney W. Grimes 		}
1020df8bae1dSRodney W. Grimes 		start = *addr;
1021df8bae1dSRodney W. Grimes 	}
1022bd7e5f99SJohn Dyson 	result = vm_map_insert(map, object, offset,
1023bd7e5f99SJohn Dyson 		start, start + length, prot, max, cow);
1024df8bae1dSRodney W. Grimes 	vm_map_unlock(map);
10258d6e8edeSDavid Greenman 
102608442f8aSBosko Milekic 	if (map == kmem_map)
10278d6e8edeSDavid Greenman 		splx(s);
10288d6e8edeSDavid Greenman 
1029df8bae1dSRodney W. Grimes 	return (result);
1030df8bae1dSRodney W. Grimes }
1031df8bae1dSRodney W. Grimes 
1032df8bae1dSRodney W. Grimes /*
1033b7b2aac2SJohn Dyson  *	vm_map_simplify_entry:
103467bf6868SJohn Dyson  *
10354e71e795SMatthew Dillon  *	Simplify the given map entry by merging with either neighbor.  This
10364e71e795SMatthew Dillon  *	routine also has the ability to merge with both neighbors.
10374e71e795SMatthew Dillon  *
10384e71e795SMatthew Dillon  *	The map must be locked.
10394e71e795SMatthew Dillon  *
10404e71e795SMatthew Dillon  *	This routine guarentees that the passed entry remains valid (though
10414e71e795SMatthew Dillon  *	possibly extended).  When merging, this routine may delete one or
10424e71e795SMatthew Dillon  *	both neighbors.
1043df8bae1dSRodney W. Grimes  */
1044b7b2aac2SJohn Dyson void
10451b40f8c0SMatthew Dillon vm_map_simplify_entry(vm_map_t map, vm_map_entry_t entry)
1046df8bae1dSRodney W. Grimes {
1047308c24baSJohn Dyson 	vm_map_entry_t next, prev;
1048b7b2aac2SJohn Dyson 	vm_size_t prevsize, esize;
1049df8bae1dSRodney W. Grimes 
1050acd9a301SAlan Cox 	if (entry->eflags & (MAP_ENTRY_IN_TRANSITION | MAP_ENTRY_IS_SUB_MAP))
1051df8bae1dSRodney W. Grimes 		return;
1052308c24baSJohn Dyson 
1053308c24baSJohn Dyson 	prev = entry->prev;
1054308c24baSJohn Dyson 	if (prev != &map->header) {
105567bf6868SJohn Dyson 		prevsize = prev->end - prev->start;
105667bf6868SJohn Dyson 		if ( (prev->end == entry->start) &&
105767bf6868SJohn Dyson 		     (prev->object.vm_object == entry->object.vm_object) &&
105895e5e988SJohn Dyson 		     (!prev->object.vm_object ||
105967bf6868SJohn Dyson 			(prev->offset + prevsize == entry->offset)) &&
1060afa07f7eSJohn Dyson 		     (prev->eflags == entry->eflags) &&
106167bf6868SJohn Dyson 		     (prev->protection == entry->protection) &&
106267bf6868SJohn Dyson 		     (prev->max_protection == entry->max_protection) &&
106367bf6868SJohn Dyson 		     (prev->inheritance == entry->inheritance) &&
1064b7b2aac2SJohn Dyson 		     (prev->wired_count == entry->wired_count)) {
1065308c24baSJohn Dyson 			if (map->first_free == prev)
1066308c24baSJohn Dyson 				map->first_free = entry;
1067308c24baSJohn Dyson 			vm_map_entry_unlink(map, prev);
1068308c24baSJohn Dyson 			entry->start = prev->start;
1069308c24baSJohn Dyson 			entry->offset = prev->offset;
1070b18bfc3dSJohn Dyson 			if (prev->object.vm_object)
1071308c24baSJohn Dyson 				vm_object_deallocate(prev->object.vm_object);
1072308c24baSJohn Dyson 			vm_map_entry_dispose(map, prev);
1073308c24baSJohn Dyson 		}
1074308c24baSJohn Dyson 	}
1075de5f6a77SJohn Dyson 
1076de5f6a77SJohn Dyson 	next = entry->next;
1077308c24baSJohn Dyson 	if (next != &map->header) {
107867bf6868SJohn Dyson 		esize = entry->end - entry->start;
107967bf6868SJohn Dyson 		if ((entry->end == next->start) &&
108067bf6868SJohn Dyson 		    (next->object.vm_object == entry->object.vm_object) &&
108167bf6868SJohn Dyson 		     (!entry->object.vm_object ||
108267bf6868SJohn Dyson 			(entry->offset + esize == next->offset)) &&
1083afa07f7eSJohn Dyson 		    (next->eflags == entry->eflags) &&
108467bf6868SJohn Dyson 		    (next->protection == entry->protection) &&
108567bf6868SJohn Dyson 		    (next->max_protection == entry->max_protection) &&
108667bf6868SJohn Dyson 		    (next->inheritance == entry->inheritance) &&
1087b7b2aac2SJohn Dyson 		    (next->wired_count == entry->wired_count)) {
1088308c24baSJohn Dyson 			if (map->first_free == next)
1089308c24baSJohn Dyson 				map->first_free = entry;
1090de5f6a77SJohn Dyson 			vm_map_entry_unlink(map, next);
1091de5f6a77SJohn Dyson 			entry->end = next->end;
1092b18bfc3dSJohn Dyson 			if (next->object.vm_object)
1093de5f6a77SJohn Dyson 				vm_object_deallocate(next->object.vm_object);
1094de5f6a77SJohn Dyson 			vm_map_entry_dispose(map, next);
1095df8bae1dSRodney W. Grimes 	        }
1096df8bae1dSRodney W. Grimes 	}
1097de5f6a77SJohn Dyson }
1098df8bae1dSRodney W. Grimes /*
1099df8bae1dSRodney W. Grimes  *	vm_map_clip_start:	[ internal use only ]
1100df8bae1dSRodney W. Grimes  *
1101df8bae1dSRodney W. Grimes  *	Asserts that the given entry begins at or after
1102df8bae1dSRodney W. Grimes  *	the specified address; if necessary,
1103df8bae1dSRodney W. Grimes  *	it splits the entry into two.
1104df8bae1dSRodney W. Grimes  */
1105df8bae1dSRodney W. Grimes #define vm_map_clip_start(map, entry, startaddr) \
1106df8bae1dSRodney W. Grimes { \
1107df8bae1dSRodney W. Grimes 	if (startaddr > entry->start) \
1108df8bae1dSRodney W. Grimes 		_vm_map_clip_start(map, entry, startaddr); \
1109df8bae1dSRodney W. Grimes }
1110df8bae1dSRodney W. Grimes 
1111df8bae1dSRodney W. Grimes /*
1112df8bae1dSRodney W. Grimes  *	This routine is called only when it is known that
1113df8bae1dSRodney W. Grimes  *	the entry must be split.
1114df8bae1dSRodney W. Grimes  */
11150d94caffSDavid Greenman static void
11161b40f8c0SMatthew Dillon _vm_map_clip_start(vm_map_t map, vm_map_entry_t entry, vm_offset_t start)
1117df8bae1dSRodney W. Grimes {
1118c0877f10SJohn Dyson 	vm_map_entry_t new_entry;
1119df8bae1dSRodney W. Grimes 
1120df8bae1dSRodney W. Grimes 	/*
11210d94caffSDavid Greenman 	 * Split off the front portion -- note that we must insert the new
11220d94caffSDavid Greenman 	 * entry BEFORE this one, so that this entry has the specified
11230d94caffSDavid Greenman 	 * starting address.
1124df8bae1dSRodney W. Grimes 	 */
1125f32dbbeeSJohn Dyson 	vm_map_simplify_entry(map, entry);
1126f32dbbeeSJohn Dyson 
112711cccda1SJohn Dyson 	/*
112811cccda1SJohn Dyson 	 * If there is no object backing this entry, we might as well create
112911cccda1SJohn Dyson 	 * one now.  If we defer it, an object can get created after the map
113011cccda1SJohn Dyson 	 * is clipped, and individual objects will be created for the split-up
113111cccda1SJohn Dyson 	 * map.  This is a bit of a hack, but is also about the best place to
113211cccda1SJohn Dyson 	 * put this improvement.
113311cccda1SJohn Dyson 	 */
11344e71e795SMatthew Dillon 	if (entry->object.vm_object == NULL && !map->system_map) {
113511cccda1SJohn Dyson 		vm_object_t object;
113611cccda1SJohn Dyson 		object = vm_object_allocate(OBJT_DEFAULT,
1137c2e11a03SJohn Dyson 				atop(entry->end - entry->start));
113811cccda1SJohn Dyson 		entry->object.vm_object = object;
113911cccda1SJohn Dyson 		entry->offset = 0;
114011cccda1SJohn Dyson 	}
114111cccda1SJohn Dyson 
1142df8bae1dSRodney W. Grimes 	new_entry = vm_map_entry_create(map);
1143df8bae1dSRodney W. Grimes 	*new_entry = *entry;
1144df8bae1dSRodney W. Grimes 
1145df8bae1dSRodney W. Grimes 	new_entry->end = start;
1146df8bae1dSRodney W. Grimes 	entry->offset += (start - entry->start);
1147df8bae1dSRodney W. Grimes 	entry->start = start;
1148df8bae1dSRodney W. Grimes 
1149df8bae1dSRodney W. Grimes 	vm_map_entry_link(map, entry->prev, new_entry);
1150df8bae1dSRodney W. Grimes 
11519fdfe602SMatthew Dillon 	if ((entry->eflags & MAP_ENTRY_IS_SUB_MAP) == 0) {
1152df8bae1dSRodney W. Grimes 		vm_object_reference(new_entry->object.vm_object);
1153df8bae1dSRodney W. Grimes 	}
1154c0877f10SJohn Dyson }
1155df8bae1dSRodney W. Grimes 
1156df8bae1dSRodney W. Grimes /*
1157df8bae1dSRodney W. Grimes  *	vm_map_clip_end:	[ internal use only ]
1158df8bae1dSRodney W. Grimes  *
1159df8bae1dSRodney W. Grimes  *	Asserts that the given entry ends at or before
1160df8bae1dSRodney W. Grimes  *	the specified address; if necessary,
1161df8bae1dSRodney W. Grimes  *	it splits the entry into two.
1162df8bae1dSRodney W. Grimes  */
1163df8bae1dSRodney W. Grimes #define vm_map_clip_end(map, entry, endaddr) \
1164df8bae1dSRodney W. Grimes { \
1165af045176SPoul-Henning Kamp 	if ((endaddr) < (entry->end)) \
1166af045176SPoul-Henning Kamp 		_vm_map_clip_end((map), (entry), (endaddr)); \
1167df8bae1dSRodney W. Grimes }
1168df8bae1dSRodney W. Grimes 
1169df8bae1dSRodney W. Grimes /*
1170df8bae1dSRodney W. Grimes  *	This routine is called only when it is known that
1171df8bae1dSRodney W. Grimes  *	the entry must be split.
1172df8bae1dSRodney W. Grimes  */
11730d94caffSDavid Greenman static void
11741b40f8c0SMatthew Dillon _vm_map_clip_end(vm_map_t map, vm_map_entry_t entry, vm_offset_t end)
1175df8bae1dSRodney W. Grimes {
1176c0877f10SJohn Dyson 	vm_map_entry_t new_entry;
1177df8bae1dSRodney W. Grimes 
1178df8bae1dSRodney W. Grimes 	/*
117911cccda1SJohn Dyson 	 * If there is no object backing this entry, we might as well create
118011cccda1SJohn Dyson 	 * one now.  If we defer it, an object can get created after the map
118111cccda1SJohn Dyson 	 * is clipped, and individual objects will be created for the split-up
118211cccda1SJohn Dyson 	 * map.  This is a bit of a hack, but is also about the best place to
118311cccda1SJohn Dyson 	 * put this improvement.
118411cccda1SJohn Dyson 	 */
11854e71e795SMatthew Dillon 	if (entry->object.vm_object == NULL && !map->system_map) {
118611cccda1SJohn Dyson 		vm_object_t object;
118711cccda1SJohn Dyson 		object = vm_object_allocate(OBJT_DEFAULT,
1188c2e11a03SJohn Dyson 				atop(entry->end - entry->start));
118911cccda1SJohn Dyson 		entry->object.vm_object = object;
119011cccda1SJohn Dyson 		entry->offset = 0;
119111cccda1SJohn Dyson 	}
119211cccda1SJohn Dyson 
119311cccda1SJohn Dyson 	/*
11940d94caffSDavid Greenman 	 * Create a new entry and insert it AFTER the specified entry
1195df8bae1dSRodney W. Grimes 	 */
1196df8bae1dSRodney W. Grimes 	new_entry = vm_map_entry_create(map);
1197df8bae1dSRodney W. Grimes 	*new_entry = *entry;
1198df8bae1dSRodney W. Grimes 
1199df8bae1dSRodney W. Grimes 	new_entry->start = entry->end = end;
1200df8bae1dSRodney W. Grimes 	new_entry->offset += (end - entry->start);
1201df8bae1dSRodney W. Grimes 
1202df8bae1dSRodney W. Grimes 	vm_map_entry_link(map, entry, new_entry);
1203df8bae1dSRodney W. Grimes 
12049fdfe602SMatthew Dillon 	if ((entry->eflags & MAP_ENTRY_IS_SUB_MAP) == 0) {
1205df8bae1dSRodney W. Grimes 		vm_object_reference(new_entry->object.vm_object);
1206df8bae1dSRodney W. Grimes 	}
1207c0877f10SJohn Dyson }
1208df8bae1dSRodney W. Grimes 
1209df8bae1dSRodney W. Grimes /*
1210df8bae1dSRodney W. Grimes  *	VM_MAP_RANGE_CHECK:	[ internal use only ]
1211df8bae1dSRodney W. Grimes  *
1212df8bae1dSRodney W. Grimes  *	Asserts that the starting and ending region
1213df8bae1dSRodney W. Grimes  *	addresses fall within the valid range of the map.
1214df8bae1dSRodney W. Grimes  */
1215df8bae1dSRodney W. Grimes #define	VM_MAP_RANGE_CHECK(map, start, end)		\
1216df8bae1dSRodney W. Grimes 		{					\
1217df8bae1dSRodney W. Grimes 		if (start < vm_map_min(map))		\
1218df8bae1dSRodney W. Grimes 			start = vm_map_min(map);	\
1219df8bae1dSRodney W. Grimes 		if (end > vm_map_max(map))		\
1220df8bae1dSRodney W. Grimes 			end = vm_map_max(map);		\
1221df8bae1dSRodney W. Grimes 		if (start > end)			\
1222df8bae1dSRodney W. Grimes 			start = end;			\
1223df8bae1dSRodney W. Grimes 		}
1224df8bae1dSRodney W. Grimes 
1225df8bae1dSRodney W. Grimes /*
1226df8bae1dSRodney W. Grimes  *	vm_map_submap:		[ kernel use only ]
1227df8bae1dSRodney W. Grimes  *
1228df8bae1dSRodney W. Grimes  *	Mark the given range as handled by a subordinate map.
1229df8bae1dSRodney W. Grimes  *
1230df8bae1dSRodney W. Grimes  *	This range must have been created with vm_map_find,
1231df8bae1dSRodney W. Grimes  *	and no other operations may have been performed on this
1232df8bae1dSRodney W. Grimes  *	range prior to calling vm_map_submap.
1233df8bae1dSRodney W. Grimes  *
1234df8bae1dSRodney W. Grimes  *	Only a limited number of operations can be performed
1235df8bae1dSRodney W. Grimes  *	within this rage after calling vm_map_submap:
1236df8bae1dSRodney W. Grimes  *		vm_fault
1237df8bae1dSRodney W. Grimes  *	[Don't try vm_map_copy!]
1238df8bae1dSRodney W. Grimes  *
1239df8bae1dSRodney W. Grimes  *	To remove a submapping, one must first remove the
1240df8bae1dSRodney W. Grimes  *	range from the superior map, and then destroy the
1241df8bae1dSRodney W. Grimes  *	submap (if desired).  [Better yet, don't try it.]
1242df8bae1dSRodney W. Grimes  */
1243df8bae1dSRodney W. Grimes int
12441b40f8c0SMatthew Dillon vm_map_submap(
12451b40f8c0SMatthew Dillon 	vm_map_t map,
12461b40f8c0SMatthew Dillon 	vm_offset_t start,
12471b40f8c0SMatthew Dillon 	vm_offset_t end,
12481b40f8c0SMatthew Dillon 	vm_map_t submap)
1249df8bae1dSRodney W. Grimes {
1250df8bae1dSRodney W. Grimes 	vm_map_entry_t entry;
1251c0877f10SJohn Dyson 	int result = KERN_INVALID_ARGUMENT;
1252df8bae1dSRodney W. Grimes 
1253df8bae1dSRodney W. Grimes 	vm_map_lock(map);
1254df8bae1dSRodney W. Grimes 
1255df8bae1dSRodney W. Grimes 	VM_MAP_RANGE_CHECK(map, start, end);
1256df8bae1dSRodney W. Grimes 
1257df8bae1dSRodney W. Grimes 	if (vm_map_lookup_entry(map, start, &entry)) {
1258df8bae1dSRodney W. Grimes 		vm_map_clip_start(map, entry, start);
12590d94caffSDavid Greenman 	} else
1260df8bae1dSRodney W. Grimes 		entry = entry->next;
1261df8bae1dSRodney W. Grimes 
1262df8bae1dSRodney W. Grimes 	vm_map_clip_end(map, entry, end);
1263df8bae1dSRodney W. Grimes 
1264df8bae1dSRodney W. Grimes 	if ((entry->start == start) && (entry->end == end) &&
12659fdfe602SMatthew Dillon 	    ((entry->eflags & MAP_ENTRY_COW) == 0) &&
1266afa07f7eSJohn Dyson 	    (entry->object.vm_object == NULL)) {
12672d8acc0fSJohn Dyson 		entry->object.sub_map = submap;
1268afa07f7eSJohn Dyson 		entry->eflags |= MAP_ENTRY_IS_SUB_MAP;
1269df8bae1dSRodney W. Grimes 		result = KERN_SUCCESS;
1270df8bae1dSRodney W. Grimes 	}
1271df8bae1dSRodney W. Grimes 	vm_map_unlock(map);
1272df8bae1dSRodney W. Grimes 
1273df8bae1dSRodney W. Grimes 	return (result);
1274df8bae1dSRodney W. Grimes }
1275df8bae1dSRodney W. Grimes 
1276df8bae1dSRodney W. Grimes /*
1277df8bae1dSRodney W. Grimes  *	vm_map_protect:
1278df8bae1dSRodney W. Grimes  *
1279df8bae1dSRodney W. Grimes  *	Sets the protection of the specified address
1280df8bae1dSRodney W. Grimes  *	region in the target map.  If "set_max" is
1281df8bae1dSRodney W. Grimes  *	specified, the maximum protection is to be set;
1282df8bae1dSRodney W. Grimes  *	otherwise, only the current protection is affected.
1283df8bae1dSRodney W. Grimes  */
1284df8bae1dSRodney W. Grimes int
1285b9dcd593SBruce Evans vm_map_protect(vm_map_t map, vm_offset_t start, vm_offset_t end,
1286b9dcd593SBruce Evans 	       vm_prot_t new_prot, boolean_t set_max)
1287df8bae1dSRodney W. Grimes {
1288c0877f10SJohn Dyson 	vm_map_entry_t current;
1289df8bae1dSRodney W. Grimes 	vm_map_entry_t entry;
1290df8bae1dSRodney W. Grimes 
1291df8bae1dSRodney W. Grimes 	vm_map_lock(map);
1292df8bae1dSRodney W. Grimes 
1293df8bae1dSRodney W. Grimes 	VM_MAP_RANGE_CHECK(map, start, end);
1294df8bae1dSRodney W. Grimes 
1295df8bae1dSRodney W. Grimes 	if (vm_map_lookup_entry(map, start, &entry)) {
1296df8bae1dSRodney W. Grimes 		vm_map_clip_start(map, entry, start);
1297b7b2aac2SJohn Dyson 	} else {
1298df8bae1dSRodney W. Grimes 		entry = entry->next;
1299b7b2aac2SJohn Dyson 	}
1300df8bae1dSRodney W. Grimes 
1301df8bae1dSRodney W. Grimes 	/*
13020d94caffSDavid Greenman 	 * Make a first pass to check for protection violations.
1303df8bae1dSRodney W. Grimes 	 */
1304df8bae1dSRodney W. Grimes 	current = entry;
1305df8bae1dSRodney W. Grimes 	while ((current != &map->header) && (current->start < end)) {
1306afa07f7eSJohn Dyson 		if (current->eflags & MAP_ENTRY_IS_SUB_MAP) {
1307a1f6d91cSDavid Greenman 			vm_map_unlock(map);
1308df8bae1dSRodney W. Grimes 			return (KERN_INVALID_ARGUMENT);
1309a1f6d91cSDavid Greenman 		}
1310df8bae1dSRodney W. Grimes 		if ((new_prot & current->max_protection) != new_prot) {
1311df8bae1dSRodney W. Grimes 			vm_map_unlock(map);
1312df8bae1dSRodney W. Grimes 			return (KERN_PROTECTION_FAILURE);
1313df8bae1dSRodney W. Grimes 		}
1314df8bae1dSRodney W. Grimes 		current = current->next;
1315df8bae1dSRodney W. Grimes 	}
1316df8bae1dSRodney W. Grimes 
1317df8bae1dSRodney W. Grimes 	/*
13180d94caffSDavid Greenman 	 * Go back and fix up protections. [Note that clipping is not
13190d94caffSDavid Greenman 	 * necessary the second time.]
1320df8bae1dSRodney W. Grimes 	 */
1321df8bae1dSRodney W. Grimes 	current = entry;
1322df8bae1dSRodney W. Grimes 	while ((current != &map->header) && (current->start < end)) {
1323df8bae1dSRodney W. Grimes 		vm_prot_t old_prot;
1324df8bae1dSRodney W. Grimes 
1325df8bae1dSRodney W. Grimes 		vm_map_clip_end(map, current, end);
1326df8bae1dSRodney W. Grimes 
1327df8bae1dSRodney W. Grimes 		old_prot = current->protection;
1328df8bae1dSRodney W. Grimes 		if (set_max)
1329df8bae1dSRodney W. Grimes 			current->protection =
1330df8bae1dSRodney W. Grimes 			    (current->max_protection = new_prot) &
1331df8bae1dSRodney W. Grimes 			    old_prot;
1332df8bae1dSRodney W. Grimes 		else
1333df8bae1dSRodney W. Grimes 			current->protection = new_prot;
1334df8bae1dSRodney W. Grimes 
1335df8bae1dSRodney W. Grimes 		/*
13360d94caffSDavid Greenman 		 * Update physical map if necessary. Worry about copy-on-write
13370d94caffSDavid Greenman 		 * here -- CHECK THIS XXX
1338df8bae1dSRodney W. Grimes 		 */
1339df8bae1dSRodney W. Grimes 		if (current->protection != old_prot) {
134047c3ccc4SAlan Cox 			mtx_lock(&Giant);
134185e03a7eSAlan Cox 			vm_page_lock_queues();
1342afa07f7eSJohn Dyson #define MASK(entry)	(((entry)->eflags & MAP_ENTRY_COW) ? ~VM_PROT_WRITE : \
1343df8bae1dSRodney W. Grimes 							VM_PROT_ALL)
1344df8bae1dSRodney W. Grimes 			pmap_protect(map->pmap, current->start,
1345df8bae1dSRodney W. Grimes 			    current->end,
13461c85e3dfSAlan Cox 			    current->protection & MASK(current));
1347df8bae1dSRodney W. Grimes #undef	MASK
134885e03a7eSAlan Cox 			vm_page_unlock_queues();
134947c3ccc4SAlan Cox 			mtx_unlock(&Giant);
1350df8bae1dSRodney W. Grimes 		}
13517d78abc9SJohn Dyson 		vm_map_simplify_entry(map, current);
1352df8bae1dSRodney W. Grimes 		current = current->next;
1353df8bae1dSRodney W. Grimes 	}
1354df8bae1dSRodney W. Grimes 	vm_map_unlock(map);
1355df8bae1dSRodney W. Grimes 	return (KERN_SUCCESS);
1356df8bae1dSRodney W. Grimes }
1357df8bae1dSRodney W. Grimes 
1358df8bae1dSRodney W. Grimes /*
1359867a482dSJohn Dyson  *	vm_map_madvise:
1360867a482dSJohn Dyson  *
1361867a482dSJohn Dyson  * 	This routine traverses a processes map handling the madvise
1362f7fc307aSAlan Cox  *	system call.  Advisories are classified as either those effecting
1363f7fc307aSAlan Cox  *	the vm_map_entry structure, or those effecting the underlying
1364f7fc307aSAlan Cox  *	objects.
1365867a482dSJohn Dyson  */
1366b4309055SMatthew Dillon int
13671b40f8c0SMatthew Dillon vm_map_madvise(
13681b40f8c0SMatthew Dillon 	vm_map_t map,
13691b40f8c0SMatthew Dillon 	vm_offset_t start,
13701b40f8c0SMatthew Dillon 	vm_offset_t end,
13711b40f8c0SMatthew Dillon 	int behav)
1372867a482dSJohn Dyson {
1373f7fc307aSAlan Cox 	vm_map_entry_t current, entry;
1374b4309055SMatthew Dillon 	int modify_map = 0;
1375867a482dSJohn Dyson 
1376b4309055SMatthew Dillon 	/*
1377b4309055SMatthew Dillon 	 * Some madvise calls directly modify the vm_map_entry, in which case
1378b4309055SMatthew Dillon 	 * we need to use an exclusive lock on the map and we need to perform
1379b4309055SMatthew Dillon 	 * various clipping operations.  Otherwise we only need a read-lock
1380b4309055SMatthew Dillon 	 * on the map.
1381b4309055SMatthew Dillon 	 */
1382b4309055SMatthew Dillon 	switch(behav) {
1383b4309055SMatthew Dillon 	case MADV_NORMAL:
1384b4309055SMatthew Dillon 	case MADV_SEQUENTIAL:
1385b4309055SMatthew Dillon 	case MADV_RANDOM:
13864f79d873SMatthew Dillon 	case MADV_NOSYNC:
13874f79d873SMatthew Dillon 	case MADV_AUTOSYNC:
13889730a5daSPaul Saab 	case MADV_NOCORE:
13899730a5daSPaul Saab 	case MADV_CORE:
1390b4309055SMatthew Dillon 		modify_map = 1;
1391867a482dSJohn Dyson 		vm_map_lock(map);
1392b4309055SMatthew Dillon 		break;
1393b4309055SMatthew Dillon 	case MADV_WILLNEED:
1394b4309055SMatthew Dillon 	case MADV_DONTNEED:
1395b4309055SMatthew Dillon 	case MADV_FREE:
1396f7fc307aSAlan Cox 		vm_map_lock_read(map);
1397b4309055SMatthew Dillon 		break;
1398b4309055SMatthew Dillon 	default:
1399b4309055SMatthew Dillon 		return (KERN_INVALID_ARGUMENT);
1400b4309055SMatthew Dillon 	}
1401b4309055SMatthew Dillon 
1402b4309055SMatthew Dillon 	/*
1403b4309055SMatthew Dillon 	 * Locate starting entry and clip if necessary.
1404b4309055SMatthew Dillon 	 */
1405867a482dSJohn Dyson 	VM_MAP_RANGE_CHECK(map, start, end);
1406867a482dSJohn Dyson 
1407867a482dSJohn Dyson 	if (vm_map_lookup_entry(map, start, &entry)) {
1408f7fc307aSAlan Cox 		if (modify_map)
1409867a482dSJohn Dyson 			vm_map_clip_start(map, entry, start);
1410b4309055SMatthew Dillon 	} else {
1411867a482dSJohn Dyson 		entry = entry->next;
1412b4309055SMatthew Dillon 	}
1413867a482dSJohn Dyson 
1414f7fc307aSAlan Cox 	if (modify_map) {
1415f7fc307aSAlan Cox 		/*
1416f7fc307aSAlan Cox 		 * madvise behaviors that are implemented in the vm_map_entry.
1417f7fc307aSAlan Cox 		 *
1418f7fc307aSAlan Cox 		 * We clip the vm_map_entry so that behavioral changes are
1419f7fc307aSAlan Cox 		 * limited to the specified address range.
1420f7fc307aSAlan Cox 		 */
1421867a482dSJohn Dyson 		for (current = entry;
1422867a482dSJohn Dyson 		     (current != &map->header) && (current->start < end);
1423b4309055SMatthew Dillon 		     current = current->next
1424b4309055SMatthew Dillon 		) {
1425f7fc307aSAlan Cox 			if (current->eflags & MAP_ENTRY_IS_SUB_MAP)
1426867a482dSJohn Dyson 				continue;
1427fed9a903SJohn Dyson 
142847221757SJohn Dyson 			vm_map_clip_end(map, current, end);
1429fed9a903SJohn Dyson 
1430f7fc307aSAlan Cox 			switch (behav) {
1431867a482dSJohn Dyson 			case MADV_NORMAL:
14327f866e4bSAlan Cox 				vm_map_entry_set_behavior(current, MAP_ENTRY_BEHAV_NORMAL);
1433867a482dSJohn Dyson 				break;
1434867a482dSJohn Dyson 			case MADV_SEQUENTIAL:
14357f866e4bSAlan Cox 				vm_map_entry_set_behavior(current, MAP_ENTRY_BEHAV_SEQUENTIAL);
1436867a482dSJohn Dyson 				break;
1437867a482dSJohn Dyson 			case MADV_RANDOM:
14387f866e4bSAlan Cox 				vm_map_entry_set_behavior(current, MAP_ENTRY_BEHAV_RANDOM);
1439867a482dSJohn Dyson 				break;
14404f79d873SMatthew Dillon 			case MADV_NOSYNC:
14414f79d873SMatthew Dillon 				current->eflags |= MAP_ENTRY_NOSYNC;
14424f79d873SMatthew Dillon 				break;
14434f79d873SMatthew Dillon 			case MADV_AUTOSYNC:
14444f79d873SMatthew Dillon 				current->eflags &= ~MAP_ENTRY_NOSYNC;
14454f79d873SMatthew Dillon 				break;
14469730a5daSPaul Saab 			case MADV_NOCORE:
14479730a5daSPaul Saab 				current->eflags |= MAP_ENTRY_NOCOREDUMP;
14489730a5daSPaul Saab 				break;
14499730a5daSPaul Saab 			case MADV_CORE:
14509730a5daSPaul Saab 				current->eflags &= ~MAP_ENTRY_NOCOREDUMP;
14519730a5daSPaul Saab 				break;
1452867a482dSJohn Dyson 			default:
1453867a482dSJohn Dyson 				break;
1454867a482dSJohn Dyson 			}
1455f7fc307aSAlan Cox 			vm_map_simplify_entry(map, current);
1456867a482dSJohn Dyson 		}
1457867a482dSJohn Dyson 		vm_map_unlock(map);
1458b4309055SMatthew Dillon 	} else {
1459f7fc307aSAlan Cox 		vm_pindex_t pindex;
1460f7fc307aSAlan Cox 		int count;
1461f7fc307aSAlan Cox 
1462f7fc307aSAlan Cox 		/*
1463f7fc307aSAlan Cox 		 * madvise behaviors that are implemented in the underlying
1464f7fc307aSAlan Cox 		 * vm_object.
1465f7fc307aSAlan Cox 		 *
1466f7fc307aSAlan Cox 		 * Since we don't clip the vm_map_entry, we have to clip
1467f7fc307aSAlan Cox 		 * the vm_object pindex and count.
1468f7fc307aSAlan Cox 		 */
1469f7fc307aSAlan Cox 		for (current = entry;
1470f7fc307aSAlan Cox 		     (current != &map->header) && (current->start < end);
1471b4309055SMatthew Dillon 		     current = current->next
1472b4309055SMatthew Dillon 		) {
14735f99b57cSMatthew Dillon 			vm_offset_t useStart;
14745f99b57cSMatthew Dillon 
1475f7fc307aSAlan Cox 			if (current->eflags & MAP_ENTRY_IS_SUB_MAP)
1476f7fc307aSAlan Cox 				continue;
1477f7fc307aSAlan Cox 
1478f7fc307aSAlan Cox 			pindex = OFF_TO_IDX(current->offset);
1479f7fc307aSAlan Cox 			count = atop(current->end - current->start);
14805f99b57cSMatthew Dillon 			useStart = current->start;
1481f7fc307aSAlan Cox 
1482f7fc307aSAlan Cox 			if (current->start < start) {
1483f7fc307aSAlan Cox 				pindex += atop(start - current->start);
1484f7fc307aSAlan Cox 				count -= atop(start - current->start);
14855f99b57cSMatthew Dillon 				useStart = start;
1486f7fc307aSAlan Cox 			}
1487f7fc307aSAlan Cox 			if (current->end > end)
1488f7fc307aSAlan Cox 				count -= atop(current->end - end);
1489f7fc307aSAlan Cox 
1490f7fc307aSAlan Cox 			if (count <= 0)
1491f7fc307aSAlan Cox 				continue;
1492f7fc307aSAlan Cox 
1493f7fc307aSAlan Cox 			vm_object_madvise(current->object.vm_object,
1494f7fc307aSAlan Cox 					  pindex, count, behav);
1495b4309055SMatthew Dillon 			if (behav == MADV_WILLNEED) {
1496094f6d26SAlan Cox 				mtx_lock(&Giant);
1497b4309055SMatthew Dillon 				pmap_object_init_pt(
1498b4309055SMatthew Dillon 				    map->pmap,
14995f99b57cSMatthew Dillon 				    useStart,
1500f7fc307aSAlan Cox 				    current->object.vm_object,
1501b4309055SMatthew Dillon 				    pindex,
1502b4309055SMatthew Dillon 				    (count << PAGE_SHIFT),
1503e3026983SMatthew Dillon 				    MAP_PREFAULT_MADVISE
1504b4309055SMatthew Dillon 				);
1505094f6d26SAlan Cox 				mtx_unlock(&Giant);
1506f7fc307aSAlan Cox 			}
1507f7fc307aSAlan Cox 		}
1508f7fc307aSAlan Cox 		vm_map_unlock_read(map);
1509f7fc307aSAlan Cox 	}
1510b4309055SMatthew Dillon 	return (0);
1511867a482dSJohn Dyson }
1512867a482dSJohn Dyson 
1513867a482dSJohn Dyson 
1514867a482dSJohn Dyson /*
1515df8bae1dSRodney W. Grimes  *	vm_map_inherit:
1516df8bae1dSRodney W. Grimes  *
1517df8bae1dSRodney W. Grimes  *	Sets the inheritance of the specified address
1518df8bae1dSRodney W. Grimes  *	range in the target map.  Inheritance
1519df8bae1dSRodney W. Grimes  *	affects how the map will be shared with
1520df8bae1dSRodney W. Grimes  *	child maps at the time of vm_map_fork.
1521df8bae1dSRodney W. Grimes  */
1522df8bae1dSRodney W. Grimes int
1523b9dcd593SBruce Evans vm_map_inherit(vm_map_t map, vm_offset_t start, vm_offset_t end,
1524b9dcd593SBruce Evans 	       vm_inherit_t new_inheritance)
1525df8bae1dSRodney W. Grimes {
1526c0877f10SJohn Dyson 	vm_map_entry_t entry;
1527df8bae1dSRodney W. Grimes 	vm_map_entry_t temp_entry;
1528df8bae1dSRodney W. Grimes 
1529df8bae1dSRodney W. Grimes 	switch (new_inheritance) {
1530df8bae1dSRodney W. Grimes 	case VM_INHERIT_NONE:
1531df8bae1dSRodney W. Grimes 	case VM_INHERIT_COPY:
1532df8bae1dSRodney W. Grimes 	case VM_INHERIT_SHARE:
1533df8bae1dSRodney W. Grimes 		break;
1534df8bae1dSRodney W. Grimes 	default:
1535df8bae1dSRodney W. Grimes 		return (KERN_INVALID_ARGUMENT);
1536df8bae1dSRodney W. Grimes 	}
1537df8bae1dSRodney W. Grimes 	vm_map_lock(map);
1538df8bae1dSRodney W. Grimes 	VM_MAP_RANGE_CHECK(map, start, end);
1539df8bae1dSRodney W. Grimes 	if (vm_map_lookup_entry(map, start, &temp_entry)) {
1540df8bae1dSRodney W. Grimes 		entry = temp_entry;
1541df8bae1dSRodney W. Grimes 		vm_map_clip_start(map, entry, start);
15420d94caffSDavid Greenman 	} else
1543df8bae1dSRodney W. Grimes 		entry = temp_entry->next;
1544df8bae1dSRodney W. Grimes 	while ((entry != &map->header) && (entry->start < end)) {
1545df8bae1dSRodney W. Grimes 		vm_map_clip_end(map, entry, end);
1546df8bae1dSRodney W. Grimes 		entry->inheritance = new_inheritance;
154744428f62SAlan Cox 		vm_map_simplify_entry(map, entry);
1548df8bae1dSRodney W. Grimes 		entry = entry->next;
1549df8bae1dSRodney W. Grimes 	}
1550df8bae1dSRodney W. Grimes 	vm_map_unlock(map);
1551df8bae1dSRodney W. Grimes 	return (KERN_SUCCESS);
1552df8bae1dSRodney W. Grimes }
1553df8bae1dSRodney W. Grimes 
1554df8bae1dSRodney W. Grimes /*
1555acd9a301SAlan Cox  *	vm_map_unwire:
1556acd9a301SAlan Cox  *
1557e27e17b7SAlan Cox  *	Implements both kernel and user unwiring.
1558acd9a301SAlan Cox  */
1559acd9a301SAlan Cox int
1560acd9a301SAlan Cox vm_map_unwire(vm_map_t map, vm_offset_t start, vm_offset_t end,
1561acd9a301SAlan Cox 	boolean_t user_unwire)
1562acd9a301SAlan Cox {
1563acd9a301SAlan Cox 	vm_map_entry_t entry, first_entry, tmp_entry;
1564acd9a301SAlan Cox 	vm_offset_t saved_start;
1565acd9a301SAlan Cox 	unsigned int last_timestamp;
1566acd9a301SAlan Cox 	int rv;
1567acd9a301SAlan Cox 	boolean_t need_wakeup, result;
1568acd9a301SAlan Cox 
1569acd9a301SAlan Cox 	vm_map_lock(map);
1570acd9a301SAlan Cox 	VM_MAP_RANGE_CHECK(map, start, end);
1571acd9a301SAlan Cox 	if (!vm_map_lookup_entry(map, start, &first_entry)) {
1572acd9a301SAlan Cox 		vm_map_unlock(map);
1573acd9a301SAlan Cox 		return (KERN_INVALID_ADDRESS);
1574acd9a301SAlan Cox 	}
1575acd9a301SAlan Cox 	last_timestamp = map->timestamp;
1576acd9a301SAlan Cox 	entry = first_entry;
1577acd9a301SAlan Cox 	while (entry != &map->header && entry->start < end) {
1578acd9a301SAlan Cox 		if (entry->eflags & MAP_ENTRY_IN_TRANSITION) {
1579acd9a301SAlan Cox 			/*
1580acd9a301SAlan Cox 			 * We have not yet clipped the entry.
1581acd9a301SAlan Cox 			 */
1582acd9a301SAlan Cox 			saved_start = (start >= entry->start) ? start :
1583acd9a301SAlan Cox 			    entry->start;
1584acd9a301SAlan Cox 			entry->eflags |= MAP_ENTRY_NEEDS_WAKEUP;
1585acd9a301SAlan Cox 			if (vm_map_unlock_and_wait(map, user_unwire)) {
1586acd9a301SAlan Cox 				/*
1587acd9a301SAlan Cox 				 * Allow interruption of user unwiring?
1588acd9a301SAlan Cox 				 */
1589acd9a301SAlan Cox 			}
1590acd9a301SAlan Cox 			vm_map_lock(map);
1591acd9a301SAlan Cox 			if (last_timestamp+1 != map->timestamp) {
1592acd9a301SAlan Cox 				/*
1593acd9a301SAlan Cox 				 * Look again for the entry because the map was
1594acd9a301SAlan Cox 				 * modified while it was unlocked.
1595acd9a301SAlan Cox 				 * Specifically, the entry may have been
1596acd9a301SAlan Cox 				 * clipped, merged, or deleted.
1597acd9a301SAlan Cox 				 */
1598acd9a301SAlan Cox 				if (!vm_map_lookup_entry(map, saved_start,
1599acd9a301SAlan Cox 				    &tmp_entry)) {
1600acd9a301SAlan Cox 					if (saved_start == start) {
1601acd9a301SAlan Cox 						/*
1602acd9a301SAlan Cox 						 * First_entry has been deleted.
1603acd9a301SAlan Cox 						 */
1604acd9a301SAlan Cox 						vm_map_unlock(map);
1605acd9a301SAlan Cox 						return (KERN_INVALID_ADDRESS);
1606acd9a301SAlan Cox 					}
1607acd9a301SAlan Cox 					end = saved_start;
1608acd9a301SAlan Cox 					rv = KERN_INVALID_ADDRESS;
1609acd9a301SAlan Cox 					goto done;
1610acd9a301SAlan Cox 				}
1611acd9a301SAlan Cox 				if (entry == first_entry)
1612acd9a301SAlan Cox 					first_entry = tmp_entry;
1613acd9a301SAlan Cox 				else
1614acd9a301SAlan Cox 					first_entry = NULL;
1615acd9a301SAlan Cox 				entry = tmp_entry;
1616acd9a301SAlan Cox 			}
1617acd9a301SAlan Cox 			last_timestamp = map->timestamp;
1618acd9a301SAlan Cox 			continue;
1619acd9a301SAlan Cox 		}
1620acd9a301SAlan Cox 		vm_map_clip_start(map, entry, start);
1621acd9a301SAlan Cox 		vm_map_clip_end(map, entry, end);
1622acd9a301SAlan Cox 		/*
1623acd9a301SAlan Cox 		 * Mark the entry in case the map lock is released.  (See
1624acd9a301SAlan Cox 		 * above.)
1625acd9a301SAlan Cox 		 */
1626acd9a301SAlan Cox 		entry->eflags |= MAP_ENTRY_IN_TRANSITION;
1627acd9a301SAlan Cox 		/*
1628acd9a301SAlan Cox 		 * Check the map for holes in the specified region.
1629acd9a301SAlan Cox 		 */
1630acd9a301SAlan Cox 		if (entry->end < end && (entry->next == &map->header ||
1631acd9a301SAlan Cox 		    entry->next->start > entry->end)) {
1632acd9a301SAlan Cox 			end = entry->end;
1633acd9a301SAlan Cox 			rv = KERN_INVALID_ADDRESS;
1634acd9a301SAlan Cox 			goto done;
1635acd9a301SAlan Cox 		}
1636acd9a301SAlan Cox 		/*
1637acd9a301SAlan Cox 		 * Require that the entry is wired.
1638acd9a301SAlan Cox 		 */
1639acd9a301SAlan Cox 		if (entry->wired_count == 0 || (user_unwire &&
1640acd9a301SAlan Cox 		    (entry->eflags & MAP_ENTRY_USER_WIRED) == 0)) {
1641acd9a301SAlan Cox 			end = entry->end;
1642acd9a301SAlan Cox 			rv = KERN_INVALID_ARGUMENT;
1643acd9a301SAlan Cox 			goto done;
1644acd9a301SAlan Cox 		}
1645acd9a301SAlan Cox 		entry = entry->next;
1646acd9a301SAlan Cox 	}
1647acd9a301SAlan Cox 	rv = KERN_SUCCESS;
1648acd9a301SAlan Cox done:
1649e27e17b7SAlan Cox 	need_wakeup = FALSE;
1650acd9a301SAlan Cox 	if (first_entry == NULL) {
1651acd9a301SAlan Cox 		result = vm_map_lookup_entry(map, start, &first_entry);
1652acd9a301SAlan Cox 		KASSERT(result, ("vm_map_unwire: lookup failed"));
1653acd9a301SAlan Cox 	}
1654acd9a301SAlan Cox 	entry = first_entry;
1655acd9a301SAlan Cox 	while (entry != &map->header && entry->start < end) {
1656b2f3846aSAlan Cox 		if (rv == KERN_SUCCESS) {
1657b2f3846aSAlan Cox 			if (user_unwire)
1658b2f3846aSAlan Cox 				entry->eflags &= ~MAP_ENTRY_USER_WIRED;
1659b2f3846aSAlan Cox 			entry->wired_count--;
1660b2f3846aSAlan Cox 			if (entry->wired_count == 0) {
1661b2f3846aSAlan Cox 				/*
1662b2f3846aSAlan Cox 				 * Retain the map lock.
1663b2f3846aSAlan Cox 				 */
1664b2f3846aSAlan Cox 				vm_fault_unwire(map, entry->start, entry->end);
1665b2f3846aSAlan Cox 			}
1666b2f3846aSAlan Cox 		}
1667acd9a301SAlan Cox 		KASSERT(entry->eflags & MAP_ENTRY_IN_TRANSITION,
1668acd9a301SAlan Cox 			("vm_map_unwire: in-transition flag missing"));
1669acd9a301SAlan Cox 		entry->eflags &= ~MAP_ENTRY_IN_TRANSITION;
1670acd9a301SAlan Cox 		if (entry->eflags & MAP_ENTRY_NEEDS_WAKEUP) {
1671acd9a301SAlan Cox 			entry->eflags &= ~MAP_ENTRY_NEEDS_WAKEUP;
1672acd9a301SAlan Cox 			need_wakeup = TRUE;
1673acd9a301SAlan Cox 		}
1674acd9a301SAlan Cox 		vm_map_simplify_entry(map, entry);
1675acd9a301SAlan Cox 		entry = entry->next;
1676acd9a301SAlan Cox 	}
1677acd9a301SAlan Cox 	vm_map_unlock(map);
1678acd9a301SAlan Cox 	if (need_wakeup)
1679acd9a301SAlan Cox 		vm_map_wakeup(map);
1680acd9a301SAlan Cox 	return (rv);
1681acd9a301SAlan Cox }
1682acd9a301SAlan Cox 
1683acd9a301SAlan Cox /*
1684e27e17b7SAlan Cox  *	vm_map_wire:
1685e27e17b7SAlan Cox  *
1686e27e17b7SAlan Cox  *	Implements both kernel and user wiring.
1687e27e17b7SAlan Cox  */
1688e27e17b7SAlan Cox int
1689e27e17b7SAlan Cox vm_map_wire(vm_map_t map, vm_offset_t start, vm_offset_t end,
1690e27e17b7SAlan Cox 	boolean_t user_wire)
1691e27e17b7SAlan Cox {
169212d7cc84SAlan Cox 	vm_map_entry_t entry, first_entry, tmp_entry;
169312d7cc84SAlan Cox 	vm_offset_t saved_end, saved_start;
169412d7cc84SAlan Cox 	unsigned int last_timestamp;
169512d7cc84SAlan Cox 	int rv;
169612d7cc84SAlan Cox 	boolean_t need_wakeup, result;
1697e27e17b7SAlan Cox 
169812d7cc84SAlan Cox 	vm_map_lock(map);
169912d7cc84SAlan Cox 	VM_MAP_RANGE_CHECK(map, start, end);
170012d7cc84SAlan Cox 	if (!vm_map_lookup_entry(map, start, &first_entry)) {
170112d7cc84SAlan Cox 		vm_map_unlock(map);
170212d7cc84SAlan Cox 		return (KERN_INVALID_ADDRESS);
170312d7cc84SAlan Cox 	}
170412d7cc84SAlan Cox 	last_timestamp = map->timestamp;
170512d7cc84SAlan Cox 	entry = first_entry;
170612d7cc84SAlan Cox 	while (entry != &map->header && entry->start < end) {
170712d7cc84SAlan Cox 		if (entry->eflags & MAP_ENTRY_IN_TRANSITION) {
170812d7cc84SAlan Cox 			/*
170912d7cc84SAlan Cox 			 * We have not yet clipped the entry.
171012d7cc84SAlan Cox 			 */
171112d7cc84SAlan Cox 			saved_start = (start >= entry->start) ? start :
171212d7cc84SAlan Cox 			    entry->start;
171312d7cc84SAlan Cox 			entry->eflags |= MAP_ENTRY_NEEDS_WAKEUP;
171412d7cc84SAlan Cox 			if (vm_map_unlock_and_wait(map, user_wire)) {
171512d7cc84SAlan Cox 				/*
171612d7cc84SAlan Cox 				 * Allow interruption of user wiring?
171712d7cc84SAlan Cox 				 */
171812d7cc84SAlan Cox 			}
171912d7cc84SAlan Cox 			vm_map_lock(map);
172012d7cc84SAlan Cox 			if (last_timestamp + 1 != map->timestamp) {
172112d7cc84SAlan Cox 				/*
172212d7cc84SAlan Cox 				 * Look again for the entry because the map was
172312d7cc84SAlan Cox 				 * modified while it was unlocked.
172412d7cc84SAlan Cox 				 * Specifically, the entry may have been
172512d7cc84SAlan Cox 				 * clipped, merged, or deleted.
172612d7cc84SAlan Cox 				 */
172712d7cc84SAlan Cox 				if (!vm_map_lookup_entry(map, saved_start,
172812d7cc84SAlan Cox 				    &tmp_entry)) {
172912d7cc84SAlan Cox 					if (saved_start == start) {
173012d7cc84SAlan Cox 						/*
173112d7cc84SAlan Cox 						 * first_entry has been deleted.
173212d7cc84SAlan Cox 						 */
173312d7cc84SAlan Cox 						vm_map_unlock(map);
173412d7cc84SAlan Cox 						return (KERN_INVALID_ADDRESS);
173512d7cc84SAlan Cox 					}
173612d7cc84SAlan Cox 					end = saved_start;
173712d7cc84SAlan Cox 					rv = KERN_INVALID_ADDRESS;
173812d7cc84SAlan Cox 					goto done;
173912d7cc84SAlan Cox 				}
174012d7cc84SAlan Cox 				if (entry == first_entry)
174112d7cc84SAlan Cox 					first_entry = tmp_entry;
174212d7cc84SAlan Cox 				else
174312d7cc84SAlan Cox 					first_entry = NULL;
174412d7cc84SAlan Cox 				entry = tmp_entry;
174512d7cc84SAlan Cox 			}
174612d7cc84SAlan Cox 			last_timestamp = map->timestamp;
174712d7cc84SAlan Cox 			continue;
174812d7cc84SAlan Cox 		}
174912d7cc84SAlan Cox 		vm_map_clip_start(map, entry, start);
175012d7cc84SAlan Cox 		vm_map_clip_end(map, entry, end);
175112d7cc84SAlan Cox 		/*
175212d7cc84SAlan Cox 		 * Mark the entry in case the map lock is released.  (See
175312d7cc84SAlan Cox 		 * above.)
175412d7cc84SAlan Cox 		 */
175512d7cc84SAlan Cox 		entry->eflags |= MAP_ENTRY_IN_TRANSITION;
175612d7cc84SAlan Cox 		/*
175712d7cc84SAlan Cox 		 *
175812d7cc84SAlan Cox 		 */
175912d7cc84SAlan Cox 		if (entry->wired_count == 0) {
176012d7cc84SAlan Cox 			entry->wired_count++;
176112d7cc84SAlan Cox 			saved_start = entry->start;
176212d7cc84SAlan Cox 			saved_end = entry->end;
176312d7cc84SAlan Cox 			/*
176412d7cc84SAlan Cox 			 * Release the map lock, relying on the in-transition
176512d7cc84SAlan Cox 			 * mark.
176612d7cc84SAlan Cox 			 */
176712d7cc84SAlan Cox 			vm_map_unlock(map);
1768ef594d31SAlan Cox 			rv = vm_fault_wire(map, saved_start, saved_end,
1769ef594d31SAlan Cox 			    user_wire);
177012d7cc84SAlan Cox 			vm_map_lock(map);
177112d7cc84SAlan Cox 			if (last_timestamp + 1 != map->timestamp) {
177212d7cc84SAlan Cox 				/*
177312d7cc84SAlan Cox 				 * Look again for the entry because the map was
177412d7cc84SAlan Cox 				 * modified while it was unlocked.  The entry
177512d7cc84SAlan Cox 				 * may have been clipped, but NOT merged or
177612d7cc84SAlan Cox 				 * deleted.
177712d7cc84SAlan Cox 				 */
177812d7cc84SAlan Cox 				result = vm_map_lookup_entry(map, saved_start,
177912d7cc84SAlan Cox 				    &tmp_entry);
178012d7cc84SAlan Cox 				KASSERT(result, ("vm_map_wire: lookup failed"));
178112d7cc84SAlan Cox 				if (entry == first_entry)
178212d7cc84SAlan Cox 					first_entry = tmp_entry;
178312d7cc84SAlan Cox 				else
178412d7cc84SAlan Cox 					first_entry = NULL;
178512d7cc84SAlan Cox 				entry = tmp_entry;
178628c58286SAlan Cox 				while (entry->end < saved_end) {
178728c58286SAlan Cox 					if (rv != KERN_SUCCESS) {
178828c58286SAlan Cox 						KASSERT(entry->wired_count == 1,
178928c58286SAlan Cox 						    ("vm_map_wire: bad count"));
179028c58286SAlan Cox 						entry->wired_count = -1;
179128c58286SAlan Cox 					}
179212d7cc84SAlan Cox 					entry = entry->next;
179312d7cc84SAlan Cox 				}
179428c58286SAlan Cox 			}
179512d7cc84SAlan Cox 			last_timestamp = map->timestamp;
179612d7cc84SAlan Cox 			if (rv != KERN_SUCCESS) {
179728c58286SAlan Cox 				KASSERT(entry->wired_count == 1,
179828c58286SAlan Cox 				    ("vm_map_wire: bad count"));
179912d7cc84SAlan Cox 				/*
180028c58286SAlan Cox 				 * Assign an out-of-range value to represent
180128c58286SAlan Cox 				 * the failure to wire this entry.
180212d7cc84SAlan Cox 				 */
180328c58286SAlan Cox 				entry->wired_count = -1;
180412d7cc84SAlan Cox 				end = entry->end;
180512d7cc84SAlan Cox 				goto done;
180612d7cc84SAlan Cox 			}
180712d7cc84SAlan Cox 		} else if (!user_wire ||
180812d7cc84SAlan Cox 			   (entry->eflags & MAP_ENTRY_USER_WIRED) == 0) {
180912d7cc84SAlan Cox 			entry->wired_count++;
181012d7cc84SAlan Cox 		}
181112d7cc84SAlan Cox 		/*
181212d7cc84SAlan Cox 		 * Check the map for holes in the specified region.
181312d7cc84SAlan Cox 		 */
181412d7cc84SAlan Cox 		if (entry->end < end && (entry->next == &map->header ||
181512d7cc84SAlan Cox 		    entry->next->start > entry->end)) {
181612d7cc84SAlan Cox 			end = entry->end;
181712d7cc84SAlan Cox 			rv = KERN_INVALID_ADDRESS;
181812d7cc84SAlan Cox 			goto done;
181912d7cc84SAlan Cox 		}
182012d7cc84SAlan Cox 		entry = entry->next;
182112d7cc84SAlan Cox 	}
182212d7cc84SAlan Cox 	rv = KERN_SUCCESS;
182312d7cc84SAlan Cox done:
182412d7cc84SAlan Cox 	need_wakeup = FALSE;
182512d7cc84SAlan Cox 	if (first_entry == NULL) {
182612d7cc84SAlan Cox 		result = vm_map_lookup_entry(map, start, &first_entry);
182712d7cc84SAlan Cox 		KASSERT(result, ("vm_map_wire: lookup failed"));
182812d7cc84SAlan Cox 	}
182912d7cc84SAlan Cox 	entry = first_entry;
183012d7cc84SAlan Cox 	while (entry != &map->header && entry->start < end) {
183112d7cc84SAlan Cox 		if (rv == KERN_SUCCESS) {
183212d7cc84SAlan Cox 			if (user_wire)
183312d7cc84SAlan Cox 				entry->eflags |= MAP_ENTRY_USER_WIRED;
183428c58286SAlan Cox 		} else if (entry->wired_count == -1) {
183528c58286SAlan Cox 			/*
183628c58286SAlan Cox 			 * Wiring failed on this entry.  Thus, unwiring is
183728c58286SAlan Cox 			 * unnecessary.
183828c58286SAlan Cox 			 */
183928c58286SAlan Cox 			entry->wired_count = 0;
184012d7cc84SAlan Cox 		} else {
1841f6116791SAlan Cox 			if (!user_wire ||
1842f6116791SAlan Cox 			    (entry->eflags & MAP_ENTRY_USER_WIRED) == 0)
184312d7cc84SAlan Cox 				entry->wired_count--;
184412d7cc84SAlan Cox 			if (entry->wired_count == 0) {
184512d7cc84SAlan Cox 				/*
184612d7cc84SAlan Cox 				 * Retain the map lock.
184712d7cc84SAlan Cox 				 */
184812d7cc84SAlan Cox 				vm_fault_unwire(map, entry->start, entry->end);
184912d7cc84SAlan Cox 			}
185012d7cc84SAlan Cox 		}
185112d7cc84SAlan Cox 		KASSERT(entry->eflags & MAP_ENTRY_IN_TRANSITION,
185212d7cc84SAlan Cox 			("vm_map_wire: in-transition flag missing"));
185312d7cc84SAlan Cox 		entry->eflags &= ~MAP_ENTRY_IN_TRANSITION;
185412d7cc84SAlan Cox 		if (entry->eflags & MAP_ENTRY_NEEDS_WAKEUP) {
185512d7cc84SAlan Cox 			entry->eflags &= ~MAP_ENTRY_NEEDS_WAKEUP;
185612d7cc84SAlan Cox 			need_wakeup = TRUE;
185712d7cc84SAlan Cox 		}
185812d7cc84SAlan Cox 		vm_map_simplify_entry(map, entry);
185912d7cc84SAlan Cox 		entry = entry->next;
186012d7cc84SAlan Cox 	}
186112d7cc84SAlan Cox 	vm_map_unlock(map);
186212d7cc84SAlan Cox 	if (need_wakeup)
186312d7cc84SAlan Cox 		vm_map_wakeup(map);
186412d7cc84SAlan Cox 	return (rv);
1865e27e17b7SAlan Cox }
1866e27e17b7SAlan Cox 
1867e27e17b7SAlan Cox /*
1868df8bae1dSRodney W. Grimes  * vm_map_clean
1869df8bae1dSRodney W. Grimes  *
1870df8bae1dSRodney W. Grimes  * Push any dirty cached pages in the address range to their pager.
1871df8bae1dSRodney W. Grimes  * If syncio is TRUE, dirty pages are written synchronously.
1872df8bae1dSRodney W. Grimes  * If invalidate is TRUE, any cached pages are freed as well.
1873df8bae1dSRodney W. Grimes  *
1874df8bae1dSRodney W. Grimes  * Returns an error if any part of the specified range is not mapped.
1875df8bae1dSRodney W. Grimes  */
1876df8bae1dSRodney W. Grimes int
18771b40f8c0SMatthew Dillon vm_map_clean(
18781b40f8c0SMatthew Dillon 	vm_map_t map,
18791b40f8c0SMatthew Dillon 	vm_offset_t start,
18801b40f8c0SMatthew Dillon 	vm_offset_t end,
18811b40f8c0SMatthew Dillon 	boolean_t syncio,
18821b40f8c0SMatthew Dillon 	boolean_t invalidate)
1883df8bae1dSRodney W. Grimes {
1884c0877f10SJohn Dyson 	vm_map_entry_t current;
1885df8bae1dSRodney W. Grimes 	vm_map_entry_t entry;
1886df8bae1dSRodney W. Grimes 	vm_size_t size;
1887df8bae1dSRodney W. Grimes 	vm_object_t object;
1888a316d390SJohn Dyson 	vm_ooffset_t offset;
1889df8bae1dSRodney W. Grimes 
18900cddd8f0SMatthew Dillon 	GIANT_REQUIRED;
18910cddd8f0SMatthew Dillon 
1892df8bae1dSRodney W. Grimes 	vm_map_lock_read(map);
1893df8bae1dSRodney W. Grimes 	VM_MAP_RANGE_CHECK(map, start, end);
1894df8bae1dSRodney W. Grimes 	if (!vm_map_lookup_entry(map, start, &entry)) {
1895df8bae1dSRodney W. Grimes 		vm_map_unlock_read(map);
1896df8bae1dSRodney W. Grimes 		return (KERN_INVALID_ADDRESS);
1897df8bae1dSRodney W. Grimes 	}
1898df8bae1dSRodney W. Grimes 	/*
1899df8bae1dSRodney W. Grimes 	 * Make a first pass to check for holes.
1900df8bae1dSRodney W. Grimes 	 */
1901df8bae1dSRodney W. Grimes 	for (current = entry; current->start < end; current = current->next) {
1902afa07f7eSJohn Dyson 		if (current->eflags & MAP_ENTRY_IS_SUB_MAP) {
1903df8bae1dSRodney W. Grimes 			vm_map_unlock_read(map);
1904df8bae1dSRodney W. Grimes 			return (KERN_INVALID_ARGUMENT);
1905df8bae1dSRodney W. Grimes 		}
1906df8bae1dSRodney W. Grimes 		if (end > current->end &&
1907df8bae1dSRodney W. Grimes 		    (current->next == &map->header ||
1908df8bae1dSRodney W. Grimes 			current->end != current->next->start)) {
1909df8bae1dSRodney W. Grimes 			vm_map_unlock_read(map);
1910df8bae1dSRodney W. Grimes 			return (KERN_INVALID_ADDRESS);
1911df8bae1dSRodney W. Grimes 		}
1912df8bae1dSRodney W. Grimes 	}
1913df8bae1dSRodney W. Grimes 
1914bc105a67SAlan Cox 	if (invalidate) {
1915bc105a67SAlan Cox 		vm_page_lock_queues();
1916bc105a67SAlan Cox 		pmap_remove(map->pmap, start, end);
1917bc105a67SAlan Cox 		vm_page_unlock_queues();
1918bc105a67SAlan Cox 	}
1919df8bae1dSRodney W. Grimes 	/*
1920df8bae1dSRodney W. Grimes 	 * Make a second pass, cleaning/uncaching pages from the indicated
1921df8bae1dSRodney W. Grimes 	 * objects as we go.
1922df8bae1dSRodney W. Grimes 	 */
1923df8bae1dSRodney W. Grimes 	for (current = entry; current->start < end; current = current->next) {
1924df8bae1dSRodney W. Grimes 		offset = current->offset + (start - current->start);
1925df8bae1dSRodney W. Grimes 		size = (end <= current->end ? end : current->end) - start;
19269fdfe602SMatthew Dillon 		if (current->eflags & MAP_ENTRY_IS_SUB_MAP) {
1927c0877f10SJohn Dyson 			vm_map_t smap;
1928df8bae1dSRodney W. Grimes 			vm_map_entry_t tentry;
1929df8bae1dSRodney W. Grimes 			vm_size_t tsize;
1930df8bae1dSRodney W. Grimes 
19319fdfe602SMatthew Dillon 			smap = current->object.sub_map;
1932df8bae1dSRodney W. Grimes 			vm_map_lock_read(smap);
1933df8bae1dSRodney W. Grimes 			(void) vm_map_lookup_entry(smap, offset, &tentry);
1934df8bae1dSRodney W. Grimes 			tsize = tentry->end - offset;
1935df8bae1dSRodney W. Grimes 			if (tsize < size)
1936df8bae1dSRodney W. Grimes 				size = tsize;
1937df8bae1dSRodney W. Grimes 			object = tentry->object.vm_object;
1938df8bae1dSRodney W. Grimes 			offset = tentry->offset + (offset - tentry->start);
1939df8bae1dSRodney W. Grimes 			vm_map_unlock_read(smap);
1940df8bae1dSRodney W. Grimes 		} else {
1941df8bae1dSRodney W. Grimes 			object = current->object.vm_object;
1942df8bae1dSRodney W. Grimes 		}
19438a02c104SJohn Dyson 		/*
19448a02c104SJohn Dyson 		 * Note that there is absolutely no sense in writing out
19458a02c104SJohn Dyson 		 * anonymous objects, so we track down the vnode object
19468a02c104SJohn Dyson 		 * to write out.
19478a02c104SJohn Dyson 		 * We invalidate (remove) all pages from the address space
19488a02c104SJohn Dyson 		 * anyway, for semantic correctness.
19498c5dffe8SMatthew Dillon 		 *
19508c5dffe8SMatthew Dillon 		 * note: certain anonymous maps, such as MAP_NOSYNC maps,
19518c5dffe8SMatthew Dillon 		 * may start out with a NULL object.
19528a02c104SJohn Dyson 		 */
19538c5dffe8SMatthew Dillon 		while (object && object->backing_object) {
19548a02c104SJohn Dyson 			object = object->backing_object;
19558a02c104SJohn Dyson 			offset += object->backing_object_offset;
19568a02c104SJohn Dyson 			if (object->size < OFF_TO_IDX(offset + size))
19578a02c104SJohn Dyson 				size = IDX_TO_OFF(object->size) - offset;
19588a02c104SJohn Dyson 		}
1959ff359f84SMatthew Dillon 		if (object && (object->type == OBJT_VNODE) &&
1960ff359f84SMatthew Dillon 		    (current->protection & VM_PROT_WRITE)) {
1961df8bae1dSRodney W. Grimes 			/*
1962ff359f84SMatthew Dillon 			 * Flush pages if writing is allowed, invalidate them
1963ff359f84SMatthew Dillon 			 * if invalidation requested.  Pages undergoing I/O
1964ff359f84SMatthew Dillon 			 * will be ignored by vm_object_page_remove().
1965f5cf85d4SDavid Greenman 			 *
1966ff359f84SMatthew Dillon 			 * We cannot lock the vnode and then wait for paging
1967ff359f84SMatthew Dillon 			 * to complete without deadlocking against vm_fault.
1968ff359f84SMatthew Dillon 			 * Instead we simply call vm_object_page_remove() and
1969ff359f84SMatthew Dillon 			 * allow it to block internally on a page-by-page
1970ff359f84SMatthew Dillon 			 * basis when it encounters pages undergoing async
1971ff359f84SMatthew Dillon 			 * I/O.
1972df8bae1dSRodney W. Grimes 			 */
19738f9110f6SJohn Dyson 			int flags;
1974ff359f84SMatthew Dillon 
1975ff359f84SMatthew Dillon 			vm_object_reference(object);
1976b40ce416SJulian Elischer 			vn_lock(object->handle, LK_EXCLUSIVE | LK_RETRY, curthread);
19778f9110f6SJohn Dyson 			flags = (syncio || invalidate) ? OBJPC_SYNC : 0;
19788f9110f6SJohn Dyson 			flags |= invalidate ? OBJPC_INVAL : 0;
1979a316d390SJohn Dyson 			vm_object_page_clean(object,
1980a316d390SJohn Dyson 			    OFF_TO_IDX(offset),
19812be70f79SJohn Dyson 			    OFF_TO_IDX(offset + size + PAGE_MASK),
19828f9110f6SJohn Dyson 			    flags);
19834a2eca23SMatthew N. Dodd 			VOP_UNLOCK(object->handle, 0, curthread);
19844a2eca23SMatthew N. Dodd 			vm_object_deallocate(object);
19854a2eca23SMatthew N. Dodd 		}
19864a2eca23SMatthew N. Dodd 		if (object && invalidate &&
19874a2eca23SMatthew N. Dodd 		    ((object->type == OBJT_VNODE) ||
19884a2eca23SMatthew N. Dodd 		     (object->type == OBJT_DEVICE))) {
1989034b3d7aSAlan Cox 			VM_OBJECT_LOCK(object);
1990a316d390SJohn Dyson 			vm_object_page_remove(object,
1991a316d390SJohn Dyson 			    OFF_TO_IDX(offset),
19922be70f79SJohn Dyson 			    OFF_TO_IDX(offset + size + PAGE_MASK),
1993a316d390SJohn Dyson 			    FALSE);
1994034b3d7aSAlan Cox 			VM_OBJECT_UNLOCK(object);
1995a02051c3SJohn Dyson                 }
1996df8bae1dSRodney W. Grimes 		start += size;
1997df8bae1dSRodney W. Grimes 	}
1998df8bae1dSRodney W. Grimes 
1999df8bae1dSRodney W. Grimes 	vm_map_unlock_read(map);
2000df8bae1dSRodney W. Grimes 	return (KERN_SUCCESS);
2001df8bae1dSRodney W. Grimes }
2002df8bae1dSRodney W. Grimes 
2003df8bae1dSRodney W. Grimes /*
2004df8bae1dSRodney W. Grimes  *	vm_map_entry_unwire:	[ internal use only ]
2005df8bae1dSRodney W. Grimes  *
2006df8bae1dSRodney W. Grimes  *	Make the region specified by this entry pageable.
2007df8bae1dSRodney W. Grimes  *
2008df8bae1dSRodney W. Grimes  *	The map in question should be locked.
2009df8bae1dSRodney W. Grimes  *	[This is the reason for this routine's existence.]
2010df8bae1dSRodney W. Grimes  */
20110362d7d7SJohn Dyson static void
20121b40f8c0SMatthew Dillon vm_map_entry_unwire(vm_map_t map, vm_map_entry_t entry)
2013df8bae1dSRodney W. Grimes {
2014df8bae1dSRodney W. Grimes 	vm_fault_unwire(map, entry->start, entry->end);
2015df8bae1dSRodney W. Grimes 	entry->wired_count = 0;
2016df8bae1dSRodney W. Grimes }
2017df8bae1dSRodney W. Grimes 
2018df8bae1dSRodney W. Grimes /*
2019df8bae1dSRodney W. Grimes  *	vm_map_entry_delete:	[ internal use only ]
2020df8bae1dSRodney W. Grimes  *
2021df8bae1dSRodney W. Grimes  *	Deallocate the given entry from the target map.
2022df8bae1dSRodney W. Grimes  */
20230362d7d7SJohn Dyson static void
20241b40f8c0SMatthew Dillon vm_map_entry_delete(vm_map_t map, vm_map_entry_t entry)
2025df8bae1dSRodney W. Grimes {
2026df8bae1dSRodney W. Grimes 	vm_map_entry_unlink(map, entry);
2027df8bae1dSRodney W. Grimes 	map->size -= entry->end - entry->start;
2028df8bae1dSRodney W. Grimes 
20299fdfe602SMatthew Dillon 	if ((entry->eflags & MAP_ENTRY_IS_SUB_MAP) == 0) {
2030df8bae1dSRodney W. Grimes 		vm_object_deallocate(entry->object.vm_object);
2031b5b40fa6SJohn Dyson 	}
2032df8bae1dSRodney W. Grimes 
2033df8bae1dSRodney W. Grimes 	vm_map_entry_dispose(map, entry);
2034df8bae1dSRodney W. Grimes }
2035df8bae1dSRodney W. Grimes 
2036df8bae1dSRodney W. Grimes /*
2037df8bae1dSRodney W. Grimes  *	vm_map_delete:	[ internal use only ]
2038df8bae1dSRodney W. Grimes  *
2039df8bae1dSRodney W. Grimes  *	Deallocates the given address range from the target
2040df8bae1dSRodney W. Grimes  *	map.
2041df8bae1dSRodney W. Grimes  */
2042df8bae1dSRodney W. Grimes int
20431b40f8c0SMatthew Dillon vm_map_delete(vm_map_t map, vm_offset_t start, vm_offset_t end)
2044df8bae1dSRodney W. Grimes {
2045cbd8ec09SJohn Dyson 	vm_object_t object;
2046c0877f10SJohn Dyson 	vm_map_entry_t entry;
2047df8bae1dSRodney W. Grimes 	vm_map_entry_t first_entry;
2048df8bae1dSRodney W. Grimes 
2049df8bae1dSRodney W. Grimes 	/*
2050df8bae1dSRodney W. Grimes 	 * Find the start of the region, and clip it
2051df8bae1dSRodney W. Grimes 	 */
2052876318ecSAlan Cox 	if (!vm_map_lookup_entry(map, start, &first_entry))
2053df8bae1dSRodney W. Grimes 		entry = first_entry->next;
2054876318ecSAlan Cox 	else {
2055df8bae1dSRodney W. Grimes 		entry = first_entry;
2056df8bae1dSRodney W. Grimes 		vm_map_clip_start(map, entry, start);
2057df8bae1dSRodney W. Grimes 	}
2058df8bae1dSRodney W. Grimes 
2059df8bae1dSRodney W. Grimes 	/*
2060df8bae1dSRodney W. Grimes 	 * Save the free space hint
2061df8bae1dSRodney W. Grimes 	 */
2062b18bfc3dSJohn Dyson 	if (entry == &map->header) {
2063b18bfc3dSJohn Dyson 		map->first_free = &map->header;
20642dbea5d2SJohn Dyson 	} else if (map->first_free->start >= start) {
2065df8bae1dSRodney W. Grimes 		map->first_free = entry->prev;
20662dbea5d2SJohn Dyson 	}
2067df8bae1dSRodney W. Grimes 
2068df8bae1dSRodney W. Grimes 	/*
2069df8bae1dSRodney W. Grimes 	 * Step through all entries in this region
2070df8bae1dSRodney W. Grimes 	 */
2071df8bae1dSRodney W. Grimes 	while ((entry != &map->header) && (entry->start < end)) {
2072df8bae1dSRodney W. Grimes 		vm_map_entry_t next;
2073b18bfc3dSJohn Dyson 		vm_offset_t s, e;
2074cbd8ec09SJohn Dyson 		vm_pindex_t offidxstart, offidxend, count;
2075df8bae1dSRodney W. Grimes 
207673b2baceSAlan Cox 		/*
207773b2baceSAlan Cox 		 * Wait for wiring or unwiring of an entry to complete.
207873b2baceSAlan Cox 		 */
207973b2baceSAlan Cox 		if ((entry->eflags & MAP_ENTRY_IN_TRANSITION) != 0) {
208073b2baceSAlan Cox 			unsigned int last_timestamp;
208173b2baceSAlan Cox 			vm_offset_t saved_start;
208273b2baceSAlan Cox 			vm_map_entry_t tmp_entry;
208373b2baceSAlan Cox 
208473b2baceSAlan Cox 			saved_start = entry->start;
208573b2baceSAlan Cox 			entry->eflags |= MAP_ENTRY_NEEDS_WAKEUP;
208673b2baceSAlan Cox 			last_timestamp = map->timestamp;
208773b2baceSAlan Cox 			(void) vm_map_unlock_and_wait(map, FALSE);
208873b2baceSAlan Cox 			vm_map_lock(map);
208973b2baceSAlan Cox 			if (last_timestamp + 1 != map->timestamp) {
209073b2baceSAlan Cox 				/*
209173b2baceSAlan Cox 				 * Look again for the entry because the map was
209273b2baceSAlan Cox 				 * modified while it was unlocked.
209373b2baceSAlan Cox 				 * Specifically, the entry may have been
209473b2baceSAlan Cox 				 * clipped, merged, or deleted.
209573b2baceSAlan Cox 				 */
209673b2baceSAlan Cox 				if (!vm_map_lookup_entry(map, saved_start,
209773b2baceSAlan Cox 							 &tmp_entry))
209873b2baceSAlan Cox 					entry = tmp_entry->next;
209973b2baceSAlan Cox 				else {
210073b2baceSAlan Cox 					entry = tmp_entry;
210173b2baceSAlan Cox 					vm_map_clip_start(map, entry,
210273b2baceSAlan Cox 							  saved_start);
210373b2baceSAlan Cox 				}
210473b2baceSAlan Cox 			}
210573b2baceSAlan Cox 			continue;
210673b2baceSAlan Cox 		}
2107df8bae1dSRodney W. Grimes 		vm_map_clip_end(map, entry, end);
2108df8bae1dSRodney W. Grimes 
2109df8bae1dSRodney W. Grimes 		s = entry->start;
2110df8bae1dSRodney W. Grimes 		e = entry->end;
2111c0877f10SJohn Dyson 		next = entry->next;
2112df8bae1dSRodney W. Grimes 
2113cbd8ec09SJohn Dyson 		offidxstart = OFF_TO_IDX(entry->offset);
2114cbd8ec09SJohn Dyson 		count = OFF_TO_IDX(e - s);
2115cbd8ec09SJohn Dyson 		object = entry->object.vm_object;
21162dbea5d2SJohn Dyson 
2117df8bae1dSRodney W. Grimes 		/*
21180d94caffSDavid Greenman 		 * Unwire before removing addresses from the pmap; otherwise,
21190d94caffSDavid Greenman 		 * unwiring will put the entries back in the pmap.
2120df8bae1dSRodney W. Grimes 		 */
2121c0877f10SJohn Dyson 		if (entry->wired_count != 0) {
2122df8bae1dSRodney W. Grimes 			vm_map_entry_unwire(map, entry);
2123c0877f10SJohn Dyson 		}
2124df8bae1dSRodney W. Grimes 
2125cbd8ec09SJohn Dyson 		offidxend = offidxstart + count;
2126df8bae1dSRodney W. Grimes 
21277d040e3cSAlan Cox 		if (object == kernel_object || object == kmem_object) {
21287d040e3cSAlan Cox 			if (object == kernel_object)
21297d040e3cSAlan Cox 				GIANT_REQUIRED;
21307d040e3cSAlan Cox 			VM_OBJECT_LOCK(object);
21312dbea5d2SJohn Dyson 			vm_object_page_remove(object, offidxstart, offidxend, FALSE);
21327d040e3cSAlan Cox 			VM_OBJECT_UNLOCK(object);
2133b18bfc3dSJohn Dyson 		} else {
21347d040e3cSAlan Cox 			mtx_lock(&Giant);
2135bc105a67SAlan Cox 			vm_page_lock_queues();
2136df8bae1dSRodney W. Grimes 			pmap_remove(map->pmap, s, e);
2137bc105a67SAlan Cox 			vm_page_unlock_queues();
2138876318ecSAlan Cox 			if (object != NULL &&
2139876318ecSAlan Cox 			    object->ref_count != 1 &&
2140876318ecSAlan Cox 			    (object->flags & (OBJ_NOSPLIT|OBJ_ONEMAPPING)) == OBJ_ONEMAPPING &&
2141876318ecSAlan Cox 			    (object->type == OBJT_DEFAULT || object->type == OBJT_SWAP)) {
21422dbea5d2SJohn Dyson 				vm_object_collapse(object);
21437d040e3cSAlan Cox 				VM_OBJECT_LOCK(object);
21442dbea5d2SJohn Dyson 				vm_object_page_remove(object, offidxstart, offidxend, FALSE);
21457d040e3cSAlan Cox 				VM_OBJECT_UNLOCK(object);
21462dbea5d2SJohn Dyson 				if (object->type == OBJT_SWAP) {
2147cbd8ec09SJohn Dyson 					swap_pager_freespace(object, offidxstart, count);
21482dbea5d2SJohn Dyson 				}
2149876318ecSAlan Cox 				if (offidxend >= object->size &&
2150876318ecSAlan Cox 				    offidxstart < object->size) {
2151c0877f10SJohn Dyson 					object->size = offidxstart;
2152c0877f10SJohn Dyson 				}
21532dbea5d2SJohn Dyson 			}
21547d040e3cSAlan Cox 			mtx_unlock(&Giant);
2155b18bfc3dSJohn Dyson 		}
2156df8bae1dSRodney W. Grimes 
2157df8bae1dSRodney W. Grimes 		/*
21580d94caffSDavid Greenman 		 * Delete the entry (which may delete the object) only after
21590d94caffSDavid Greenman 		 * removing all pmap entries pointing to its pages.
21600d94caffSDavid Greenman 		 * (Otherwise, its page frames may be reallocated, and any
21610d94caffSDavid Greenman 		 * modify bits will be set in the wrong object!)
2162df8bae1dSRodney W. Grimes 		 */
2163df8bae1dSRodney W. Grimes 		vm_map_entry_delete(map, entry);
2164df8bae1dSRodney W. Grimes 		entry = next;
2165df8bae1dSRodney W. Grimes 	}
2166df8bae1dSRodney W. Grimes 	return (KERN_SUCCESS);
2167df8bae1dSRodney W. Grimes }
2168df8bae1dSRodney W. Grimes 
2169df8bae1dSRodney W. Grimes /*
2170df8bae1dSRodney W. Grimes  *	vm_map_remove:
2171df8bae1dSRodney W. Grimes  *
2172df8bae1dSRodney W. Grimes  *	Remove the given address range from the target map.
2173df8bae1dSRodney W. Grimes  *	This is the exported form of vm_map_delete.
2174df8bae1dSRodney W. Grimes  */
2175df8bae1dSRodney W. Grimes int
21761b40f8c0SMatthew Dillon vm_map_remove(vm_map_t map, vm_offset_t start, vm_offset_t end)
2177df8bae1dSRodney W. Grimes {
2178c0877f10SJohn Dyson 	int result, s = 0;
21798d6e8edeSDavid Greenman 
218008442f8aSBosko Milekic 	if (map == kmem_map)
2181b18bfc3dSJohn Dyson 		s = splvm();
2182df8bae1dSRodney W. Grimes 
2183df8bae1dSRodney W. Grimes 	vm_map_lock(map);
2184df8bae1dSRodney W. Grimes 	VM_MAP_RANGE_CHECK(map, start, end);
2185df8bae1dSRodney W. Grimes 	result = vm_map_delete(map, start, end);
2186df8bae1dSRodney W. Grimes 	vm_map_unlock(map);
2187df8bae1dSRodney W. Grimes 
218808442f8aSBosko Milekic 	if (map == kmem_map)
21898d6e8edeSDavid Greenman 		splx(s);
21908d6e8edeSDavid Greenman 
2191df8bae1dSRodney W. Grimes 	return (result);
2192df8bae1dSRodney W. Grimes }
2193df8bae1dSRodney W. Grimes 
2194df8bae1dSRodney W. Grimes /*
2195df8bae1dSRodney W. Grimes  *	vm_map_check_protection:
2196df8bae1dSRodney W. Grimes  *
21972d5c7e45SMatthew Dillon  *	Assert that the target map allows the specified privilege on the
21982d5c7e45SMatthew Dillon  *	entire address region given.  The entire region must be allocated.
21992d5c7e45SMatthew Dillon  *
22002d5c7e45SMatthew Dillon  *	WARNING!  This code does not and should not check whether the
22012d5c7e45SMatthew Dillon  *	contents of the region is accessible.  For example a smaller file
22022d5c7e45SMatthew Dillon  *	might be mapped into a larger address space.
22032d5c7e45SMatthew Dillon  *
22042d5c7e45SMatthew Dillon  *	NOTE!  This code is also called by munmap().
2205df8bae1dSRodney W. Grimes  */
22060d94caffSDavid Greenman boolean_t
2207b9dcd593SBruce Evans vm_map_check_protection(vm_map_t map, vm_offset_t start, vm_offset_t end,
2208b9dcd593SBruce Evans 			vm_prot_t protection)
2209df8bae1dSRodney W. Grimes {
2210c0877f10SJohn Dyson 	vm_map_entry_t entry;
2211df8bae1dSRodney W. Grimes 	vm_map_entry_t tmp_entry;
2212df8bae1dSRodney W. Grimes 
22132f6c16e1SAlan Cox 	vm_map_lock_read(map);
2214df8bae1dSRodney W. Grimes 	if (!vm_map_lookup_entry(map, start, &tmp_entry)) {
22152f6c16e1SAlan Cox 		vm_map_unlock_read(map);
2216df8bae1dSRodney W. Grimes 		return (FALSE);
2217df8bae1dSRodney W. Grimes 	}
2218df8bae1dSRodney W. Grimes 	entry = tmp_entry;
2219df8bae1dSRodney W. Grimes 
2220df8bae1dSRodney W. Grimes 	while (start < end) {
2221df8bae1dSRodney W. Grimes 		if (entry == &map->header) {
22222f6c16e1SAlan Cox 			vm_map_unlock_read(map);
2223df8bae1dSRodney W. Grimes 			return (FALSE);
2224df8bae1dSRodney W. Grimes 		}
2225df8bae1dSRodney W. Grimes 		/*
2226df8bae1dSRodney W. Grimes 		 * No holes allowed!
2227df8bae1dSRodney W. Grimes 		 */
2228df8bae1dSRodney W. Grimes 		if (start < entry->start) {
22292f6c16e1SAlan Cox 			vm_map_unlock_read(map);
2230df8bae1dSRodney W. Grimes 			return (FALSE);
2231df8bae1dSRodney W. Grimes 		}
2232df8bae1dSRodney W. Grimes 		/*
2233df8bae1dSRodney W. Grimes 		 * Check protection associated with entry.
2234df8bae1dSRodney W. Grimes 		 */
2235df8bae1dSRodney W. Grimes 		if ((entry->protection & protection) != protection) {
22362f6c16e1SAlan Cox 			vm_map_unlock_read(map);
2237df8bae1dSRodney W. Grimes 			return (FALSE);
2238df8bae1dSRodney W. Grimes 		}
2239df8bae1dSRodney W. Grimes 		/* go to next entry */
2240df8bae1dSRodney W. Grimes 		start = entry->end;
2241df8bae1dSRodney W. Grimes 		entry = entry->next;
2242df8bae1dSRodney W. Grimes 	}
22432f6c16e1SAlan Cox 	vm_map_unlock_read(map);
2244df8bae1dSRodney W. Grimes 	return (TRUE);
2245df8bae1dSRodney W. Grimes }
2246df8bae1dSRodney W. Grimes 
224786524867SJohn Dyson /*
2248df8bae1dSRodney W. Grimes  *	vm_map_copy_entry:
2249df8bae1dSRodney W. Grimes  *
2250df8bae1dSRodney W. Grimes  *	Copies the contents of the source entry to the destination
2251df8bae1dSRodney W. Grimes  *	entry.  The entries *must* be aligned properly.
2252df8bae1dSRodney W. Grimes  */
2253f708ef1bSPoul-Henning Kamp static void
22541b40f8c0SMatthew Dillon vm_map_copy_entry(
22551b40f8c0SMatthew Dillon 	vm_map_t src_map,
22561b40f8c0SMatthew Dillon 	vm_map_t dst_map,
22571b40f8c0SMatthew Dillon 	vm_map_entry_t src_entry,
22581b40f8c0SMatthew Dillon 	vm_map_entry_t dst_entry)
2259df8bae1dSRodney W. Grimes {
2260c0877f10SJohn Dyson 	vm_object_t src_object;
2261c0877f10SJohn Dyson 
22629fdfe602SMatthew Dillon 	if ((dst_entry->eflags|src_entry->eflags) & MAP_ENTRY_IS_SUB_MAP)
2263df8bae1dSRodney W. Grimes 		return;
2264df8bae1dSRodney W. Grimes 
2265df8bae1dSRodney W. Grimes 	if (src_entry->wired_count == 0) {
2266df8bae1dSRodney W. Grimes 
2267df8bae1dSRodney W. Grimes 		/*
22680d94caffSDavid Greenman 		 * If the source entry is marked needs_copy, it is already
22690d94caffSDavid Greenman 		 * write-protected.
2270df8bae1dSRodney W. Grimes 		 */
2271afa07f7eSJohn Dyson 		if ((src_entry->eflags & MAP_ENTRY_NEEDS_COPY) == 0) {
227285e03a7eSAlan Cox 			vm_page_lock_queues();
2273df8bae1dSRodney W. Grimes 			pmap_protect(src_map->pmap,
2274df8bae1dSRodney W. Grimes 			    src_entry->start,
2275df8bae1dSRodney W. Grimes 			    src_entry->end,
2276df8bae1dSRodney W. Grimes 			    src_entry->protection & ~VM_PROT_WRITE);
227785e03a7eSAlan Cox 			vm_page_unlock_queues();
2278df8bae1dSRodney W. Grimes 		}
2279b18bfc3dSJohn Dyson 
2280df8bae1dSRodney W. Grimes 		/*
2281df8bae1dSRodney W. Grimes 		 * Make a copy of the object.
2282df8bae1dSRodney W. Grimes 		 */
22838aef1712SMatthew Dillon 		if ((src_object = src_entry->object.vm_object) != NULL) {
2284c0877f10SJohn Dyson 
2285c0877f10SJohn Dyson 			if ((src_object->handle == NULL) &&
2286c0877f10SJohn Dyson 				(src_object->type == OBJT_DEFAULT ||
2287c0877f10SJohn Dyson 				 src_object->type == OBJT_SWAP)) {
2288c0877f10SJohn Dyson 				vm_object_collapse(src_object);
228996fb8cf2SJohn Dyson 				if ((src_object->flags & (OBJ_NOSPLIT|OBJ_ONEMAPPING)) == OBJ_ONEMAPPING) {
2290c5aaa06dSAlan Cox 					vm_object_split(src_entry);
2291c0877f10SJohn Dyson 					src_object = src_entry->object.vm_object;
2292c0877f10SJohn Dyson 				}
2293c0877f10SJohn Dyson 			}
2294c0877f10SJohn Dyson 
2295c0877f10SJohn Dyson 			vm_object_reference(src_object);
2296e2479b4fSAlan Cox 			VM_OBJECT_LOCK(src_object);
2297069e9bc1SDoug Rabson 			vm_object_clear_flag(src_object, OBJ_ONEMAPPING);
2298e2479b4fSAlan Cox 			VM_OBJECT_UNLOCK(src_object);
2299c0877f10SJohn Dyson 			dst_entry->object.vm_object = src_object;
2300afa07f7eSJohn Dyson 			src_entry->eflags |= (MAP_ENTRY_COW|MAP_ENTRY_NEEDS_COPY);
2301afa07f7eSJohn Dyson 			dst_entry->eflags |= (MAP_ENTRY_COW|MAP_ENTRY_NEEDS_COPY);
2302b18bfc3dSJohn Dyson 			dst_entry->offset = src_entry->offset;
2303b18bfc3dSJohn Dyson 		} else {
2304b18bfc3dSJohn Dyson 			dst_entry->object.vm_object = NULL;
2305b18bfc3dSJohn Dyson 			dst_entry->offset = 0;
2306b18bfc3dSJohn Dyson 		}
2307df8bae1dSRodney W. Grimes 
2308df8bae1dSRodney W. Grimes 		pmap_copy(dst_map->pmap, src_map->pmap, dst_entry->start,
2309df8bae1dSRodney W. Grimes 		    dst_entry->end - dst_entry->start, src_entry->start);
23100d94caffSDavid Greenman 	} else {
2311df8bae1dSRodney W. Grimes 		/*
2312df8bae1dSRodney W. Grimes 		 * Of course, wired down pages can't be set copy-on-write.
23130d94caffSDavid Greenman 		 * Cause wired pages to be copied into the new map by
23140d94caffSDavid Greenman 		 * simulating faults (the new pages are pageable)
2315df8bae1dSRodney W. Grimes 		 */
2316df8bae1dSRodney W. Grimes 		vm_fault_copy_entry(dst_map, src_map, dst_entry, src_entry);
2317df8bae1dSRodney W. Grimes 	}
2318df8bae1dSRodney W. Grimes }
2319df8bae1dSRodney W. Grimes 
2320df8bae1dSRodney W. Grimes /*
2321df8bae1dSRodney W. Grimes  * vmspace_fork:
2322df8bae1dSRodney W. Grimes  * Create a new process vmspace structure and vm_map
2323df8bae1dSRodney W. Grimes  * based on those of an existing process.  The new map
2324df8bae1dSRodney W. Grimes  * is based on the old map, according to the inheritance
2325df8bae1dSRodney W. Grimes  * values on the regions in that map.
2326df8bae1dSRodney W. Grimes  *
2327df8bae1dSRodney W. Grimes  * The source map must not be locked.
2328df8bae1dSRodney W. Grimes  */
2329df8bae1dSRodney W. Grimes struct vmspace *
23301b40f8c0SMatthew Dillon vmspace_fork(struct vmspace *vm1)
2331df8bae1dSRodney W. Grimes {
2332c0877f10SJohn Dyson 	struct vmspace *vm2;
2333df8bae1dSRodney W. Grimes 	vm_map_t old_map = &vm1->vm_map;
2334df8bae1dSRodney W. Grimes 	vm_map_t new_map;
2335df8bae1dSRodney W. Grimes 	vm_map_entry_t old_entry;
2336df8bae1dSRodney W. Grimes 	vm_map_entry_t new_entry;
2337de5f6a77SJohn Dyson 	vm_object_t object;
2338df8bae1dSRodney W. Grimes 
23390cddd8f0SMatthew Dillon 	GIANT_REQUIRED;
23400cddd8f0SMatthew Dillon 
2341df8bae1dSRodney W. Grimes 	vm_map_lock(old_map);
2342b823bbd6SMatthew Dillon 	old_map->infork = 1;
2343df8bae1dSRodney W. Grimes 
23442d8acc0fSJohn Dyson 	vm2 = vmspace_alloc(old_map->min_offset, old_map->max_offset);
2345df8bae1dSRodney W. Grimes 	bcopy(&vm1->vm_startcopy, &vm2->vm_startcopy,
2346582ec34cSAlfred Perlstein 	    (caddr_t) &vm1->vm_endcopy - (caddr_t) &vm1->vm_startcopy);
2347df8bae1dSRodney W. Grimes 	new_map = &vm2->vm_map;	/* XXX */
234847221757SJohn Dyson 	new_map->timestamp = 1;
2349df8bae1dSRodney W. Grimes 
2350df8bae1dSRodney W. Grimes 	old_entry = old_map->header.next;
2351df8bae1dSRodney W. Grimes 
2352df8bae1dSRodney W. Grimes 	while (old_entry != &old_map->header) {
2353afa07f7eSJohn Dyson 		if (old_entry->eflags & MAP_ENTRY_IS_SUB_MAP)
2354df8bae1dSRodney W. Grimes 			panic("vm_map_fork: encountered a submap");
2355df8bae1dSRodney W. Grimes 
2356df8bae1dSRodney W. Grimes 		switch (old_entry->inheritance) {
2357df8bae1dSRodney W. Grimes 		case VM_INHERIT_NONE:
2358df8bae1dSRodney W. Grimes 			break;
2359df8bae1dSRodney W. Grimes 
2360df8bae1dSRodney W. Grimes 		case VM_INHERIT_SHARE:
2361df8bae1dSRodney W. Grimes 			/*
2362fed9a903SJohn Dyson 			 * Clone the entry, creating the shared object if necessary.
2363fed9a903SJohn Dyson 			 */
2364fed9a903SJohn Dyson 			object = old_entry->object.vm_object;
2365fed9a903SJohn Dyson 			if (object == NULL) {
2366fed9a903SJohn Dyson 				object = vm_object_allocate(OBJT_DEFAULT,
2367c2e11a03SJohn Dyson 					atop(old_entry->end - old_entry->start));
2368fed9a903SJohn Dyson 				old_entry->object.vm_object = object;
2369fed9a903SJohn Dyson 				old_entry->offset = (vm_offset_t) 0;
23709a2f6362SAlan Cox 			}
23719a2f6362SAlan Cox 
23729a2f6362SAlan Cox 			/*
23739a2f6362SAlan Cox 			 * Add the reference before calling vm_object_shadow
23749a2f6362SAlan Cox 			 * to insure that a shadow object is created.
23759a2f6362SAlan Cox 			 */
23769a2f6362SAlan Cox 			vm_object_reference(object);
23779a2f6362SAlan Cox 			if (old_entry->eflags & MAP_ENTRY_NEEDS_COPY) {
23785069bf57SJohn Dyson 				vm_object_shadow(&old_entry->object.vm_object,
23795069bf57SJohn Dyson 					&old_entry->offset,
2380c2e11a03SJohn Dyson 					atop(old_entry->end - old_entry->start));
23815069bf57SJohn Dyson 				old_entry->eflags &= ~MAP_ENTRY_NEEDS_COPY;
2382d30344bdSIan Dowse 				/* Transfer the second reference too. */
2383d30344bdSIan Dowse 				vm_object_reference(
2384d30344bdSIan Dowse 				    old_entry->object.vm_object);
2385d30344bdSIan Dowse 				vm_object_deallocate(object);
23865069bf57SJohn Dyson 				object = old_entry->object.vm_object;
2387fed9a903SJohn Dyson 			}
2388e2479b4fSAlan Cox 			VM_OBJECT_LOCK(object);
2389069e9bc1SDoug Rabson 			vm_object_clear_flag(object, OBJ_ONEMAPPING);
2390e2479b4fSAlan Cox 			VM_OBJECT_UNLOCK(object);
2391fed9a903SJohn Dyson 
2392fed9a903SJohn Dyson 			/*
2393ad5fca3bSAlan Cox 			 * Clone the entry, referencing the shared object.
2394df8bae1dSRodney W. Grimes 			 */
2395df8bae1dSRodney W. Grimes 			new_entry = vm_map_entry_create(new_map);
2396df8bae1dSRodney W. Grimes 			*new_entry = *old_entry;
2397028fe6ecSTor Egge 			new_entry->eflags &= ~MAP_ENTRY_USER_WIRED;
2398df8bae1dSRodney W. Grimes 			new_entry->wired_count = 0;
2399df8bae1dSRodney W. Grimes 
2400df8bae1dSRodney W. Grimes 			/*
24010d94caffSDavid Greenman 			 * Insert the entry into the new map -- we know we're
24020d94caffSDavid Greenman 			 * inserting at the end of the new map.
2403df8bae1dSRodney W. Grimes 			 */
2404df8bae1dSRodney W. Grimes 			vm_map_entry_link(new_map, new_map->header.prev,
2405df8bae1dSRodney W. Grimes 			    new_entry);
2406df8bae1dSRodney W. Grimes 
2407df8bae1dSRodney W. Grimes 			/*
2408df8bae1dSRodney W. Grimes 			 * Update the physical map
2409df8bae1dSRodney W. Grimes 			 */
2410df8bae1dSRodney W. Grimes 			pmap_copy(new_map->pmap, old_map->pmap,
2411df8bae1dSRodney W. Grimes 			    new_entry->start,
2412df8bae1dSRodney W. Grimes 			    (old_entry->end - old_entry->start),
2413df8bae1dSRodney W. Grimes 			    old_entry->start);
2414df8bae1dSRodney W. Grimes 			break;
2415df8bae1dSRodney W. Grimes 
2416df8bae1dSRodney W. Grimes 		case VM_INHERIT_COPY:
2417df8bae1dSRodney W. Grimes 			/*
2418df8bae1dSRodney W. Grimes 			 * Clone the entry and link into the map.
2419df8bae1dSRodney W. Grimes 			 */
2420df8bae1dSRodney W. Grimes 			new_entry = vm_map_entry_create(new_map);
2421df8bae1dSRodney W. Grimes 			*new_entry = *old_entry;
2422028fe6ecSTor Egge 			new_entry->eflags &= ~MAP_ENTRY_USER_WIRED;
2423df8bae1dSRodney W. Grimes 			new_entry->wired_count = 0;
2424df8bae1dSRodney W. Grimes 			new_entry->object.vm_object = NULL;
2425df8bae1dSRodney W. Grimes 			vm_map_entry_link(new_map, new_map->header.prev,
2426df8bae1dSRodney W. Grimes 			    new_entry);
2427bd7e5f99SJohn Dyson 			vm_map_copy_entry(old_map, new_map, old_entry,
2428bd7e5f99SJohn Dyson 			    new_entry);
2429df8bae1dSRodney W. Grimes 			break;
2430df8bae1dSRodney W. Grimes 		}
2431df8bae1dSRodney W. Grimes 		old_entry = old_entry->next;
2432df8bae1dSRodney W. Grimes 	}
2433df8bae1dSRodney W. Grimes 
2434df8bae1dSRodney W. Grimes 	new_map->size = old_map->size;
2435b823bbd6SMatthew Dillon 	old_map->infork = 0;
2436df8bae1dSRodney W. Grimes 	vm_map_unlock(old_map);
2437df8bae1dSRodney W. Grimes 
2438df8bae1dSRodney W. Grimes 	return (vm2);
2439df8bae1dSRodney W. Grimes }
2440df8bae1dSRodney W. Grimes 
244194f7e29aSAlan Cox int
244294f7e29aSAlan Cox vm_map_stack (vm_map_t map, vm_offset_t addrbos, vm_size_t max_ssize,
244394f7e29aSAlan Cox 	      vm_prot_t prot, vm_prot_t max, int cow)
244494f7e29aSAlan Cox {
244594f7e29aSAlan Cox 	vm_map_entry_t prev_entry;
244694f7e29aSAlan Cox 	vm_map_entry_t new_stack_entry;
244794f7e29aSAlan Cox 	vm_size_t      init_ssize;
244894f7e29aSAlan Cox 	int            rv;
244994f7e29aSAlan Cox 
245005ba50f5SJake Burkholder 	if (addrbos < vm_map_min(map))
245194f7e29aSAlan Cox 		return (KERN_NO_SPACE);
245294f7e29aSAlan Cox 
2453cbc89bfbSPaul Saab 	if (max_ssize < sgrowsiz)
245494f7e29aSAlan Cox 		init_ssize = max_ssize;
245594f7e29aSAlan Cox 	else
2456cbc89bfbSPaul Saab 		init_ssize = sgrowsiz;
245794f7e29aSAlan Cox 
245894f7e29aSAlan Cox 	vm_map_lock(map);
245994f7e29aSAlan Cox 
246094f7e29aSAlan Cox 	/* If addr is already mapped, no go */
246194f7e29aSAlan Cox 	if (vm_map_lookup_entry(map, addrbos, &prev_entry)) {
246294f7e29aSAlan Cox 		vm_map_unlock(map);
246394f7e29aSAlan Cox 		return (KERN_NO_SPACE);
246494f7e29aSAlan Cox 	}
246594f7e29aSAlan Cox 
2466a69ac174SMatthew Dillon 	/* If we would blow our VMEM resource limit, no go */
2467a69ac174SMatthew Dillon 	if (map->size + init_ssize >
2468a69ac174SMatthew Dillon 	    curthread->td_proc->p_rlimit[RLIMIT_VMEM].rlim_cur) {
2469a69ac174SMatthew Dillon 		vm_map_unlock(map);
2470a69ac174SMatthew Dillon 		return (KERN_NO_SPACE);
2471a69ac174SMatthew Dillon 	}
2472a69ac174SMatthew Dillon 
247394f7e29aSAlan Cox 	/* If we can't accomodate max_ssize in the current mapping,
247494f7e29aSAlan Cox 	 * no go.  However, we need to be aware that subsequent user
247594f7e29aSAlan Cox 	 * mappings might map into the space we have reserved for
247694f7e29aSAlan Cox 	 * stack, and currently this space is not protected.
247794f7e29aSAlan Cox 	 *
247894f7e29aSAlan Cox 	 * Hopefully we will at least detect this condition
247994f7e29aSAlan Cox 	 * when we try to grow the stack.
248094f7e29aSAlan Cox 	 */
248194f7e29aSAlan Cox 	if ((prev_entry->next != &map->header) &&
248294f7e29aSAlan Cox 	    (prev_entry->next->start < addrbos + max_ssize)) {
248394f7e29aSAlan Cox 		vm_map_unlock(map);
248494f7e29aSAlan Cox 		return (KERN_NO_SPACE);
248594f7e29aSAlan Cox 	}
248694f7e29aSAlan Cox 
248794f7e29aSAlan Cox 	/* We initially map a stack of only init_ssize.  We will
248894f7e29aSAlan Cox 	 * grow as needed later.  Since this is to be a grow
248994f7e29aSAlan Cox 	 * down stack, we map at the top of the range.
249094f7e29aSAlan Cox 	 *
249194f7e29aSAlan Cox 	 * Note: we would normally expect prot and max to be
249294f7e29aSAlan Cox 	 * VM_PROT_ALL, and cow to be 0.  Possibly we should
249394f7e29aSAlan Cox 	 * eliminate these as input parameters, and just
249494f7e29aSAlan Cox 	 * pass these values here in the insert call.
249594f7e29aSAlan Cox 	 */
249694f7e29aSAlan Cox 	rv = vm_map_insert(map, NULL, 0, addrbos + max_ssize - init_ssize,
249794f7e29aSAlan Cox 	                   addrbos + max_ssize, prot, max, cow);
249894f7e29aSAlan Cox 
249994f7e29aSAlan Cox 	/* Now set the avail_ssize amount */
250094f7e29aSAlan Cox 	if (rv == KERN_SUCCESS){
250129b45e9eSAlan Cox 		if (prev_entry != &map->header)
250229b45e9eSAlan Cox 			vm_map_clip_end(map, prev_entry, addrbos + max_ssize - init_ssize);
250394f7e29aSAlan Cox 		new_stack_entry = prev_entry->next;
250494f7e29aSAlan Cox 		if (new_stack_entry->end   != addrbos + max_ssize ||
250594f7e29aSAlan Cox 		    new_stack_entry->start != addrbos + max_ssize - init_ssize)
250694f7e29aSAlan Cox 			panic ("Bad entry start/end for new stack entry");
250794f7e29aSAlan Cox 		else
250894f7e29aSAlan Cox 			new_stack_entry->avail_ssize = max_ssize - init_ssize;
250994f7e29aSAlan Cox 	}
251094f7e29aSAlan Cox 
251194f7e29aSAlan Cox 	vm_map_unlock(map);
251294f7e29aSAlan Cox 	return (rv);
251394f7e29aSAlan Cox }
251494f7e29aSAlan Cox 
251594f7e29aSAlan Cox /* Attempts to grow a vm stack entry.  Returns KERN_SUCCESS if the
251694f7e29aSAlan Cox  * desired address is already mapped, or if we successfully grow
251794f7e29aSAlan Cox  * the stack.  Also returns KERN_SUCCESS if addr is outside the
251894f7e29aSAlan Cox  * stack range (this is strange, but preserves compatibility with
251994f7e29aSAlan Cox  * the grow function in vm_machdep.c).
252094f7e29aSAlan Cox  */
252194f7e29aSAlan Cox int
252294f7e29aSAlan Cox vm_map_growstack (struct proc *p, vm_offset_t addr)
252394f7e29aSAlan Cox {
252494f7e29aSAlan Cox 	vm_map_entry_t prev_entry;
252594f7e29aSAlan Cox 	vm_map_entry_t stack_entry;
252694f7e29aSAlan Cox 	vm_map_entry_t new_stack_entry;
252794f7e29aSAlan Cox 	struct vmspace *vm = p->p_vmspace;
252894f7e29aSAlan Cox 	vm_map_t map = &vm->vm_map;
252994f7e29aSAlan Cox 	vm_offset_t    end;
253094f7e29aSAlan Cox 	int      grow_amount;
253194f7e29aSAlan Cox 	int      rv;
253294f7e29aSAlan Cox 	int      is_procstack;
253323955314SAlfred Perlstein 
25340cddd8f0SMatthew Dillon 	GIANT_REQUIRED;
253523955314SAlfred Perlstein 
253694f7e29aSAlan Cox Retry:
253794f7e29aSAlan Cox 	vm_map_lock_read(map);
253894f7e29aSAlan Cox 
253994f7e29aSAlan Cox 	/* If addr is already in the entry range, no need to grow.*/
254094f7e29aSAlan Cox 	if (vm_map_lookup_entry(map, addr, &prev_entry)) {
254194f7e29aSAlan Cox 		vm_map_unlock_read(map);
25420cddd8f0SMatthew Dillon 		return (KERN_SUCCESS);
254394f7e29aSAlan Cox 	}
254494f7e29aSAlan Cox 
254594f7e29aSAlan Cox 	if ((stack_entry = prev_entry->next) == &map->header) {
254694f7e29aSAlan Cox 		vm_map_unlock_read(map);
25470cddd8f0SMatthew Dillon 		return (KERN_SUCCESS);
254894f7e29aSAlan Cox 	}
254994f7e29aSAlan Cox 	if (prev_entry == &map->header)
255094f7e29aSAlan Cox 		end = stack_entry->start - stack_entry->avail_ssize;
255194f7e29aSAlan Cox 	else
255294f7e29aSAlan Cox 		end = prev_entry->end;
255394f7e29aSAlan Cox 
255494f7e29aSAlan Cox 	/* This next test mimics the old grow function in vm_machdep.c.
255594f7e29aSAlan Cox 	 * It really doesn't quite make sense, but we do it anyway
255694f7e29aSAlan Cox 	 * for compatibility.
255794f7e29aSAlan Cox 	 *
255894f7e29aSAlan Cox 	 * If not growable stack, return success.  This signals the
255994f7e29aSAlan Cox 	 * caller to proceed as he would normally with normal vm.
256094f7e29aSAlan Cox 	 */
256194f7e29aSAlan Cox 	if (stack_entry->avail_ssize < 1 ||
256294f7e29aSAlan Cox 	    addr >= stack_entry->start ||
256394f7e29aSAlan Cox 	    addr <  stack_entry->start - stack_entry->avail_ssize) {
256494f7e29aSAlan Cox 		vm_map_unlock_read(map);
25650cddd8f0SMatthew Dillon 		return (KERN_SUCCESS);
256694f7e29aSAlan Cox 	}
256794f7e29aSAlan Cox 
256894f7e29aSAlan Cox 	/* Find the minimum grow amount */
256994f7e29aSAlan Cox 	grow_amount = roundup (stack_entry->start - addr, PAGE_SIZE);
257094f7e29aSAlan Cox 	if (grow_amount > stack_entry->avail_ssize) {
257194f7e29aSAlan Cox 		vm_map_unlock_read(map);
25720cddd8f0SMatthew Dillon 		return (KERN_NO_SPACE);
257394f7e29aSAlan Cox 	}
257494f7e29aSAlan Cox 
257594f7e29aSAlan Cox 	/* If there is no longer enough space between the entries
257694f7e29aSAlan Cox 	 * nogo, and adjust the available space.  Note: this
257794f7e29aSAlan Cox 	 * should only happen if the user has mapped into the
257894f7e29aSAlan Cox 	 * stack area after the stack was created, and is
257994f7e29aSAlan Cox 	 * probably an error.
258094f7e29aSAlan Cox 	 *
258194f7e29aSAlan Cox 	 * This also effectively destroys any guard page the user
258294f7e29aSAlan Cox 	 * might have intended by limiting the stack size.
258394f7e29aSAlan Cox 	 */
258494f7e29aSAlan Cox 	if (grow_amount > stack_entry->start - end) {
258525adb370SBrian Feldman 		if (vm_map_lock_upgrade(map))
258694f7e29aSAlan Cox 			goto Retry;
258794f7e29aSAlan Cox 
258894f7e29aSAlan Cox 		stack_entry->avail_ssize = stack_entry->start - end;
258994f7e29aSAlan Cox 
259094f7e29aSAlan Cox 		vm_map_unlock(map);
25910cddd8f0SMatthew Dillon 		return (KERN_NO_SPACE);
259294f7e29aSAlan Cox 	}
259394f7e29aSAlan Cox 
259494f7e29aSAlan Cox 	is_procstack = addr >= (vm_offset_t)vm->vm_maxsaddr;
259594f7e29aSAlan Cox 
259694f7e29aSAlan Cox 	/* If this is the main process stack, see if we're over the
259794f7e29aSAlan Cox 	 * stack limit.
259894f7e29aSAlan Cox 	 */
25996389da78SAlan Cox 	if (is_procstack && (ctob(vm->vm_ssize) + grow_amount >
260094f7e29aSAlan Cox 			     p->p_rlimit[RLIMIT_STACK].rlim_cur)) {
260194f7e29aSAlan Cox 		vm_map_unlock_read(map);
26020cddd8f0SMatthew Dillon 		return (KERN_NO_SPACE);
260394f7e29aSAlan Cox 	}
260494f7e29aSAlan Cox 
260594f7e29aSAlan Cox 	/* Round up the grow amount modulo SGROWSIZ */
2606cbc89bfbSPaul Saab 	grow_amount = roundup (grow_amount, sgrowsiz);
260794f7e29aSAlan Cox 	if (grow_amount > stack_entry->avail_ssize) {
260894f7e29aSAlan Cox 		grow_amount = stack_entry->avail_ssize;
260994f7e29aSAlan Cox 	}
26106389da78SAlan Cox 	if (is_procstack && (ctob(vm->vm_ssize) + grow_amount >
261194f7e29aSAlan Cox 	                     p->p_rlimit[RLIMIT_STACK].rlim_cur)) {
261294f7e29aSAlan Cox 		grow_amount = p->p_rlimit[RLIMIT_STACK].rlim_cur -
26136389da78SAlan Cox 		              ctob(vm->vm_ssize);
261494f7e29aSAlan Cox 	}
261594f7e29aSAlan Cox 
2616a69ac174SMatthew Dillon 	/* If we would blow our VMEM resource limit, no go */
2617a69ac174SMatthew Dillon 	if (map->size + grow_amount >
2618a69ac174SMatthew Dillon 	    curthread->td_proc->p_rlimit[RLIMIT_VMEM].rlim_cur) {
2619a69ac174SMatthew Dillon 		vm_map_unlock_read(map);
2620a69ac174SMatthew Dillon 		return (KERN_NO_SPACE);
2621a69ac174SMatthew Dillon 	}
2622a69ac174SMatthew Dillon 
262325adb370SBrian Feldman 	if (vm_map_lock_upgrade(map))
262494f7e29aSAlan Cox 		goto Retry;
262594f7e29aSAlan Cox 
262694f7e29aSAlan Cox 	/* Get the preliminary new entry start value */
262794f7e29aSAlan Cox 	addr = stack_entry->start - grow_amount;
262894f7e29aSAlan Cox 
262994f7e29aSAlan Cox 	/* If this puts us into the previous entry, cut back our growth
263094f7e29aSAlan Cox 	 * to the available space.  Also, see the note above.
263194f7e29aSAlan Cox 	 */
263294f7e29aSAlan Cox 	if (addr < end) {
263394f7e29aSAlan Cox 		stack_entry->avail_ssize = stack_entry->start - end;
263494f7e29aSAlan Cox 		addr = end;
263594f7e29aSAlan Cox 	}
263694f7e29aSAlan Cox 
263794f7e29aSAlan Cox 	rv = vm_map_insert(map, NULL, 0, addr, stack_entry->start,
263805ba50f5SJake Burkholder 	    p->p_sysent->sv_stackprot, VM_PROT_ALL, 0);
263994f7e29aSAlan Cox 
264094f7e29aSAlan Cox 	/* Adjust the available stack space by the amount we grew. */
264194f7e29aSAlan Cox 	if (rv == KERN_SUCCESS) {
264229b45e9eSAlan Cox 		if (prev_entry != &map->header)
264329b45e9eSAlan Cox 			vm_map_clip_end(map, prev_entry, addr);
264494f7e29aSAlan Cox 		new_stack_entry = prev_entry->next;
264594f7e29aSAlan Cox 		if (new_stack_entry->end   != stack_entry->start  ||
264694f7e29aSAlan Cox 		    new_stack_entry->start != addr)
264794f7e29aSAlan Cox 			panic ("Bad stack grow start/end in new stack entry");
264894f7e29aSAlan Cox 		else {
264994f7e29aSAlan Cox 			new_stack_entry->avail_ssize = stack_entry->avail_ssize -
265094f7e29aSAlan Cox 							(new_stack_entry->end -
265194f7e29aSAlan Cox 							 new_stack_entry->start);
265294f7e29aSAlan Cox 			if (is_procstack)
26536389da78SAlan Cox 				vm->vm_ssize += btoc(new_stack_entry->end -
26546389da78SAlan Cox 						     new_stack_entry->start);
265594f7e29aSAlan Cox 		}
265694f7e29aSAlan Cox 	}
265794f7e29aSAlan Cox 
265894f7e29aSAlan Cox 	vm_map_unlock(map);
26590cddd8f0SMatthew Dillon 	return (rv);
266094f7e29aSAlan Cox }
266194f7e29aSAlan Cox 
2662df8bae1dSRodney W. Grimes /*
26635856e12eSJohn Dyson  * Unshare the specified VM space for exec.  If other processes are
26645856e12eSJohn Dyson  * mapped to it, then create a new one.  The new vmspace is null.
26655856e12eSJohn Dyson  */
26665856e12eSJohn Dyson void
26673ebc1248SPeter Wemm vmspace_exec(struct proc *p, vm_offset_t minuser, vm_offset_t maxuser)
26681b40f8c0SMatthew Dillon {
26695856e12eSJohn Dyson 	struct vmspace *oldvmspace = p->p_vmspace;
26705856e12eSJohn Dyson 	struct vmspace *newvmspace;
26715856e12eSJohn Dyson 
26720cddd8f0SMatthew Dillon 	GIANT_REQUIRED;
26733ebc1248SPeter Wemm 	newvmspace = vmspace_alloc(minuser, maxuser);
26745856e12eSJohn Dyson 	bcopy(&oldvmspace->vm_startcopy, &newvmspace->vm_startcopy,
26755856e12eSJohn Dyson 	    (caddr_t) (newvmspace + 1) - (caddr_t) &newvmspace->vm_startcopy);
26765856e12eSJohn Dyson 	/*
26775856e12eSJohn Dyson 	 * This code is written like this for prototype purposes.  The
26785856e12eSJohn Dyson 	 * goal is to avoid running down the vmspace here, but let the
26795856e12eSJohn Dyson 	 * other process's that are still using the vmspace to finally
26805856e12eSJohn Dyson 	 * run it down.  Even though there is little or no chance of blocking
26815856e12eSJohn Dyson 	 * here, it is a good idea to keep this form for future mods.
26825856e12eSJohn Dyson 	 */
26835856e12eSJohn Dyson 	p->p_vmspace = newvmspace;
2684d4da2dbaSAlan Cox 	pmap_pinit2(vmspace_pmap(newvmspace));
268521c641b2SJohn Baldwin 	vmspace_free(oldvmspace);
2686b40ce416SJulian Elischer 	if (p == curthread->td_proc)		/* XXXKSE ? */
2687b40ce416SJulian Elischer 		pmap_activate(curthread);
26885856e12eSJohn Dyson }
26895856e12eSJohn Dyson 
26905856e12eSJohn Dyson /*
26915856e12eSJohn Dyson  * Unshare the specified VM space for forcing COW.  This
26925856e12eSJohn Dyson  * is called by rfork, for the (RFMEM|RFPROC) == 0 case.
26935856e12eSJohn Dyson  */
26945856e12eSJohn Dyson void
26951b40f8c0SMatthew Dillon vmspace_unshare(struct proc *p)
26961b40f8c0SMatthew Dillon {
26975856e12eSJohn Dyson 	struct vmspace *oldvmspace = p->p_vmspace;
26985856e12eSJohn Dyson 	struct vmspace *newvmspace;
26995856e12eSJohn Dyson 
27000cddd8f0SMatthew Dillon 	GIANT_REQUIRED;
27015856e12eSJohn Dyson 	if (oldvmspace->vm_refcnt == 1)
27025856e12eSJohn Dyson 		return;
27035856e12eSJohn Dyson 	newvmspace = vmspace_fork(oldvmspace);
27045856e12eSJohn Dyson 	p->p_vmspace = newvmspace;
2705d4da2dbaSAlan Cox 	pmap_pinit2(vmspace_pmap(newvmspace));
270621c641b2SJohn Baldwin 	vmspace_free(oldvmspace);
2707b40ce416SJulian Elischer 	if (p == curthread->td_proc)		/* XXXKSE ? */
2708b40ce416SJulian Elischer 		pmap_activate(curthread);
27095856e12eSJohn Dyson }
27105856e12eSJohn Dyson 
27115856e12eSJohn Dyson /*
2712df8bae1dSRodney W. Grimes  *	vm_map_lookup:
2713df8bae1dSRodney W. Grimes  *
2714df8bae1dSRodney W. Grimes  *	Finds the VM object, offset, and
2715df8bae1dSRodney W. Grimes  *	protection for a given virtual address in the
2716df8bae1dSRodney W. Grimes  *	specified map, assuming a page fault of the
2717df8bae1dSRodney W. Grimes  *	type specified.
2718df8bae1dSRodney W. Grimes  *
2719df8bae1dSRodney W. Grimes  *	Leaves the map in question locked for read; return
2720df8bae1dSRodney W. Grimes  *	values are guaranteed until a vm_map_lookup_done
2721df8bae1dSRodney W. Grimes  *	call is performed.  Note that the map argument
2722df8bae1dSRodney W. Grimes  *	is in/out; the returned map must be used in
2723df8bae1dSRodney W. Grimes  *	the call to vm_map_lookup_done.
2724df8bae1dSRodney W. Grimes  *
2725df8bae1dSRodney W. Grimes  *	A handle (out_entry) is returned for use in
2726df8bae1dSRodney W. Grimes  *	vm_map_lookup_done, to make that fast.
2727df8bae1dSRodney W. Grimes  *
2728df8bae1dSRodney W. Grimes  *	If a lookup is requested with "write protection"
2729df8bae1dSRodney W. Grimes  *	specified, the map may be changed to perform virtual
2730df8bae1dSRodney W. Grimes  *	copying operations, although the data referenced will
2731df8bae1dSRodney W. Grimes  *	remain the same.
2732df8bae1dSRodney W. Grimes  */
2733df8bae1dSRodney W. Grimes int
2734b9dcd593SBruce Evans vm_map_lookup(vm_map_t *var_map,		/* IN/OUT */
2735b9dcd593SBruce Evans 	      vm_offset_t vaddr,
273647221757SJohn Dyson 	      vm_prot_t fault_typea,
2737b9dcd593SBruce Evans 	      vm_map_entry_t *out_entry,	/* OUT */
2738b9dcd593SBruce Evans 	      vm_object_t *object,		/* OUT */
2739b9dcd593SBruce Evans 	      vm_pindex_t *pindex,		/* OUT */
2740b9dcd593SBruce Evans 	      vm_prot_t *out_prot,		/* OUT */
27412d8acc0fSJohn Dyson 	      boolean_t *wired)			/* OUT */
2742df8bae1dSRodney W. Grimes {
2743c0877f10SJohn Dyson 	vm_map_entry_t entry;
2744c0877f10SJohn Dyson 	vm_map_t map = *var_map;
2745c0877f10SJohn Dyson 	vm_prot_t prot;
274647221757SJohn Dyson 	vm_prot_t fault_type = fault_typea;
2747df8bae1dSRodney W. Grimes 
2748df8bae1dSRodney W. Grimes RetryLookup:;
2749df8bae1dSRodney W. Grimes 	/*
2750df8bae1dSRodney W. Grimes 	 * Lookup the faulting address.
2751df8bae1dSRodney W. Grimes 	 */
2752df8bae1dSRodney W. Grimes 
2753df8bae1dSRodney W. Grimes 	vm_map_lock_read(map);
2754df8bae1dSRodney W. Grimes #define	RETURN(why) \
2755df8bae1dSRodney W. Grimes 		{ \
2756df8bae1dSRodney W. Grimes 		vm_map_unlock_read(map); \
2757df8bae1dSRodney W. Grimes 		return (why); \
2758df8bae1dSRodney W. Grimes 		}
2759df8bae1dSRodney W. Grimes 
2760df8bae1dSRodney W. Grimes 	/*
27610d94caffSDavid Greenman 	 * If the map has an interesting hint, try it before calling full
27620d94caffSDavid Greenman 	 * blown lookup routine.
2763df8bae1dSRodney W. Grimes 	 */
27644e94f402SAlan Cox 	entry = map->root;
2765df8bae1dSRodney W. Grimes 	*out_entry = entry;
27664e94f402SAlan Cox 	if (entry == NULL ||
2767df8bae1dSRodney W. Grimes 	    (vaddr < entry->start) || (vaddr >= entry->end)) {
2768df8bae1dSRodney W. Grimes 		/*
27690d94caffSDavid Greenman 		 * Entry was either not a valid hint, or the vaddr was not
27700d94caffSDavid Greenman 		 * contained in the entry, so do a full lookup.
2771df8bae1dSRodney W. Grimes 		 */
27724e94f402SAlan Cox 		if (!vm_map_lookup_entry(map, vaddr, out_entry))
2773df8bae1dSRodney W. Grimes 			RETURN(KERN_INVALID_ADDRESS);
2774df8bae1dSRodney W. Grimes 
27754e94f402SAlan Cox 		entry = *out_entry;
2776df8bae1dSRodney W. Grimes 	}
2777b7b2aac2SJohn Dyson 
2778df8bae1dSRodney W. Grimes 	/*
2779df8bae1dSRodney W. Grimes 	 * Handle submaps.
2780df8bae1dSRodney W. Grimes 	 */
2781afa07f7eSJohn Dyson 	if (entry->eflags & MAP_ENTRY_IS_SUB_MAP) {
2782df8bae1dSRodney W. Grimes 		vm_map_t old_map = map;
2783df8bae1dSRodney W. Grimes 
2784df8bae1dSRodney W. Grimes 		*var_map = map = entry->object.sub_map;
2785df8bae1dSRodney W. Grimes 		vm_map_unlock_read(old_map);
2786df8bae1dSRodney W. Grimes 		goto RetryLookup;
2787df8bae1dSRodney W. Grimes 	}
2788a04c970aSJohn Dyson 
2789df8bae1dSRodney W. Grimes 	/*
27900d94caffSDavid Greenman 	 * Check whether this task is allowed to have this page.
2791a04c970aSJohn Dyson 	 * Note the special case for MAP_ENTRY_COW
2792a04c970aSJohn Dyson 	 * pages with an override.  This is to implement a forced
2793a04c970aSJohn Dyson 	 * COW for debuggers.
2794df8bae1dSRodney W. Grimes 	 */
2795480ba2f5SJohn Dyson 	if (fault_type & VM_PROT_OVERRIDE_WRITE)
2796480ba2f5SJohn Dyson 		prot = entry->max_protection;
2797480ba2f5SJohn Dyson 	else
2798df8bae1dSRodney W. Grimes 		prot = entry->protection;
279947221757SJohn Dyson 	fault_type &= (VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
280047221757SJohn Dyson 	if ((fault_type & prot) != fault_type) {
280147221757SJohn Dyson 			RETURN(KERN_PROTECTION_FAILURE);
280247221757SJohn Dyson 	}
28032ed14a92SAlan Cox 	if ((entry->eflags & MAP_ENTRY_USER_WIRED) &&
280447221757SJohn Dyson 	    (entry->eflags & MAP_ENTRY_COW) &&
28052ed14a92SAlan Cox 	    (fault_type & VM_PROT_WRITE) &&
280647221757SJohn Dyson 	    (fault_typea & VM_PROT_OVERRIDE_WRITE) == 0) {
2807df8bae1dSRodney W. Grimes 		RETURN(KERN_PROTECTION_FAILURE);
2808a04c970aSJohn Dyson 	}
2809df8bae1dSRodney W. Grimes 
2810df8bae1dSRodney W. Grimes 	/*
28110d94caffSDavid Greenman 	 * If this page is not pageable, we have to get it for all possible
28120d94caffSDavid Greenman 	 * accesses.
2813df8bae1dSRodney W. Grimes 	 */
281405f0fdd2SPoul-Henning Kamp 	*wired = (entry->wired_count != 0);
281505f0fdd2SPoul-Henning Kamp 	if (*wired)
2816df8bae1dSRodney W. Grimes 		prot = fault_type = entry->protection;
2817df8bae1dSRodney W. Grimes 
2818df8bae1dSRodney W. Grimes 	/*
2819df8bae1dSRodney W. Grimes 	 * If the entry was copy-on-write, we either ...
2820df8bae1dSRodney W. Grimes 	 */
2821afa07f7eSJohn Dyson 	if (entry->eflags & MAP_ENTRY_NEEDS_COPY) {
2822df8bae1dSRodney W. Grimes 		/*
28230d94caffSDavid Greenman 		 * If we want to write the page, we may as well handle that
2824ad5fca3bSAlan Cox 		 * now since we've got the map locked.
2825df8bae1dSRodney W. Grimes 		 *
28260d94caffSDavid Greenman 		 * If we don't need to write the page, we just demote the
28270d94caffSDavid Greenman 		 * permissions allowed.
2828df8bae1dSRodney W. Grimes 		 */
2829df8bae1dSRodney W. Grimes 		if (fault_type & VM_PROT_WRITE) {
2830df8bae1dSRodney W. Grimes 			/*
28310d94caffSDavid Greenman 			 * Make a new object, and place it in the object
28320d94caffSDavid Greenman 			 * chain.  Note that no new references have appeared
2833ad5fca3bSAlan Cox 			 * -- one just moved from the map to the new
28340d94caffSDavid Greenman 			 * object.
2835df8bae1dSRodney W. Grimes 			 */
283625adb370SBrian Feldman 			if (vm_map_lock_upgrade(map))
2837df8bae1dSRodney W. Grimes 				goto RetryLookup;
28389917e010SAlan Cox 
2839df8bae1dSRodney W. Grimes 			vm_object_shadow(
2840df8bae1dSRodney W. Grimes 			    &entry->object.vm_object,
2841df8bae1dSRodney W. Grimes 			    &entry->offset,
2842c2e11a03SJohn Dyson 			    atop(entry->end - entry->start));
2843afa07f7eSJohn Dyson 			entry->eflags &= ~MAP_ENTRY_NEEDS_COPY;
28449917e010SAlan Cox 
28459b09b6c7SMatthew Dillon 			vm_map_lock_downgrade(map);
28460d94caffSDavid Greenman 		} else {
2847df8bae1dSRodney W. Grimes 			/*
28480d94caffSDavid Greenman 			 * We're attempting to read a copy-on-write page --
28490d94caffSDavid Greenman 			 * don't allow writes.
2850df8bae1dSRodney W. Grimes 			 */
28512d8acc0fSJohn Dyson 			prot &= ~VM_PROT_WRITE;
2852df8bae1dSRodney W. Grimes 		}
2853df8bae1dSRodney W. Grimes 	}
28542d8acc0fSJohn Dyson 
2855df8bae1dSRodney W. Grimes 	/*
2856df8bae1dSRodney W. Grimes 	 * Create an object if necessary.
2857df8bae1dSRodney W. Grimes 	 */
28584e71e795SMatthew Dillon 	if (entry->object.vm_object == NULL &&
28594e71e795SMatthew Dillon 	    !map->system_map) {
286025adb370SBrian Feldman 		if (vm_map_lock_upgrade(map))
2861df8bae1dSRodney W. Grimes 			goto RetryLookup;
286224a1cce3SDavid Greenman 		entry->object.vm_object = vm_object_allocate(OBJT_DEFAULT,
2863c2e11a03SJohn Dyson 		    atop(entry->end - entry->start));
2864df8bae1dSRodney W. Grimes 		entry->offset = 0;
28659b09b6c7SMatthew Dillon 		vm_map_lock_downgrade(map);
2866df8bae1dSRodney W. Grimes 	}
2867b5b40fa6SJohn Dyson 
2868df8bae1dSRodney W. Grimes 	/*
28690d94caffSDavid Greenman 	 * Return the object/offset from this entry.  If the entry was
28700d94caffSDavid Greenman 	 * copy-on-write or empty, it has been fixed up.
2871df8bae1dSRodney W. Grimes 	 */
28729b09b6c7SMatthew Dillon 	*pindex = OFF_TO_IDX((vaddr - entry->start) + entry->offset);
2873df8bae1dSRodney W. Grimes 	*object = entry->object.vm_object;
2874df8bae1dSRodney W. Grimes 
2875df8bae1dSRodney W. Grimes 	/*
2876df8bae1dSRodney W. Grimes 	 * Return whether this is the only map sharing this data.
2877df8bae1dSRodney W. Grimes 	 */
2878df8bae1dSRodney W. Grimes 	*out_prot = prot;
2879df8bae1dSRodney W. Grimes 	return (KERN_SUCCESS);
2880df8bae1dSRodney W. Grimes 
2881df8bae1dSRodney W. Grimes #undef	RETURN
2882df8bae1dSRodney W. Grimes }
2883df8bae1dSRodney W. Grimes 
2884df8bae1dSRodney W. Grimes /*
2885df8bae1dSRodney W. Grimes  *	vm_map_lookup_done:
2886df8bae1dSRodney W. Grimes  *
2887df8bae1dSRodney W. Grimes  *	Releases locks acquired by a vm_map_lookup
2888df8bae1dSRodney W. Grimes  *	(according to the handle returned by that lookup).
2889df8bae1dSRodney W. Grimes  */
28900d94caffSDavid Greenman void
28911b40f8c0SMatthew Dillon vm_map_lookup_done(vm_map_t map, vm_map_entry_t entry)
2892df8bae1dSRodney W. Grimes {
2893df8bae1dSRodney W. Grimes 	/*
2894df8bae1dSRodney W. Grimes 	 * Unlock the main-level map
2895df8bae1dSRodney W. Grimes 	 */
2896df8bae1dSRodney W. Grimes 	vm_map_unlock_read(map);
2897df8bae1dSRodney W. Grimes }
2898df8bae1dSRodney W. Grimes 
2899c7c34a24SBruce Evans #include "opt_ddb.h"
2900c3cb3e12SDavid Greenman #ifdef DDB
2901c7c34a24SBruce Evans #include <sys/kernel.h>
2902c7c34a24SBruce Evans 
2903c7c34a24SBruce Evans #include <ddb/ddb.h>
2904c7c34a24SBruce Evans 
2905df8bae1dSRodney W. Grimes /*
2906df8bae1dSRodney W. Grimes  *	vm_map_print:	[ debug ]
2907df8bae1dSRodney W. Grimes  */
2908c7c34a24SBruce Evans DB_SHOW_COMMAND(map, vm_map_print)
2909df8bae1dSRodney W. Grimes {
291095e5e988SJohn Dyson 	static int nlines;
2911c7c34a24SBruce Evans 	/* XXX convert args. */
2912c0877f10SJohn Dyson 	vm_map_t map = (vm_map_t)addr;
2913c7c34a24SBruce Evans 	boolean_t full = have_addr;
2914df8bae1dSRodney W. Grimes 
2915c0877f10SJohn Dyson 	vm_map_entry_t entry;
2916c7c34a24SBruce Evans 
2917e5f251d2SAlan Cox 	db_iprintf("Task map %p: pmap=%p, nentries=%d, version=%u\n",
2918e5f251d2SAlan Cox 	    (void *)map,
2919101eeb7fSBruce Evans 	    (void *)map->pmap, map->nentries, map->timestamp);
292095e5e988SJohn Dyson 	nlines++;
2921df8bae1dSRodney W. Grimes 
2922c7c34a24SBruce Evans 	if (!full && db_indent)
2923df8bae1dSRodney W. Grimes 		return;
2924df8bae1dSRodney W. Grimes 
2925c7c34a24SBruce Evans 	db_indent += 2;
2926df8bae1dSRodney W. Grimes 	for (entry = map->header.next; entry != &map->header;
2927df8bae1dSRodney W. Grimes 	    entry = entry->next) {
2928fc62ef1fSBruce Evans 		db_iprintf("map entry %p: start=%p, end=%p\n",
2929fc62ef1fSBruce Evans 		    (void *)entry, (void *)entry->start, (void *)entry->end);
293095e5e988SJohn Dyson 		nlines++;
2931e5f251d2SAlan Cox 		{
2932df8bae1dSRodney W. Grimes 			static char *inheritance_name[4] =
2933df8bae1dSRodney W. Grimes 			{"share", "copy", "none", "donate_copy"};
29340d94caffSDavid Greenman 
293595e5e988SJohn Dyson 			db_iprintf(" prot=%x/%x/%s",
2936df8bae1dSRodney W. Grimes 			    entry->protection,
2937df8bae1dSRodney W. Grimes 			    entry->max_protection,
29388aef1712SMatthew Dillon 			    inheritance_name[(int)(unsigned char)entry->inheritance]);
2939df8bae1dSRodney W. Grimes 			if (entry->wired_count != 0)
294095e5e988SJohn Dyson 				db_printf(", wired");
2941df8bae1dSRodney W. Grimes 		}
29429fdfe602SMatthew Dillon 		if (entry->eflags & MAP_ENTRY_IS_SUB_MAP) {
2943cd034a5bSMaxime Henrion 			db_printf(", share=%p, offset=0x%jx\n",
29449fdfe602SMatthew Dillon 			    (void *)entry->object.sub_map,
2945cd034a5bSMaxime Henrion 			    (uintmax_t)entry->offset);
294695e5e988SJohn Dyson 			nlines++;
2947df8bae1dSRodney W. Grimes 			if ((entry->prev == &map->header) ||
29489fdfe602SMatthew Dillon 			    (entry->prev->object.sub_map !=
29499fdfe602SMatthew Dillon 				entry->object.sub_map)) {
2950c7c34a24SBruce Evans 				db_indent += 2;
2951101eeb7fSBruce Evans 				vm_map_print((db_expr_t)(intptr_t)
29529fdfe602SMatthew Dillon 					     entry->object.sub_map,
2953914181e7SBruce Evans 					     full, 0, (char *)0);
2954c7c34a24SBruce Evans 				db_indent -= 2;
2955df8bae1dSRodney W. Grimes 			}
29560d94caffSDavid Greenman 		} else {
2957cd034a5bSMaxime Henrion 			db_printf(", object=%p, offset=0x%jx",
2958101eeb7fSBruce Evans 			    (void *)entry->object.vm_object,
2959cd034a5bSMaxime Henrion 			    (uintmax_t)entry->offset);
2960afa07f7eSJohn Dyson 			if (entry->eflags & MAP_ENTRY_COW)
2961c7c34a24SBruce Evans 				db_printf(", copy (%s)",
2962afa07f7eSJohn Dyson 				    (entry->eflags & MAP_ENTRY_NEEDS_COPY) ? "needed" : "done");
2963c7c34a24SBruce Evans 			db_printf("\n");
296495e5e988SJohn Dyson 			nlines++;
2965df8bae1dSRodney W. Grimes 
2966df8bae1dSRodney W. Grimes 			if ((entry->prev == &map->header) ||
2967df8bae1dSRodney W. Grimes 			    (entry->prev->object.vm_object !=
2968df8bae1dSRodney W. Grimes 				entry->object.vm_object)) {
2969c7c34a24SBruce Evans 				db_indent += 2;
2970101eeb7fSBruce Evans 				vm_object_print((db_expr_t)(intptr_t)
2971101eeb7fSBruce Evans 						entry->object.vm_object,
2972914181e7SBruce Evans 						full, 0, (char *)0);
297395e5e988SJohn Dyson 				nlines += 4;
2974c7c34a24SBruce Evans 				db_indent -= 2;
2975df8bae1dSRodney W. Grimes 			}
2976df8bae1dSRodney W. Grimes 		}
2977df8bae1dSRodney W. Grimes 	}
2978c7c34a24SBruce Evans 	db_indent -= 2;
297995e5e988SJohn Dyson 	if (db_indent == 0)
298095e5e988SJohn Dyson 		nlines = 0;
2981df8bae1dSRodney W. Grimes }
298295e5e988SJohn Dyson 
298395e5e988SJohn Dyson 
298495e5e988SJohn Dyson DB_SHOW_COMMAND(procvm, procvm)
298595e5e988SJohn Dyson {
298695e5e988SJohn Dyson 	struct proc *p;
298795e5e988SJohn Dyson 
298895e5e988SJohn Dyson 	if (have_addr) {
298995e5e988SJohn Dyson 		p = (struct proc *) addr;
299095e5e988SJohn Dyson 	} else {
299195e5e988SJohn Dyson 		p = curproc;
299295e5e988SJohn Dyson 	}
299395e5e988SJohn Dyson 
2994ac1e407bSBruce Evans 	db_printf("p = %p, vmspace = %p, map = %p, pmap = %p\n",
2995ac1e407bSBruce Evans 	    (void *)p, (void *)p->p_vmspace, (void *)&p->p_vmspace->vm_map,
2996b1028ad1SLuoqi Chen 	    (void *)vmspace_pmap(p->p_vmspace));
299795e5e988SJohn Dyson 
2998101eeb7fSBruce Evans 	vm_map_print((db_expr_t)(intptr_t)&p->p_vmspace->vm_map, 1, 0, NULL);
299995e5e988SJohn Dyson }
300095e5e988SJohn Dyson 
3001c7c34a24SBruce Evans #endif /* DDB */
3002