xref: /csrg-svn/sys/vm/vm_object.c (revision 45748)
1*45748Smckusick /*
2*45748Smckusick  * Copyright (c) 1985, Avadis Tevanian, Jr., Michael Wayne Young
3*45748Smckusick  * Copyright (c) 1987 Carnegie-Mellon University
4*45748Smckusick  * Copyright (c) 1991 Regents of the University of California.
5*45748Smckusick  * All rights reserved.
6*45748Smckusick  *
7*45748Smckusick  * This code is derived from software contributed to Berkeley by
8*45748Smckusick  * The Mach Operating System project at Carnegie-Mellon University.
9*45748Smckusick  *
10*45748Smckusick  * The CMU software License Agreement specifies the terms and conditions
11*45748Smckusick  * for use and redistribution.
12*45748Smckusick  *
13*45748Smckusick  *	@(#)vm_object.c	7.1 (Berkeley) 12/05/90
14*45748Smckusick  */
15*45748Smckusick 
16*45748Smckusick /*
17*45748Smckusick  *	Virtual memory object module.
18*45748Smckusick  */
19*45748Smckusick 
20*45748Smckusick #include "param.h"
21*45748Smckusick #include "malloc.h"
22*45748Smckusick #include "../vm/vm_param.h"
23*45748Smckusick #include "lock.h"
24*45748Smckusick #include "../vm/vm_page.h"
25*45748Smckusick #include "../vm/vm_map.h"
26*45748Smckusick #include "../vm/vm_object.h"
27*45748Smckusick 
28*45748Smckusick /*
29*45748Smckusick  *	Virtual memory objects maintain the actual data
30*45748Smckusick  *	associated with allocated virtual memory.  A given
31*45748Smckusick  *	page of memory exists within exactly one object.
32*45748Smckusick  *
33*45748Smckusick  *	An object is only deallocated when all "references"
34*45748Smckusick  *	are given up.  Only one "reference" to a given
35*45748Smckusick  *	region of an object should be writeable.
36*45748Smckusick  *
37*45748Smckusick  *	Associated with each object is a list of all resident
38*45748Smckusick  *	memory pages belonging to that object; this list is
39*45748Smckusick  *	maintained by the "vm_page" module, and locked by the object's
40*45748Smckusick  *	lock.
41*45748Smckusick  *
42*45748Smckusick  *	Each object also records a "pager" routine which is
43*45748Smckusick  *	used to retrieve (and store) pages to the proper backing
44*45748Smckusick  *	storage.  In addition, objects may be backed by other
45*45748Smckusick  *	objects from which they were virtual-copied.
46*45748Smckusick  *
47*45748Smckusick  *	The only items within the object structure which are
48*45748Smckusick  *	modified after time of creation are:
49*45748Smckusick  *		reference count		locked by object's lock
50*45748Smckusick  *		pager routine		locked by object's lock
51*45748Smckusick  *
52*45748Smckusick  */
53*45748Smckusick 
54*45748Smckusick struct vm_object	kernel_object_store;
55*45748Smckusick struct vm_object	kmem_object_store;
56*45748Smckusick 
57*45748Smckusick #define	VM_OBJECT_HASH_COUNT	157
58*45748Smckusick 
59*45748Smckusick int		vm_cache_max = 100;	/* can patch if necessary */
60*45748Smckusick queue_head_t	vm_object_hashtable[VM_OBJECT_HASH_COUNT];
61*45748Smckusick 
62*45748Smckusick long	object_collapses = 0;
63*45748Smckusick long	object_bypasses  = 0;
64*45748Smckusick 
65*45748Smckusick /*
66*45748Smckusick  *	vm_object_init:
67*45748Smckusick  *
68*45748Smckusick  *	Initialize the VM objects module.
69*45748Smckusick  */
70*45748Smckusick void vm_object_init()
71*45748Smckusick {
72*45748Smckusick 	register int	i;
73*45748Smckusick 
74*45748Smckusick 	queue_init(&vm_object_cached_list);
75*45748Smckusick 	queue_init(&vm_object_list);
76*45748Smckusick 	vm_object_count = 0;
77*45748Smckusick 	simple_lock_init(&vm_cache_lock);
78*45748Smckusick 	simple_lock_init(&vm_object_list_lock);
79*45748Smckusick 
80*45748Smckusick 	for (i = 0; i < VM_OBJECT_HASH_COUNT; i++)
81*45748Smckusick 		queue_init(&vm_object_hashtable[i]);
82*45748Smckusick 
83*45748Smckusick 	kernel_object = &kernel_object_store;
84*45748Smckusick 	_vm_object_allocate(VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS,
85*45748Smckusick 			kernel_object);
86*45748Smckusick 
87*45748Smckusick 	kmem_object = &kmem_object_store;
88*45748Smckusick 	_vm_object_allocate(VM_KMEM_SIZE + VM_MBUF_SIZE, kmem_object);
89*45748Smckusick }
90*45748Smckusick 
91*45748Smckusick /*
92*45748Smckusick  *	vm_object_allocate:
93*45748Smckusick  *
94*45748Smckusick  *	Returns a new object with the given size.
95*45748Smckusick  */
96*45748Smckusick 
97*45748Smckusick vm_object_t vm_object_allocate(size)
98*45748Smckusick 	vm_size_t	size;
99*45748Smckusick {
100*45748Smckusick 	register vm_object_t	result;
101*45748Smckusick 
102*45748Smckusick 	result = (vm_object_t)
103*45748Smckusick 		malloc((u_long)sizeof *result, M_VMOBJ, M_WAITOK);
104*45748Smckusick 
105*45748Smckusick 	_vm_object_allocate(size, result);
106*45748Smckusick 
107*45748Smckusick 	return(result);
108*45748Smckusick }
109*45748Smckusick 
110*45748Smckusick _vm_object_allocate(size, object)
111*45748Smckusick 	vm_size_t		size;
112*45748Smckusick 	register vm_object_t	object;
113*45748Smckusick {
114*45748Smckusick 	queue_init(&object->memq);
115*45748Smckusick 	vm_object_lock_init(object);
116*45748Smckusick 	object->ref_count = 1;
117*45748Smckusick 	object->resident_page_count = 0;
118*45748Smckusick 	object->size = size;
119*45748Smckusick 	object->can_persist = FALSE;
120*45748Smckusick 	object->paging_in_progress = 0;
121*45748Smckusick 	object->copy = VM_OBJECT_NULL;
122*45748Smckusick 
123*45748Smckusick 	/*
124*45748Smckusick 	 *	Object starts out read-write, with no pager.
125*45748Smckusick 	 */
126*45748Smckusick 
127*45748Smckusick 	object->pager = vm_pager_null;
128*45748Smckusick 	object->pager_ready = FALSE;
129*45748Smckusick 	object->internal = TRUE;	/* vm_allocate_with_pager will reset */
130*45748Smckusick 	object->paging_offset = 0;
131*45748Smckusick 	object->shadow = VM_OBJECT_NULL;
132*45748Smckusick 	object->shadow_offset = (vm_offset_t) 0;
133*45748Smckusick 
134*45748Smckusick 	simple_lock(&vm_object_list_lock);
135*45748Smckusick 	queue_enter(&vm_object_list, object, vm_object_t, object_list);
136*45748Smckusick 	vm_object_count++;
137*45748Smckusick 	simple_unlock(&vm_object_list_lock);
138*45748Smckusick }
139*45748Smckusick 
140*45748Smckusick /*
141*45748Smckusick  *	vm_object_reference:
142*45748Smckusick  *
143*45748Smckusick  *	Gets another reference to the given object.
144*45748Smckusick  */
145*45748Smckusick void vm_object_reference(object)
146*45748Smckusick 	register vm_object_t	object;
147*45748Smckusick {
148*45748Smckusick 	if (object == VM_OBJECT_NULL)
149*45748Smckusick 		return;
150*45748Smckusick 
151*45748Smckusick 	vm_object_lock(object);
152*45748Smckusick 	object->ref_count++;
153*45748Smckusick 	vm_object_unlock(object);
154*45748Smckusick }
155*45748Smckusick 
156*45748Smckusick /*
157*45748Smckusick  *	vm_object_deallocate:
158*45748Smckusick  *
159*45748Smckusick  *	Release a reference to the specified object,
160*45748Smckusick  *	gained either through a vm_object_allocate
161*45748Smckusick  *	or a vm_object_reference call.  When all references
162*45748Smckusick  *	are gone, storage associated with this object
163*45748Smckusick  *	may be relinquished.
164*45748Smckusick  *
165*45748Smckusick  *	No object may be locked.
166*45748Smckusick  */
167*45748Smckusick void vm_object_deallocate(object)
168*45748Smckusick 	register vm_object_t	object;
169*45748Smckusick {
170*45748Smckusick 	vm_object_t	temp;
171*45748Smckusick 
172*45748Smckusick 	while (object != VM_OBJECT_NULL) {
173*45748Smckusick 
174*45748Smckusick 		/*
175*45748Smckusick 		 *	The cache holds a reference (uncounted) to
176*45748Smckusick 		 *	the object; we must lock it before removing
177*45748Smckusick 		 *	the object.
178*45748Smckusick 		 */
179*45748Smckusick 
180*45748Smckusick 		vm_object_cache_lock();
181*45748Smckusick 
182*45748Smckusick 		/*
183*45748Smckusick 		 *	Lose the reference
184*45748Smckusick 		 */
185*45748Smckusick 		vm_object_lock(object);
186*45748Smckusick 		if (--(object->ref_count) != 0) {
187*45748Smckusick 
188*45748Smckusick 			/*
189*45748Smckusick 			 *	If there are still references, then
190*45748Smckusick 			 *	we are done.
191*45748Smckusick 			 */
192*45748Smckusick 			vm_object_unlock(object);
193*45748Smckusick 			vm_object_cache_unlock();
194*45748Smckusick 			return;
195*45748Smckusick 		}
196*45748Smckusick 
197*45748Smckusick 		/*
198*45748Smckusick 		 *	See if this object can persist.  If so, enter
199*45748Smckusick 		 *	it in the cache, then deactivate all of its
200*45748Smckusick 		 *	pages.
201*45748Smckusick 		 */
202*45748Smckusick 
203*45748Smckusick 		if (object->can_persist) {
204*45748Smckusick 
205*45748Smckusick 			queue_enter(&vm_object_cached_list, object,
206*45748Smckusick 				vm_object_t, cached_list);
207*45748Smckusick 			vm_object_cached++;
208*45748Smckusick 			vm_object_cache_unlock();
209*45748Smckusick 
210*45748Smckusick 			vm_object_deactivate_pages(object);
211*45748Smckusick 			vm_object_unlock(object);
212*45748Smckusick 
213*45748Smckusick 			vm_object_cache_trim();
214*45748Smckusick 			return;
215*45748Smckusick 		}
216*45748Smckusick 
217*45748Smckusick 		/*
218*45748Smckusick 		 *	Make sure no one can look us up now.
219*45748Smckusick 		 */
220*45748Smckusick 		vm_object_remove(object->pager);
221*45748Smckusick 		vm_object_cache_unlock();
222*45748Smckusick 
223*45748Smckusick 		temp = object->shadow;
224*45748Smckusick 		vm_object_terminate(object);
225*45748Smckusick 			/* unlocks and deallocates object */
226*45748Smckusick 		object = temp;
227*45748Smckusick 	}
228*45748Smckusick }
229*45748Smckusick 
230*45748Smckusick 
231*45748Smckusick /*
232*45748Smckusick  *	vm_object_terminate actually destroys the specified object, freeing
233*45748Smckusick  *	up all previously used resources.
234*45748Smckusick  *
235*45748Smckusick  *	The object must be locked.
236*45748Smckusick  */
237*45748Smckusick void vm_object_terminate(object)
238*45748Smckusick 	register vm_object_t	object;
239*45748Smckusick {
240*45748Smckusick 	register vm_page_t	p;
241*45748Smckusick 	vm_object_t		shadow_object;
242*45748Smckusick 
243*45748Smckusick 	/*
244*45748Smckusick 	 *	Detach the object from its shadow if we are the shadow's
245*45748Smckusick 	 *	copy.
246*45748Smckusick 	 */
247*45748Smckusick 	if ((shadow_object = object->shadow) != VM_OBJECT_NULL) {
248*45748Smckusick 		vm_object_lock(shadow_object);
249*45748Smckusick 		if (shadow_object->copy == object)
250*45748Smckusick 			shadow_object->copy = VM_OBJECT_NULL;
251*45748Smckusick #if 0
252*45748Smckusick 		else if (shadow_object->copy != VM_OBJECT_NULL)
253*45748Smckusick 			panic("vm_object_terminate: copy/shadow inconsistency");
254*45748Smckusick #endif
255*45748Smckusick 		vm_object_unlock(shadow_object);
256*45748Smckusick 	}
257*45748Smckusick 
258*45748Smckusick 	/*
259*45748Smckusick 	 *	Wait until the pageout daemon is through
260*45748Smckusick 	 *	with the object.
261*45748Smckusick 	 */
262*45748Smckusick 
263*45748Smckusick 	while (object->paging_in_progress != 0) {
264*45748Smckusick 		vm_object_sleep(object, object, FALSE);
265*45748Smckusick 		vm_object_lock(object);
266*45748Smckusick 	}
267*45748Smckusick 
268*45748Smckusick 
269*45748Smckusick 	/*
270*45748Smckusick 	 *	While the paging system is locked,
271*45748Smckusick 	 *	pull the object's pages off the active
272*45748Smckusick 	 *	and inactive queues.  This keeps the
273*45748Smckusick 	 *	pageout daemon from playing with them
274*45748Smckusick 	 *	during vm_pager_deallocate.
275*45748Smckusick 	 *
276*45748Smckusick 	 *	We can't free the pages yet, because the
277*45748Smckusick 	 *	object's pager may have to write them out
278*45748Smckusick 	 *	before deallocating the paging space.
279*45748Smckusick 	 */
280*45748Smckusick 
281*45748Smckusick 	p = (vm_page_t) queue_first(&object->memq);
282*45748Smckusick 	while (!queue_end(&object->memq, (queue_entry_t) p)) {
283*45748Smckusick 		VM_PAGE_CHECK(p);
284*45748Smckusick 
285*45748Smckusick 		vm_page_lock_queues();
286*45748Smckusick 		if (p->active) {
287*45748Smckusick 			queue_remove(&vm_page_queue_active, p, vm_page_t,
288*45748Smckusick 						pageq);
289*45748Smckusick 			p->active = FALSE;
290*45748Smckusick 			vm_page_active_count--;
291*45748Smckusick 		}
292*45748Smckusick 
293*45748Smckusick 		if (p->inactive) {
294*45748Smckusick 			queue_remove(&vm_page_queue_inactive, p, vm_page_t,
295*45748Smckusick 						pageq);
296*45748Smckusick 			p->inactive = FALSE;
297*45748Smckusick 			vm_page_inactive_count--;
298*45748Smckusick 		}
299*45748Smckusick 		vm_page_unlock_queues();
300*45748Smckusick 		p = (vm_page_t) queue_next(&p->listq);
301*45748Smckusick 	}
302*45748Smckusick 
303*45748Smckusick 	vm_object_unlock(object);
304*45748Smckusick 
305*45748Smckusick 	if (object->paging_in_progress != 0)
306*45748Smckusick 		panic("vm_object_deallocate: pageout in progress");
307*45748Smckusick 
308*45748Smckusick 	/*
309*45748Smckusick 	 *	Clean and free the pages, as appropriate.
310*45748Smckusick 	 *	All references to the object are gone,
311*45748Smckusick 	 *	so we don't need to lock it.
312*45748Smckusick 	 */
313*45748Smckusick 
314*45748Smckusick 	if (!object->internal) {
315*45748Smckusick 		vm_object_lock(object);
316*45748Smckusick 		vm_object_page_clean(object, 0, 0);
317*45748Smckusick 		vm_object_unlock(object);
318*45748Smckusick 	}
319*45748Smckusick 	while (!queue_empty(&object->memq)) {
320*45748Smckusick 		p = (vm_page_t) queue_first(&object->memq);
321*45748Smckusick 
322*45748Smckusick 		VM_PAGE_CHECK(p);
323*45748Smckusick 
324*45748Smckusick 		vm_page_lock_queues();
325*45748Smckusick 		vm_page_free(p);
326*45748Smckusick 		vm_page_unlock_queues();
327*45748Smckusick 	}
328*45748Smckusick 
329*45748Smckusick 	/*
330*45748Smckusick 	 *	Let the pager know object is dead.
331*45748Smckusick 	 */
332*45748Smckusick 
333*45748Smckusick 	if (object->pager != vm_pager_null)
334*45748Smckusick 		vm_pager_deallocate(object->pager);
335*45748Smckusick 
336*45748Smckusick 
337*45748Smckusick 	simple_lock(&vm_object_list_lock);
338*45748Smckusick 	queue_remove(&vm_object_list, object, vm_object_t, object_list);
339*45748Smckusick 	vm_object_count--;
340*45748Smckusick 	simple_unlock(&vm_object_list_lock);
341*45748Smckusick 
342*45748Smckusick 	/*
343*45748Smckusick 	 *	Free the space for the object.
344*45748Smckusick 	 */
345*45748Smckusick 
346*45748Smckusick 	free((caddr_t)object, M_VMOBJ);
347*45748Smckusick }
348*45748Smckusick 
349*45748Smckusick /*
350*45748Smckusick  *	vm_object_page_clean
351*45748Smckusick  *
352*45748Smckusick  *	Clean all dirty pages in the specified range of object.
353*45748Smckusick  *	Leaves page on whatever queue it is currently on.
354*45748Smckusick  *
355*45748Smckusick  *	Odd semantics: if start == end, we clean everything.
356*45748Smckusick  *
357*45748Smckusick  *	The object must be locked.
358*45748Smckusick  */
359*45748Smckusick vm_object_page_clean(object, start, end)
360*45748Smckusick 	register vm_object_t	object;
361*45748Smckusick 	register vm_offset_t	start;
362*45748Smckusick 	register vm_offset_t	end;
363*45748Smckusick {
364*45748Smckusick 	register vm_page_t	p;
365*45748Smckusick 
366*45748Smckusick 	if (object->pager == vm_pager_null)
367*45748Smckusick 		return;
368*45748Smckusick 
369*45748Smckusick again:
370*45748Smckusick 	p = (vm_page_t) queue_first(&object->memq);
371*45748Smckusick 	while (!queue_end(&object->memq, (queue_entry_t) p)) {
372*45748Smckusick 		if (start == end ||
373*45748Smckusick 		    p->offset >= start && p->offset < end) {
374*45748Smckusick 			if (p->clean && pmap_is_modified(VM_PAGE_TO_PHYS(p)))
375*45748Smckusick 				p->clean = FALSE;
376*45748Smckusick 			pmap_remove_all(VM_PAGE_TO_PHYS(p));
377*45748Smckusick 			if (!p->clean) {
378*45748Smckusick 				p->busy = TRUE;
379*45748Smckusick 				object->paging_in_progress++;
380*45748Smckusick 				vm_object_unlock(object);
381*45748Smckusick 				(void) vm_pager_put(object->pager, p, TRUE);
382*45748Smckusick 				vm_object_lock(object);
383*45748Smckusick 				object->paging_in_progress--;
384*45748Smckusick 				p->busy = FALSE;
385*45748Smckusick 				PAGE_WAKEUP(p);
386*45748Smckusick 				goto again;
387*45748Smckusick 			}
388*45748Smckusick 		}
389*45748Smckusick 		p = (vm_page_t) queue_next(&p->listq);
390*45748Smckusick 	}
391*45748Smckusick }
392*45748Smckusick 
393*45748Smckusick /*
394*45748Smckusick  *	vm_object_deactivate_pages
395*45748Smckusick  *
396*45748Smckusick  *	Deactivate all pages in the specified object.  (Keep its pages
397*45748Smckusick  *	in memory even though it is no longer referenced.)
398*45748Smckusick  *
399*45748Smckusick  *	The object must be locked.
400*45748Smckusick  */
401*45748Smckusick vm_object_deactivate_pages(object)
402*45748Smckusick 	register vm_object_t	object;
403*45748Smckusick {
404*45748Smckusick 	register vm_page_t	p, next;
405*45748Smckusick 
406*45748Smckusick 	p = (vm_page_t) queue_first(&object->memq);
407*45748Smckusick 	while (!queue_end(&object->memq, (queue_entry_t) p)) {
408*45748Smckusick 		next = (vm_page_t) queue_next(&p->listq);
409*45748Smckusick 		vm_page_lock_queues();
410*45748Smckusick 		vm_page_deactivate(p);
411*45748Smckusick 		vm_page_unlock_queues();
412*45748Smckusick 		p = next;
413*45748Smckusick 	}
414*45748Smckusick }
415*45748Smckusick 
416*45748Smckusick /*
417*45748Smckusick  *	Trim the object cache to size.
418*45748Smckusick  */
419*45748Smckusick vm_object_cache_trim()
420*45748Smckusick {
421*45748Smckusick 	register vm_object_t	object;
422*45748Smckusick 
423*45748Smckusick 	vm_object_cache_lock();
424*45748Smckusick 	while (vm_object_cached > vm_cache_max) {
425*45748Smckusick 		object = (vm_object_t) queue_first(&vm_object_cached_list);
426*45748Smckusick 		vm_object_cache_unlock();
427*45748Smckusick 
428*45748Smckusick 		if (object != vm_object_lookup(object->pager))
429*45748Smckusick 			panic("vm_object_deactivate: I'm sooo confused.");
430*45748Smckusick 
431*45748Smckusick 		pager_cache(object, FALSE);
432*45748Smckusick 
433*45748Smckusick 		vm_object_cache_lock();
434*45748Smckusick 	}
435*45748Smckusick 	vm_object_cache_unlock();
436*45748Smckusick }
437*45748Smckusick 
438*45748Smckusick 
439*45748Smckusick /*
440*45748Smckusick  *	vm_object_shutdown()
441*45748Smckusick  *
442*45748Smckusick  *	Shut down the object system.  Unfortunately, while we
443*45748Smckusick  *	may be trying to do this, init is happily waiting for
444*45748Smckusick  *	processes to exit, and therefore will be causing some objects
445*45748Smckusick  *	to be deallocated.  To handle this, we gain a fake reference
446*45748Smckusick  *	to all objects we release paging areas for.  This will prevent
447*45748Smckusick  *	a duplicate deallocation.  This routine is probably full of
448*45748Smckusick  *	race conditions!
449*45748Smckusick  */
450*45748Smckusick 
451*45748Smckusick void vm_object_shutdown()
452*45748Smckusick {
453*45748Smckusick 	register vm_object_t	object;
454*45748Smckusick 
455*45748Smckusick 	/*
456*45748Smckusick 	 *	Clean up the object cache *before* we screw up the reference
457*45748Smckusick 	 *	counts on all of the objects.
458*45748Smckusick 	 */
459*45748Smckusick 
460*45748Smckusick 	vm_object_cache_clear();
461*45748Smckusick 
462*45748Smckusick 	printf("free paging spaces: ");
463*45748Smckusick 
464*45748Smckusick 	/*
465*45748Smckusick 	 *	First we gain a reference to each object so that
466*45748Smckusick 	 *	no one else will deallocate them.
467*45748Smckusick 	 */
468*45748Smckusick 
469*45748Smckusick 	simple_lock(&vm_object_list_lock);
470*45748Smckusick 	object = (vm_object_t) queue_first(&vm_object_list);
471*45748Smckusick 	while (!queue_end(&vm_object_list, (queue_entry_t) object)) {
472*45748Smckusick 		vm_object_reference(object);
473*45748Smckusick 		object = (vm_object_t) queue_next(&object->object_list);
474*45748Smckusick 	}
475*45748Smckusick 	simple_unlock(&vm_object_list_lock);
476*45748Smckusick 
477*45748Smckusick 	/*
478*45748Smckusick 	 *	Now we deallocate all the paging areas.  We don't need
479*45748Smckusick 	 *	to lock anything because we've reduced to a single
480*45748Smckusick 	 *	processor while shutting down.	This also assumes that
481*45748Smckusick 	 *	no new objects are being created.
482*45748Smckusick 	 */
483*45748Smckusick 
484*45748Smckusick 	object = (vm_object_t) queue_first(&vm_object_list);
485*45748Smckusick 	while (!queue_end(&vm_object_list, (queue_entry_t) object)) {
486*45748Smckusick 		if (object->pager != vm_pager_null)
487*45748Smckusick 			vm_pager_deallocate(object->pager);
488*45748Smckusick 		object = (vm_object_t) queue_next(&object->object_list);
489*45748Smckusick 		printf(".");
490*45748Smckusick 	}
491*45748Smckusick 	printf("done.\n");
492*45748Smckusick }
493*45748Smckusick 
494*45748Smckusick /*
495*45748Smckusick  *	vm_object_pmap_copy:
496*45748Smckusick  *
497*45748Smckusick  *	Makes all physical pages in the specified
498*45748Smckusick  *	object range copy-on-write.  No writeable
499*45748Smckusick  *	references to these pages should remain.
500*45748Smckusick  *
501*45748Smckusick  *	The object must *not* be locked.
502*45748Smckusick  */
503*45748Smckusick void vm_object_pmap_copy(object, start, end)
504*45748Smckusick 	register vm_object_t	object;
505*45748Smckusick 	register vm_offset_t	start;
506*45748Smckusick 	register vm_offset_t	end;
507*45748Smckusick {
508*45748Smckusick 	register vm_page_t	p;
509*45748Smckusick 
510*45748Smckusick 	if (object == VM_OBJECT_NULL)
511*45748Smckusick 		return;
512*45748Smckusick 
513*45748Smckusick 	vm_object_lock(object);
514*45748Smckusick 	p = (vm_page_t) queue_first(&object->memq);
515*45748Smckusick 	while (!queue_end(&object->memq, (queue_entry_t) p)) {
516*45748Smckusick 		if ((start <= p->offset) && (p->offset < end)) {
517*45748Smckusick 			if (!p->copy_on_write) {
518*45748Smckusick 				pmap_copy_on_write(VM_PAGE_TO_PHYS(p));
519*45748Smckusick 				p->copy_on_write = TRUE;
520*45748Smckusick 			}
521*45748Smckusick 		}
522*45748Smckusick 		p = (vm_page_t) queue_next(&p->listq);
523*45748Smckusick 	}
524*45748Smckusick 	vm_object_unlock(object);
525*45748Smckusick }
526*45748Smckusick 
527*45748Smckusick /*
528*45748Smckusick  *	vm_object_pmap_remove:
529*45748Smckusick  *
530*45748Smckusick  *	Removes all physical pages in the specified
531*45748Smckusick  *	object range from all physical maps.
532*45748Smckusick  *
533*45748Smckusick  *	The object must *not* be locked.
534*45748Smckusick  */
535*45748Smckusick void vm_object_pmap_remove(object, start, end)
536*45748Smckusick 	register vm_object_t	object;
537*45748Smckusick 	register vm_offset_t	start;
538*45748Smckusick 	register vm_offset_t	end;
539*45748Smckusick {
540*45748Smckusick 	register vm_page_t	p;
541*45748Smckusick 
542*45748Smckusick 	if (object == VM_OBJECT_NULL)
543*45748Smckusick 		return;
544*45748Smckusick 
545*45748Smckusick 	vm_object_lock(object);
546*45748Smckusick 	p = (vm_page_t) queue_first(&object->memq);
547*45748Smckusick 	while (!queue_end(&object->memq, (queue_entry_t) p)) {
548*45748Smckusick 		if ((start <= p->offset) && (p->offset < end)) {
549*45748Smckusick 			pmap_remove_all(VM_PAGE_TO_PHYS(p));
550*45748Smckusick 		}
551*45748Smckusick 		p = (vm_page_t) queue_next(&p->listq);
552*45748Smckusick 	}
553*45748Smckusick 	vm_object_unlock(object);
554*45748Smckusick }
555*45748Smckusick 
556*45748Smckusick /*
557*45748Smckusick  *	vm_object_copy:
558*45748Smckusick  *
559*45748Smckusick  *	Create a new object which is a copy of an existing
560*45748Smckusick  *	object, and mark all of the pages in the existing
561*45748Smckusick  *	object 'copy-on-write'.  The new object has one reference.
562*45748Smckusick  *	Returns the new object.
563*45748Smckusick  *
564*45748Smckusick  *	May defer the copy until later if the object is not backed
565*45748Smckusick  *	up by a non-default pager.
566*45748Smckusick  */
567*45748Smckusick void vm_object_copy(src_object, src_offset, size,
568*45748Smckusick 		    dst_object, dst_offset, src_needs_copy)
569*45748Smckusick 	register vm_object_t	src_object;
570*45748Smckusick 	vm_offset_t		src_offset;
571*45748Smckusick 	vm_size_t		size;
572*45748Smckusick 	vm_object_t		*dst_object;	/* OUT */
573*45748Smckusick 	vm_offset_t		*dst_offset;	/* OUT */
574*45748Smckusick 	boolean_t		*src_needs_copy;	/* OUT */
575*45748Smckusick {
576*45748Smckusick 	register vm_object_t	new_copy;
577*45748Smckusick 	register vm_object_t	old_copy;
578*45748Smckusick 	vm_offset_t		new_start, new_end;
579*45748Smckusick 
580*45748Smckusick 	register vm_page_t	p;
581*45748Smckusick 
582*45748Smckusick 	if (src_object == VM_OBJECT_NULL) {
583*45748Smckusick 		/*
584*45748Smckusick 		 *	Nothing to copy
585*45748Smckusick 		 */
586*45748Smckusick 		*dst_object = VM_OBJECT_NULL;
587*45748Smckusick 		*dst_offset = 0;
588*45748Smckusick 		*src_needs_copy = FALSE;
589*45748Smckusick 		return;
590*45748Smckusick 	}
591*45748Smckusick 
592*45748Smckusick 	/*
593*45748Smckusick 	 *	If the object's pager is null_pager or the
594*45748Smckusick 	 *	default pager, we don't have to make a copy
595*45748Smckusick 	 *	of it.  Instead, we set the needs copy flag and
596*45748Smckusick 	 *	make a shadow later.
597*45748Smckusick 	 */
598*45748Smckusick 
599*45748Smckusick 	vm_object_lock(src_object);
600*45748Smckusick 	if (src_object->pager == vm_pager_null ||
601*45748Smckusick 	    src_object->internal) {
602*45748Smckusick 
603*45748Smckusick 		/*
604*45748Smckusick 		 *	Make another reference to the object
605*45748Smckusick 		 */
606*45748Smckusick 		src_object->ref_count++;
607*45748Smckusick 
608*45748Smckusick 		/*
609*45748Smckusick 		 *	Mark all of the pages copy-on-write.
610*45748Smckusick 		 */
611*45748Smckusick 		for (p = (vm_page_t) queue_first(&src_object->memq);
612*45748Smckusick 		     !queue_end(&src_object->memq, (queue_entry_t)p);
613*45748Smckusick 		     p = (vm_page_t) queue_next(&p->listq)) {
614*45748Smckusick 			if (src_offset <= p->offset &&
615*45748Smckusick 			    p->offset < src_offset + size)
616*45748Smckusick 				p->copy_on_write = TRUE;
617*45748Smckusick 		}
618*45748Smckusick 		vm_object_unlock(src_object);
619*45748Smckusick 
620*45748Smckusick 		*dst_object = src_object;
621*45748Smckusick 		*dst_offset = src_offset;
622*45748Smckusick 
623*45748Smckusick 		/*
624*45748Smckusick 		 *	Must make a shadow when write is desired
625*45748Smckusick 		 */
626*45748Smckusick 		*src_needs_copy = TRUE;
627*45748Smckusick 		return;
628*45748Smckusick 	}
629*45748Smckusick 
630*45748Smckusick 	/*
631*45748Smckusick 	 *	Try to collapse the object before copying it.
632*45748Smckusick 	 */
633*45748Smckusick 	vm_object_collapse(src_object);
634*45748Smckusick 
635*45748Smckusick 	/*
636*45748Smckusick 	 *	If the object has a pager, the pager wants to
637*45748Smckusick 	 *	see all of the changes.  We need a copy-object
638*45748Smckusick 	 *	for the changed pages.
639*45748Smckusick 	 *
640*45748Smckusick 	 *	If there is a copy-object, and it is empty,
641*45748Smckusick 	 *	no changes have been made to the object since the
642*45748Smckusick 	 *	copy-object was made.  We can use the same copy-
643*45748Smckusick 	 *	object.
644*45748Smckusick 	 */
645*45748Smckusick 
646*45748Smckusick     Retry1:
647*45748Smckusick 	old_copy = src_object->copy;
648*45748Smckusick 	if (old_copy != VM_OBJECT_NULL) {
649*45748Smckusick 		/*
650*45748Smckusick 		 *	Try to get the locks (out of order)
651*45748Smckusick 		 */
652*45748Smckusick 		if (!vm_object_lock_try(old_copy)) {
653*45748Smckusick 			vm_object_unlock(src_object);
654*45748Smckusick 
655*45748Smckusick 			/* should spin a bit here... */
656*45748Smckusick 			vm_object_lock(src_object);
657*45748Smckusick 			goto Retry1;
658*45748Smckusick 		}
659*45748Smckusick 
660*45748Smckusick 		if (old_copy->resident_page_count == 0 &&
661*45748Smckusick 		    old_copy->pager == vm_pager_null) {
662*45748Smckusick 			/*
663*45748Smckusick 			 *	Return another reference to
664*45748Smckusick 			 *	the existing copy-object.
665*45748Smckusick 			 */
666*45748Smckusick 			old_copy->ref_count++;
667*45748Smckusick 			vm_object_unlock(old_copy);
668*45748Smckusick 			vm_object_unlock(src_object);
669*45748Smckusick 			*dst_object = old_copy;
670*45748Smckusick 			*dst_offset = src_offset;
671*45748Smckusick 			*src_needs_copy = FALSE;
672*45748Smckusick 			return;
673*45748Smckusick 		}
674*45748Smckusick 		vm_object_unlock(old_copy);
675*45748Smckusick 	}
676*45748Smckusick 	vm_object_unlock(src_object);
677*45748Smckusick 
678*45748Smckusick 	/*
679*45748Smckusick 	 *	If the object has a pager, the pager wants
680*45748Smckusick 	 *	to see all of the changes.  We must make
681*45748Smckusick 	 *	a copy-object and put the changed pages there.
682*45748Smckusick 	 *
683*45748Smckusick 	 *	The copy-object is always made large enough to
684*45748Smckusick 	 *	completely shadow the original object, since
685*45748Smckusick 	 *	it may have several users who want to shadow
686*45748Smckusick 	 *	the original object at different points.
687*45748Smckusick 	 */
688*45748Smckusick 
689*45748Smckusick 	new_copy = vm_object_allocate(src_object->size);
690*45748Smckusick 
691*45748Smckusick     Retry2:
692*45748Smckusick 	vm_object_lock(src_object);
693*45748Smckusick 	/*
694*45748Smckusick 	 *	Copy object may have changed while we were unlocked
695*45748Smckusick 	 */
696*45748Smckusick 	old_copy = src_object->copy;
697*45748Smckusick 	if (old_copy != VM_OBJECT_NULL) {
698*45748Smckusick 		/*
699*45748Smckusick 		 *	Try to get the locks (out of order)
700*45748Smckusick 		 */
701*45748Smckusick 		if (!vm_object_lock_try(old_copy)) {
702*45748Smckusick 			vm_object_unlock(src_object);
703*45748Smckusick 			goto Retry2;
704*45748Smckusick 		}
705*45748Smckusick 
706*45748Smckusick 		/*
707*45748Smckusick 		 *	Consistency check
708*45748Smckusick 		 */
709*45748Smckusick 		if (old_copy->shadow != src_object ||
710*45748Smckusick 		    old_copy->shadow_offset != (vm_offset_t) 0)
711*45748Smckusick 			panic("vm_object_copy: copy/shadow inconsistency");
712*45748Smckusick 
713*45748Smckusick 		/*
714*45748Smckusick 		 *	Make the old copy-object shadow the new one.
715*45748Smckusick 		 *	It will receive no more pages from the original
716*45748Smckusick 		 *	object.
717*45748Smckusick 		 */
718*45748Smckusick 
719*45748Smckusick 		src_object->ref_count--;	/* remove ref. from old_copy */
720*45748Smckusick 		old_copy->shadow = new_copy;
721*45748Smckusick 		new_copy->ref_count++;		/* locking not needed - we
722*45748Smckusick 						   have the only pointer */
723*45748Smckusick 		vm_object_unlock(old_copy);	/* done with old_copy */
724*45748Smckusick 	}
725*45748Smckusick 
726*45748Smckusick 	new_start = (vm_offset_t) 0;	/* always shadow original at 0 */
727*45748Smckusick 	new_end   = (vm_offset_t) new_copy->size; /* for the whole object */
728*45748Smckusick 
729*45748Smckusick 	/*
730*45748Smckusick 	 *	Point the new copy at the existing object.
731*45748Smckusick 	 */
732*45748Smckusick 
733*45748Smckusick 	new_copy->shadow = src_object;
734*45748Smckusick 	new_copy->shadow_offset = new_start;
735*45748Smckusick 	src_object->ref_count++;
736*45748Smckusick 	src_object->copy = new_copy;
737*45748Smckusick 
738*45748Smckusick 	/*
739*45748Smckusick 	 *	Mark all the affected pages of the existing object
740*45748Smckusick 	 *	copy-on-write.
741*45748Smckusick 	 */
742*45748Smckusick 	p = (vm_page_t) queue_first(&src_object->memq);
743*45748Smckusick 	while (!queue_end(&src_object->memq, (queue_entry_t) p)) {
744*45748Smckusick 		if ((new_start <= p->offset) && (p->offset < new_end)) {
745*45748Smckusick 			p->copy_on_write = TRUE;
746*45748Smckusick 		}
747*45748Smckusick 		p = (vm_page_t) queue_next(&p->listq);
748*45748Smckusick 	}
749*45748Smckusick 
750*45748Smckusick 	vm_object_unlock(src_object);
751*45748Smckusick 
752*45748Smckusick 	*dst_object = new_copy;
753*45748Smckusick 	*dst_offset = src_offset - new_start;
754*45748Smckusick 	*src_needs_copy = FALSE;
755*45748Smckusick }
756*45748Smckusick 
757*45748Smckusick /*
758*45748Smckusick  *	vm_object_shadow:
759*45748Smckusick  *
760*45748Smckusick  *	Create a new object which is backed by the
761*45748Smckusick  *	specified existing object range.  The source
762*45748Smckusick  *	object reference is deallocated.
763*45748Smckusick  *
764*45748Smckusick  *	The new object and offset into that object
765*45748Smckusick  *	are returned in the source parameters.
766*45748Smckusick  */
767*45748Smckusick 
768*45748Smckusick void vm_object_shadow(object, offset, length)
769*45748Smckusick 	vm_object_t	*object;	/* IN/OUT */
770*45748Smckusick 	vm_offset_t	*offset;	/* IN/OUT */
771*45748Smckusick 	vm_size_t	length;
772*45748Smckusick {
773*45748Smckusick 	register vm_object_t	source;
774*45748Smckusick 	register vm_object_t	result;
775*45748Smckusick 
776*45748Smckusick 	source = *object;
777*45748Smckusick 
778*45748Smckusick 	/*
779*45748Smckusick 	 *	Allocate a new object with the given length
780*45748Smckusick 	 */
781*45748Smckusick 
782*45748Smckusick 	if ((result = vm_object_allocate(length)) == VM_OBJECT_NULL)
783*45748Smckusick 		panic("vm_object_shadow: no object for shadowing");
784*45748Smckusick 
785*45748Smckusick 	/*
786*45748Smckusick 	 *	The new object shadows the source object, adding
787*45748Smckusick 	 *	a reference to it.  Our caller changes his reference
788*45748Smckusick 	 *	to point to the new object, removing a reference to
789*45748Smckusick 	 *	the source object.  Net result: no change of reference
790*45748Smckusick 	 *	count.
791*45748Smckusick 	 */
792*45748Smckusick 	result->shadow = source;
793*45748Smckusick 
794*45748Smckusick 	/*
795*45748Smckusick 	 *	Store the offset into the source object,
796*45748Smckusick 	 *	and fix up the offset into the new object.
797*45748Smckusick 	 */
798*45748Smckusick 
799*45748Smckusick 	result->shadow_offset = *offset;
800*45748Smckusick 
801*45748Smckusick 	/*
802*45748Smckusick 	 *	Return the new things
803*45748Smckusick 	 */
804*45748Smckusick 
805*45748Smckusick 	*offset = 0;
806*45748Smckusick 	*object = result;
807*45748Smckusick }
808*45748Smckusick 
809*45748Smckusick /*
810*45748Smckusick  *	Set the specified object's pager to the specified pager.
811*45748Smckusick  */
812*45748Smckusick 
813*45748Smckusick void vm_object_setpager(object, pager, paging_offset,
814*45748Smckusick 			read_only)
815*45748Smckusick 	vm_object_t	object;
816*45748Smckusick 	vm_pager_t	pager;
817*45748Smckusick 	vm_offset_t	paging_offset;
818*45748Smckusick 	boolean_t	read_only;
819*45748Smckusick {
820*45748Smckusick #ifdef	lint
821*45748Smckusick 	read_only++;	/* No longer used */
822*45748Smckusick #endif	lint
823*45748Smckusick 
824*45748Smckusick 	vm_object_lock(object);			/* XXX ? */
825*45748Smckusick 	object->pager = pager;
826*45748Smckusick 	object->paging_offset = paging_offset;
827*45748Smckusick 	vm_object_unlock(object);			/* XXX ? */
828*45748Smckusick }
829*45748Smckusick 
830*45748Smckusick /*
831*45748Smckusick  *	vm_object_hash hashes the pager/id pair.
832*45748Smckusick  */
833*45748Smckusick 
834*45748Smckusick #define vm_object_hash(pager) \
835*45748Smckusick 	(((unsigned)pager)%VM_OBJECT_HASH_COUNT)
836*45748Smckusick 
837*45748Smckusick /*
838*45748Smckusick  *	vm_object_lookup looks in the object cache for an object with the
839*45748Smckusick  *	specified pager and paging id.
840*45748Smckusick  */
841*45748Smckusick 
842*45748Smckusick vm_object_t vm_object_lookup(pager)
843*45748Smckusick 	vm_pager_t	pager;
844*45748Smckusick {
845*45748Smckusick 	register queue_t		bucket;
846*45748Smckusick 	register vm_object_hash_entry_t	entry;
847*45748Smckusick 	vm_object_t			object;
848*45748Smckusick 
849*45748Smckusick 	bucket = &vm_object_hashtable[vm_object_hash(pager)];
850*45748Smckusick 
851*45748Smckusick 	vm_object_cache_lock();
852*45748Smckusick 
853*45748Smckusick 	entry = (vm_object_hash_entry_t) queue_first(bucket);
854*45748Smckusick 	while (!queue_end(bucket, (queue_entry_t) entry)) {
855*45748Smckusick 		object = entry->object;
856*45748Smckusick 		if (object->pager == pager) {
857*45748Smckusick 			vm_object_lock(object);
858*45748Smckusick 			if (object->ref_count == 0) {
859*45748Smckusick 				queue_remove(&vm_object_cached_list, object,
860*45748Smckusick 						vm_object_t, cached_list);
861*45748Smckusick 				vm_object_cached--;
862*45748Smckusick 			}
863*45748Smckusick 			object->ref_count++;
864*45748Smckusick 			vm_object_unlock(object);
865*45748Smckusick 			vm_object_cache_unlock();
866*45748Smckusick 			return(object);
867*45748Smckusick 		}
868*45748Smckusick 		entry = (vm_object_hash_entry_t) queue_next(&entry->hash_links);
869*45748Smckusick 	}
870*45748Smckusick 
871*45748Smckusick 	vm_object_cache_unlock();
872*45748Smckusick 	return(VM_OBJECT_NULL);
873*45748Smckusick }
874*45748Smckusick 
875*45748Smckusick /*
876*45748Smckusick  *	vm_object_enter enters the specified object/pager/id into
877*45748Smckusick  *	the hash table.
878*45748Smckusick  */
879*45748Smckusick 
880*45748Smckusick void vm_object_enter(object, pager)
881*45748Smckusick 	vm_object_t	object;
882*45748Smckusick 	vm_pager_t	pager;
883*45748Smckusick {
884*45748Smckusick 	register queue_t		bucket;
885*45748Smckusick 	register vm_object_hash_entry_t	entry;
886*45748Smckusick 
887*45748Smckusick 	/*
888*45748Smckusick 	 *	We don't cache null objects, and we can't cache
889*45748Smckusick 	 *	objects with the null pager.
890*45748Smckusick 	 */
891*45748Smckusick 
892*45748Smckusick 	if (object == VM_OBJECT_NULL)
893*45748Smckusick 		return;
894*45748Smckusick 	if (pager == vm_pager_null)
895*45748Smckusick 		return;
896*45748Smckusick 
897*45748Smckusick 	bucket = &vm_object_hashtable[vm_object_hash(pager)];
898*45748Smckusick 	entry = (vm_object_hash_entry_t)
899*45748Smckusick 		malloc((u_long)sizeof *entry, M_VMOBJHASH, M_WAITOK);
900*45748Smckusick 	entry->object = object;
901*45748Smckusick 	object->can_persist = TRUE;
902*45748Smckusick 
903*45748Smckusick 	vm_object_cache_lock();
904*45748Smckusick 	queue_enter(bucket, entry, vm_object_hash_entry_t, hash_links);
905*45748Smckusick 	vm_object_cache_unlock();
906*45748Smckusick }
907*45748Smckusick 
908*45748Smckusick /*
909*45748Smckusick  *	vm_object_remove:
910*45748Smckusick  *
911*45748Smckusick  *	Remove the pager from the hash table.
912*45748Smckusick  *	Note:  This assumes that the object cache
913*45748Smckusick  *	is locked.  XXX this should be fixed
914*45748Smckusick  *	by reorganizing vm_object_deallocate.
915*45748Smckusick  */
916*45748Smckusick vm_object_remove(pager)
917*45748Smckusick 	register vm_pager_t	pager;
918*45748Smckusick {
919*45748Smckusick 	register queue_t		bucket;
920*45748Smckusick 	register vm_object_hash_entry_t	entry;
921*45748Smckusick 	register vm_object_t		object;
922*45748Smckusick 
923*45748Smckusick 	bucket = &vm_object_hashtable[vm_object_hash(pager)];
924*45748Smckusick 
925*45748Smckusick 	entry = (vm_object_hash_entry_t) queue_first(bucket);
926*45748Smckusick 	while (!queue_end(bucket, (queue_entry_t) entry)) {
927*45748Smckusick 		object = entry->object;
928*45748Smckusick 		if (object->pager == pager) {
929*45748Smckusick 			queue_remove(bucket, entry, vm_object_hash_entry_t,
930*45748Smckusick 					hash_links);
931*45748Smckusick 			free((caddr_t)entry, M_VMOBJHASH);
932*45748Smckusick 			break;
933*45748Smckusick 		}
934*45748Smckusick 		entry = (vm_object_hash_entry_t) queue_next(&entry->hash_links);
935*45748Smckusick 	}
936*45748Smckusick }
937*45748Smckusick 
938*45748Smckusick /*
939*45748Smckusick  *	vm_object_cache_clear removes all objects from the cache.
940*45748Smckusick  *
941*45748Smckusick  */
942*45748Smckusick 
943*45748Smckusick void vm_object_cache_clear()
944*45748Smckusick {
945*45748Smckusick 	register vm_object_t	object;
946*45748Smckusick 
947*45748Smckusick 	/*
948*45748Smckusick 	 *	Remove each object in the cache by scanning down the
949*45748Smckusick 	 *	list of cached objects.
950*45748Smckusick 	 */
951*45748Smckusick 	vm_object_cache_lock();
952*45748Smckusick 	while (!queue_empty(&vm_object_cached_list)) {
953*45748Smckusick 		object = (vm_object_t) queue_first(&vm_object_cached_list);
954*45748Smckusick 		vm_object_cache_unlock();
955*45748Smckusick 
956*45748Smckusick 		/*
957*45748Smckusick 		 * Note: it is important that we use vm_object_lookup
958*45748Smckusick 		 * to gain a reference, and not vm_object_reference, because
959*45748Smckusick 		 * the logic for removing an object from the cache lies in
960*45748Smckusick 		 * lookup.
961*45748Smckusick 		 */
962*45748Smckusick 		if (object != vm_object_lookup(object->pager))
963*45748Smckusick 			panic("vm_object_cache_clear: I'm sooo confused.");
964*45748Smckusick 		pager_cache(object, FALSE);
965*45748Smckusick 
966*45748Smckusick 		vm_object_cache_lock();
967*45748Smckusick 	}
968*45748Smckusick 	vm_object_cache_unlock();
969*45748Smckusick }
970*45748Smckusick 
971*45748Smckusick boolean_t	vm_object_collapse_allowed = TRUE;
972*45748Smckusick /*
973*45748Smckusick  *	vm_object_collapse:
974*45748Smckusick  *
975*45748Smckusick  *	Collapse an object with the object backing it.
976*45748Smckusick  *	Pages in the backing object are moved into the
977*45748Smckusick  *	parent, and the backing object is deallocated.
978*45748Smckusick  *
979*45748Smckusick  *	Requires that the object be locked and the page
980*45748Smckusick  *	queues be unlocked.
981*45748Smckusick  *
982*45748Smckusick  */
983*45748Smckusick void vm_object_collapse(object)
984*45748Smckusick 	register vm_object_t	object;
985*45748Smckusick 
986*45748Smckusick {
987*45748Smckusick 	register vm_object_t	backing_object;
988*45748Smckusick 	register vm_offset_t	backing_offset;
989*45748Smckusick 	register vm_size_t	size;
990*45748Smckusick 	register vm_offset_t	new_offset;
991*45748Smckusick 	register vm_page_t	p, pp;
992*45748Smckusick 
993*45748Smckusick 	if (!vm_object_collapse_allowed)
994*45748Smckusick 		return;
995*45748Smckusick 
996*45748Smckusick 	while (TRUE) {
997*45748Smckusick 		/*
998*45748Smckusick 		 *	Verify that the conditions are right for collapse:
999*45748Smckusick 		 *
1000*45748Smckusick 		 *	The object exists and no pages in it are currently
1001*45748Smckusick 		 *	being paged out (or have ever been paged out).
1002*45748Smckusick 		 */
1003*45748Smckusick 		if (object == VM_OBJECT_NULL ||
1004*45748Smckusick 		    object->paging_in_progress != 0 ||
1005*45748Smckusick 		    object->pager != vm_pager_null)
1006*45748Smckusick 			return;
1007*45748Smckusick 
1008*45748Smckusick 		/*
1009*45748Smckusick 		 *		There is a backing object, and
1010*45748Smckusick 		 */
1011*45748Smckusick 
1012*45748Smckusick 		if ((backing_object = object->shadow) == VM_OBJECT_NULL)
1013*45748Smckusick 			return;
1014*45748Smckusick 
1015*45748Smckusick 		vm_object_lock(backing_object);
1016*45748Smckusick 		/*
1017*45748Smckusick 		 *	...
1018*45748Smckusick 		 *		The backing object is not read_only,
1019*45748Smckusick 		 *		and no pages in the backing object are
1020*45748Smckusick 		 *		currently being paged out.
1021*45748Smckusick 		 *		The backing object is internal.
1022*45748Smckusick 		 */
1023*45748Smckusick 
1024*45748Smckusick 		if (!backing_object->internal ||
1025*45748Smckusick 		    backing_object->paging_in_progress != 0) {
1026*45748Smckusick 			vm_object_unlock(backing_object);
1027*45748Smckusick 			return;
1028*45748Smckusick 		}
1029*45748Smckusick 
1030*45748Smckusick 		/*
1031*45748Smckusick 		 *	The backing object can't be a copy-object:
1032*45748Smckusick 		 *	the shadow_offset for the copy-object must stay
1033*45748Smckusick 		 *	as 0.  Furthermore (for the 'we have all the
1034*45748Smckusick 		 *	pages' case), if we bypass backing_object and
1035*45748Smckusick 		 *	just shadow the next object in the chain, old
1036*45748Smckusick 		 *	pages from that object would then have to be copied
1037*45748Smckusick 		 *	BOTH into the (former) backing_object and into the
1038*45748Smckusick 		 *	parent object.
1039*45748Smckusick 		 */
1040*45748Smckusick 		if (backing_object->shadow != VM_OBJECT_NULL &&
1041*45748Smckusick 		    backing_object->shadow->copy != VM_OBJECT_NULL) {
1042*45748Smckusick 			vm_object_unlock(backing_object);
1043*45748Smckusick 			return;
1044*45748Smckusick 		}
1045*45748Smckusick 
1046*45748Smckusick 		/*
1047*45748Smckusick 		 *	We know that we can either collapse the backing
1048*45748Smckusick 		 *	object (if the parent is the only reference to
1049*45748Smckusick 		 *	it) or (perhaps) remove the parent's reference
1050*45748Smckusick 		 *	to it.
1051*45748Smckusick 		 */
1052*45748Smckusick 
1053*45748Smckusick 		backing_offset = object->shadow_offset;
1054*45748Smckusick 		size = object->size;
1055*45748Smckusick 
1056*45748Smckusick 		/*
1057*45748Smckusick 		 *	If there is exactly one reference to the backing
1058*45748Smckusick 		 *	object, we can collapse it into the parent.
1059*45748Smckusick 		 */
1060*45748Smckusick 
1061*45748Smckusick 		if (backing_object->ref_count == 1) {
1062*45748Smckusick 
1063*45748Smckusick 			/*
1064*45748Smckusick 			 *	We can collapse the backing object.
1065*45748Smckusick 			 *
1066*45748Smckusick 			 *	Move all in-memory pages from backing_object
1067*45748Smckusick 			 *	to the parent.  Pages that have been paged out
1068*45748Smckusick 			 *	will be overwritten by any of the parent's
1069*45748Smckusick 			 *	pages that shadow them.
1070*45748Smckusick 			 */
1071*45748Smckusick 
1072*45748Smckusick 			while (!queue_empty(&backing_object->memq)) {
1073*45748Smckusick 
1074*45748Smckusick 				p = (vm_page_t)
1075*45748Smckusick 					queue_first(&backing_object->memq);
1076*45748Smckusick 
1077*45748Smckusick 				new_offset = (p->offset - backing_offset);
1078*45748Smckusick 
1079*45748Smckusick 				/*
1080*45748Smckusick 				 *	If the parent has a page here, or if
1081*45748Smckusick 				 *	this page falls outside the parent,
1082*45748Smckusick 				 *	dispose of it.
1083*45748Smckusick 				 *
1084*45748Smckusick 				 *	Otherwise, move it as planned.
1085*45748Smckusick 				 */
1086*45748Smckusick 
1087*45748Smckusick 				if (p->offset < backing_offset ||
1088*45748Smckusick 				    new_offset >= size) {
1089*45748Smckusick 					vm_page_lock_queues();
1090*45748Smckusick 					vm_page_free(p);
1091*45748Smckusick 					vm_page_unlock_queues();
1092*45748Smckusick 				} else {
1093*45748Smckusick 				    pp = vm_page_lookup(object, new_offset);
1094*45748Smckusick 				    if (pp != VM_PAGE_NULL && !pp->fake) {
1095*45748Smckusick 					vm_page_lock_queues();
1096*45748Smckusick 					vm_page_free(p);
1097*45748Smckusick 					vm_page_unlock_queues();
1098*45748Smckusick 				    }
1099*45748Smckusick 				    else {
1100*45748Smckusick 					if (pp) {
1101*45748Smckusick 					    /* may be someone waiting for it */
1102*45748Smckusick 					    PAGE_WAKEUP(pp);
1103*45748Smckusick 					    vm_page_lock_queues();
1104*45748Smckusick 					    vm_page_free(pp);
1105*45748Smckusick 					    vm_page_unlock_queues();
1106*45748Smckusick 					}
1107*45748Smckusick 					vm_page_rename(p, object, new_offset);
1108*45748Smckusick 				    }
1109*45748Smckusick 				}
1110*45748Smckusick 			}
1111*45748Smckusick 
1112*45748Smckusick 			/*
1113*45748Smckusick 			 *	Move the pager from backing_object to object.
1114*45748Smckusick 			 *
1115*45748Smckusick 			 *	XXX We're only using part of the paging space
1116*45748Smckusick 			 *	for keeps now... we ought to discard the
1117*45748Smckusick 			 *	unused portion.
1118*45748Smckusick 			 */
1119*45748Smckusick 
1120*45748Smckusick 			object->pager = backing_object->pager;
1121*45748Smckusick 			object->paging_offset += backing_offset;
1122*45748Smckusick 
1123*45748Smckusick 			backing_object->pager = vm_pager_null;
1124*45748Smckusick 
1125*45748Smckusick 			/*
1126*45748Smckusick 			 *	Object now shadows whatever backing_object did.
1127*45748Smckusick 			 *	Note that the reference to backing_object->shadow
1128*45748Smckusick 			 *	moves from within backing_object to within object.
1129*45748Smckusick 			 */
1130*45748Smckusick 
1131*45748Smckusick 			object->shadow = backing_object->shadow;
1132*45748Smckusick 			object->shadow_offset += backing_object->shadow_offset;
1133*45748Smckusick 			if (object->shadow != VM_OBJECT_NULL &&
1134*45748Smckusick 			    object->shadow->copy != VM_OBJECT_NULL) {
1135*45748Smckusick 				panic("vm_object_collapse: we collapsed a copy-object!");
1136*45748Smckusick 			}
1137*45748Smckusick 			/*
1138*45748Smckusick 			 *	Discard backing_object.
1139*45748Smckusick 			 *
1140*45748Smckusick 			 *	Since the backing object has no pages, no
1141*45748Smckusick 			 *	pager left, and no object references within it,
1142*45748Smckusick 			 *	all that is necessary is to dispose of it.
1143*45748Smckusick 			 */
1144*45748Smckusick 
1145*45748Smckusick 			vm_object_unlock(backing_object);
1146*45748Smckusick 
1147*45748Smckusick 			simple_lock(&vm_object_list_lock);
1148*45748Smckusick 			queue_remove(&vm_object_list, backing_object,
1149*45748Smckusick 						vm_object_t, object_list);
1150*45748Smckusick 			vm_object_count--;
1151*45748Smckusick 			simple_unlock(&vm_object_list_lock);
1152*45748Smckusick 
1153*45748Smckusick 			free((caddr_t)backing_object, M_VMOBJ);
1154*45748Smckusick 
1155*45748Smckusick 			object_collapses++;
1156*45748Smckusick 		}
1157*45748Smckusick 		else {
1158*45748Smckusick 			/*
1159*45748Smckusick 			 *	If all of the pages in the backing object are
1160*45748Smckusick 			 *	shadowed by the parent object, the parent
1161*45748Smckusick 			 *	object no longer has to shadow the backing
1162*45748Smckusick 			 *	object; it can shadow the next one in the
1163*45748Smckusick 			 *	chain.
1164*45748Smckusick 			 *
1165*45748Smckusick 			 *	The backing object must not be paged out - we'd
1166*45748Smckusick 			 *	have to check all of the paged-out pages, as
1167*45748Smckusick 			 *	well.
1168*45748Smckusick 			 */
1169*45748Smckusick 
1170*45748Smckusick 			if (backing_object->pager != vm_pager_null) {
1171*45748Smckusick 				vm_object_unlock(backing_object);
1172*45748Smckusick 				return;
1173*45748Smckusick 			}
1174*45748Smckusick 
1175*45748Smckusick 			/*
1176*45748Smckusick 			 *	Should have a check for a 'small' number
1177*45748Smckusick 			 *	of pages here.
1178*45748Smckusick 			 */
1179*45748Smckusick 
1180*45748Smckusick 			p = (vm_page_t) queue_first(&backing_object->memq);
1181*45748Smckusick 			while (!queue_end(&backing_object->memq,
1182*45748Smckusick 					  (queue_entry_t) p)) {
1183*45748Smckusick 
1184*45748Smckusick 				new_offset = (p->offset - backing_offset);
1185*45748Smckusick 
1186*45748Smckusick 				/*
1187*45748Smckusick 				 *	If the parent has a page here, or if
1188*45748Smckusick 				 *	this page falls outside the parent,
1189*45748Smckusick 				 *	keep going.
1190*45748Smckusick 				 *
1191*45748Smckusick 				 *	Otherwise, the backing_object must be
1192*45748Smckusick 				 *	left in the chain.
1193*45748Smckusick 				 */
1194*45748Smckusick 
1195*45748Smckusick 				if (p->offset >= backing_offset &&
1196*45748Smckusick 				    new_offset <= size &&
1197*45748Smckusick 				    ((pp = vm_page_lookup(object, new_offset))
1198*45748Smckusick 				      == VM_PAGE_NULL ||
1199*45748Smckusick 				     pp->fake)) {
1200*45748Smckusick 					/*
1201*45748Smckusick 					 *	Page still needed.
1202*45748Smckusick 					 *	Can't go any further.
1203*45748Smckusick 					 */
1204*45748Smckusick 					vm_object_unlock(backing_object);
1205*45748Smckusick 					return;
1206*45748Smckusick 				}
1207*45748Smckusick 				p = (vm_page_t) queue_next(&p->listq);
1208*45748Smckusick 			}
1209*45748Smckusick 
1210*45748Smckusick 			/*
1211*45748Smckusick 			 *	Make the parent shadow the next object
1212*45748Smckusick 			 *	in the chain.  Deallocating backing_object
1213*45748Smckusick 			 *	will not remove it, since its reference
1214*45748Smckusick 			 *	count is at least 2.
1215*45748Smckusick 			 */
1216*45748Smckusick 
1217*45748Smckusick 			vm_object_reference(object->shadow = backing_object->shadow);
1218*45748Smckusick 			object->shadow_offset += backing_object->shadow_offset;
1219*45748Smckusick 
1220*45748Smckusick 			/*	Drop the reference count on backing_object.
1221*45748Smckusick 			 *	Since its ref_count was at least 2, it
1222*45748Smckusick 			 *	will not vanish; so we don't need to call
1223*45748Smckusick 			 *	vm_object_deallocate.
1224*45748Smckusick 			 */
1225*45748Smckusick 			backing_object->ref_count--;
1226*45748Smckusick 			vm_object_unlock(backing_object);
1227*45748Smckusick 
1228*45748Smckusick 			object_bypasses ++;
1229*45748Smckusick 
1230*45748Smckusick 		}
1231*45748Smckusick 
1232*45748Smckusick 		/*
1233*45748Smckusick 		 *	Try again with this object's new backing object.
1234*45748Smckusick 		 */
1235*45748Smckusick 	}
1236*45748Smckusick }
1237*45748Smckusick 
1238*45748Smckusick /*
1239*45748Smckusick  *	vm_object_page_remove: [internal]
1240*45748Smckusick  *
1241*45748Smckusick  *	Removes all physical pages in the specified
1242*45748Smckusick  *	object range from the object's list of pages.
1243*45748Smckusick  *
1244*45748Smckusick  *	The object must be locked.
1245*45748Smckusick  */
1246*45748Smckusick void vm_object_page_remove(object, start, end)
1247*45748Smckusick 	register vm_object_t	object;
1248*45748Smckusick 	register vm_offset_t	start;
1249*45748Smckusick 	register vm_offset_t	end;
1250*45748Smckusick {
1251*45748Smckusick 	register vm_page_t	p, next;
1252*45748Smckusick 
1253*45748Smckusick 	if (object == VM_OBJECT_NULL)
1254*45748Smckusick 		return;
1255*45748Smckusick 
1256*45748Smckusick 	p = (vm_page_t) queue_first(&object->memq);
1257*45748Smckusick 	while (!queue_end(&object->memq, (queue_entry_t) p)) {
1258*45748Smckusick 		next = (vm_page_t) queue_next(&p->listq);
1259*45748Smckusick 		if ((start <= p->offset) && (p->offset < end)) {
1260*45748Smckusick 			pmap_remove_all(VM_PAGE_TO_PHYS(p));
1261*45748Smckusick 			vm_page_lock_queues();
1262*45748Smckusick 			vm_page_free(p);
1263*45748Smckusick 			vm_page_unlock_queues();
1264*45748Smckusick 		}
1265*45748Smckusick 		p = next;
1266*45748Smckusick 	}
1267*45748Smckusick }
1268*45748Smckusick 
1269*45748Smckusick /*
1270*45748Smckusick  *	Routine:	vm_object_coalesce
1271*45748Smckusick  *	Function:	Coalesces two objects backing up adjoining
1272*45748Smckusick  *			regions of memory into a single object.
1273*45748Smckusick  *
1274*45748Smckusick  *	returns TRUE if objects were combined.
1275*45748Smckusick  *
1276*45748Smckusick  *	NOTE:	Only works at the moment if the second object is NULL -
1277*45748Smckusick  *		if it's not, which object do we lock first?
1278*45748Smckusick  *
1279*45748Smckusick  *	Parameters:
1280*45748Smckusick  *		prev_object	First object to coalesce
1281*45748Smckusick  *		prev_offset	Offset into prev_object
1282*45748Smckusick  *		next_object	Second object into coalesce
1283*45748Smckusick  *		next_offset	Offset into next_object
1284*45748Smckusick  *
1285*45748Smckusick  *		prev_size	Size of reference to prev_object
1286*45748Smckusick  *		next_size	Size of reference to next_object
1287*45748Smckusick  *
1288*45748Smckusick  *	Conditions:
1289*45748Smckusick  *	The object must *not* be locked.
1290*45748Smckusick  */
1291*45748Smckusick boolean_t vm_object_coalesce(prev_object, next_object,
1292*45748Smckusick 			prev_offset, next_offset,
1293*45748Smckusick 			prev_size, next_size)
1294*45748Smckusick 
1295*45748Smckusick 	register vm_object_t	prev_object;
1296*45748Smckusick 	vm_object_t	next_object;
1297*45748Smckusick 	vm_offset_t	prev_offset, next_offset;
1298*45748Smckusick 	vm_size_t	prev_size, next_size;
1299*45748Smckusick {
1300*45748Smckusick 	vm_size_t	newsize;
1301*45748Smckusick 
1302*45748Smckusick #ifdef	lint
1303*45748Smckusick 	next_offset++;
1304*45748Smckusick #endif	lint
1305*45748Smckusick 
1306*45748Smckusick 	if (next_object != VM_OBJECT_NULL) {
1307*45748Smckusick 		return(FALSE);
1308*45748Smckusick 	}
1309*45748Smckusick 
1310*45748Smckusick 	if (prev_object == VM_OBJECT_NULL) {
1311*45748Smckusick 		return(TRUE);
1312*45748Smckusick 	}
1313*45748Smckusick 
1314*45748Smckusick 	vm_object_lock(prev_object);
1315*45748Smckusick 
1316*45748Smckusick 	/*
1317*45748Smckusick 	 *	Try to collapse the object first
1318*45748Smckusick 	 */
1319*45748Smckusick 	vm_object_collapse(prev_object);
1320*45748Smckusick 
1321*45748Smckusick 	/*
1322*45748Smckusick 	 *	Can't coalesce if:
1323*45748Smckusick 	 *	. more than one reference
1324*45748Smckusick 	 *	. paged out
1325*45748Smckusick 	 *	. shadows another object
1326*45748Smckusick 	 *	. has a copy elsewhere
1327*45748Smckusick 	 *	(any of which mean that the pages not mapped to
1328*45748Smckusick 	 *	prev_entry may be in use anyway)
1329*45748Smckusick 	 */
1330*45748Smckusick 
1331*45748Smckusick 	if (prev_object->ref_count > 1 ||
1332*45748Smckusick 		prev_object->pager != vm_pager_null ||
1333*45748Smckusick 		prev_object->shadow != VM_OBJECT_NULL ||
1334*45748Smckusick 		prev_object->copy != VM_OBJECT_NULL) {
1335*45748Smckusick 		vm_object_unlock(prev_object);
1336*45748Smckusick 		return(FALSE);
1337*45748Smckusick 	}
1338*45748Smckusick 
1339*45748Smckusick 	/*
1340*45748Smckusick 	 *	Remove any pages that may still be in the object from
1341*45748Smckusick 	 *	a previous deallocation.
1342*45748Smckusick 	 */
1343*45748Smckusick 
1344*45748Smckusick 	vm_object_page_remove(prev_object,
1345*45748Smckusick 			prev_offset + prev_size,
1346*45748Smckusick 			prev_offset + prev_size + next_size);
1347*45748Smckusick 
1348*45748Smckusick 	/*
1349*45748Smckusick 	 *	Extend the object if necessary.
1350*45748Smckusick 	 */
1351*45748Smckusick 	newsize = prev_offset + prev_size + next_size;
1352*45748Smckusick 	if (newsize > prev_object->size)
1353*45748Smckusick 		prev_object->size = newsize;
1354*45748Smckusick 
1355*45748Smckusick 	vm_object_unlock(prev_object);
1356*45748Smckusick 	return(TRUE);
1357*45748Smckusick }
1358*45748Smckusick 
1359*45748Smckusick /*
1360*45748Smckusick  *	vm_object_print:	[ debug ]
1361*45748Smckusick  */
1362*45748Smckusick void vm_object_print(object, full)
1363*45748Smckusick 	vm_object_t	object;
1364*45748Smckusick 	boolean_t	full;
1365*45748Smckusick {
1366*45748Smckusick 	register vm_page_t	p;
1367*45748Smckusick 	extern indent;
1368*45748Smckusick 
1369*45748Smckusick 	register int count;
1370*45748Smckusick 
1371*45748Smckusick 	if (object == VM_OBJECT_NULL)
1372*45748Smckusick 		return;
1373*45748Smckusick 
1374*45748Smckusick 	iprintf("Object 0x%x: size=0x%x, res=%d, ref=%d, ",
1375*45748Smckusick 		(int) object, (int) object->size,
1376*45748Smckusick 		object->resident_page_count, object->ref_count);
1377*45748Smckusick 	printf("pager=0x%x+0x%x, shadow=(0x%x)+0x%x\n",
1378*45748Smckusick 	       (int) object->pager, (int) object->paging_offset,
1379*45748Smckusick 	       (int) object->shadow, (int) object->shadow_offset);
1380*45748Smckusick 	printf("cache: next=0x%x, prev=0x%x\n",
1381*45748Smckusick 	       object->cached_list.next, object->cached_list.prev);
1382*45748Smckusick 
1383*45748Smckusick 	if (!full)
1384*45748Smckusick 		return;
1385*45748Smckusick 
1386*45748Smckusick 	indent += 2;
1387*45748Smckusick 	count = 0;
1388*45748Smckusick 	p = (vm_page_t) queue_first(&object->memq);
1389*45748Smckusick 	while (!queue_end(&object->memq, (queue_entry_t) p)) {
1390*45748Smckusick 		if (count == 0)
1391*45748Smckusick 			iprintf("memory:=");
1392*45748Smckusick 		else if (count == 6) {
1393*45748Smckusick 			printf("\n");
1394*45748Smckusick 			iprintf(" ...");
1395*45748Smckusick 			count = 0;
1396*45748Smckusick 		} else
1397*45748Smckusick 			printf(",");
1398*45748Smckusick 		count++;
1399*45748Smckusick 
1400*45748Smckusick 		printf("(off=0x%x,page=0x%x)", p->offset, VM_PAGE_TO_PHYS(p));
1401*45748Smckusick 		p = (vm_page_t) queue_next(&p->listq);
1402*45748Smckusick 	}
1403*45748Smckusick 	if (count != 0)
1404*45748Smckusick 		printf("\n");
1405*45748Smckusick 	indent -= 2;
1406*45748Smckusick }
1407