xref: /386bsd/usr/src/kernel/kern/vm/object.c (revision a2142627)
1 /*
2  * Copyright (c) 1991 Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * The Mach Operating System project at Carnegie-Mellon University.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  *	$Id: object.c,v 1.1 94/10/19 17:37:18 bill Exp $
37  *
38  *
39  * Copyright (c) 1987, 1990 Carnegie-Mellon University.
40  * All rights reserved.
41  *
42  * Authors: Avadis Tevanian, Jr., Michael Wayne Young
43  *
44  * Permission to use, copy, modify and distribute this software and
45  * its documentation is hereby granted, provided that both the copyright
46  * notice and this permission notice appear in all copies of the
47  * software, derivative works or modified versions, and any portions
48  * thereof, and that both notices appear in supporting documentation.
49  *
50  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
51  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
52  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
53  *
54  * Carnegie Mellon requests users of this software to return to
55  *
56  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
57  *  School of Computer Science
58  *  Carnegie Mellon University
59  *  Pittsburgh PA 15213-3890
60  *
61  * any improvements or extensions that they make and grant Carnegie the
62  * rights to redistribute these changes.
63  */
64 
65 /* Resident contents of virtual address space via memory object abstraction. */
66 
67 #include "sys/param.h"
68 #include "proc.h"
69 #include "malloc.h"
70 #include "vm.h"
71 #define __NO_INLINES
72 #include "prototypes.h"
73 
74 /*
75  * Virtual memory objects maintain the actual data associated with
76  * allocated virtual memory, as a variable length segment of sparse memory pages.
77  * These pages each correspond to a unique offset within the logically ordered
78  * segment, which always starts at zero and ends at a maximum size.
79  * Pages are managed by a seperate mechanism that allocates them onto
80  * an object. At any time, a memory page may be uniquely identified by its
81  * object/offset pair.
82  *
83  * Objects underly map entries, and are allocated by reference to faulted
84  * pages. An object is only deallocated when all "references" are given up,
85  * as when a map is deallocated. Objects may have a "pager" routine to provide
86  * access to non-resident pages in a backing store by means of kernel I/O to
87  * make them resident. The fault and pageout mechanisms use this to exchange
88  * pages between memory/secondary storage. Objects can also use other objects
89  * to hold to a subset of the segment contents; this can be used to "share"
90  * common contents of many objects, or to uniquely record consecutive changed
91  * sets of pages used in implementing a form of sharing known as copy-on-write.
92  *
93  */
94 
95 /* statically allocated contents of kernel and kmem objects */
96 struct vm_object kernel_object_store, kmem_object_store;
97 
98 #define	VM_OBJECT_HASH_COUNT	157
99 
100 int		vm_cache_max = 100;	/* can patch if necessary */
101 queue_head_t	vm_object_hashtable[VM_OBJECT_HASH_COUNT];
102 
103 long	object_collapses;
104 long	object_bypasses;
105 
106 static void _vm_object_allocate(vm_size_t size, vm_object_t object);
107 static void vm_object_cache_trim(void);
108 /* static */ void vm_object_cache_clear();
109 /*static */ void vm_object_deactivate_pages(vm_object_t object);
110 
111 /* initialize the memory object abstraction layer. */
112 void
vm_object_init(void)113 vm_object_init(void)
114 {
115 	int	i;
116 
117 	/* initialize empty cached object list */
118 	queue_init(&vm_object_cached_list);
119 	vm_object_count = 0;
120 
121 	/* clear hash table of queue headers for vm_object_lookup() */
122 	for (i = 0; i < VM_OBJECT_HASH_COUNT; i++)
123 		queue_init(&vm_object_hashtable[i]);
124 
125 	/* allocate & initialize an empty object to hold kernel pages */
126 	kernel_object = &kernel_object_store;
127 	_vm_object_allocate(VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS,
128 			kernel_object);
129 	kernel_object->ref_count = 0;
130 
131 	/* allocate & initialize an empty object to hold kernel memory allocator pages */
132 	kmem_object = &kmem_object_store;
133 	_vm_object_allocate(VM_KMEM_SIZE + VM_MBUF_SIZE, kmem_object);
134 	kmem_object->ref_count = 0;
135 }
136 
137 /* dynamically allocate a new object to contain a desired sized segment */
138 vm_object_t
vm_object_allocate(vm_size_t size)139 vm_object_allocate(vm_size_t size)
140 {
141 	vm_object_t	result;
142 
143 	result = (vm_object_t)
144 		malloc((u_long)sizeof *result, M_VMOBJ, M_WAITOK);
145 	_vm_object_allocate(size, result);
146 	return(result);
147 }
148 
149 /* initialize the object with default paramters */
150 static void
_vm_object_allocate(vm_size_t size,register vm_object_t object)151 _vm_object_allocate(vm_size_t size, register vm_object_t object)
152 {
153 	/* empty termporary object */
154 	queue_init(&object->memq);
155 	object->ref_count = 1;
156 	object->resident_page_count = 0;
157 	object->size = size;
158 	object->can_persist = FALSE;
159 	object->paging_in_progress = 0;
160 	object->copy = NULL;
161 
162 	/* no external contents */
163 	object->pager = NULL;
164 	object->internal = TRUE;
165 	object->paging_offset = 0;
166 	object->shadow = NULL;
167 	object->shadow_offset = (vm_offset_t) 0;
168 
169 	vm_object_count++;
170 }
171 
172 /* increase reference count on an object */
173 void
vm_object_reference(vm_object_t object)174 vm_object_reference(vm_object_t object)
175 {
176 	if (object == NULL)
177 		return;
178 	object->ref_count++;
179 }
180 
181 /* release a reference on an object, deallocating if no more references */
182 void
vm_object_deallocate(vm_object_t object)183 vm_object_deallocate(vm_object_t object)
184 {
185 	vm_object_t	temp;
186 
187 	/* walk the list of allocated objects */
188 	while (object != NULL) {
189 
190 		/* reduce the reference count */
191 		if (--(object->ref_count) != 0)
192 			return;
193 
194 		/* if object persists, cache and deactivate pages */
195 		if (object->can_persist) {
196 			queue_enter(&vm_object_cached_list, object,
197 				vm_object_t, cached_list);
198 			vm_object_cached++;
199 			vm_object_deactivate_pages(object);
200 
201 			/* check for cache overflow */
202 			vm_object_cache_trim();
203 			return;
204 		}
205 
206 		/* isolate from pagers to avoid new references to obj */
207 		vm_object_remove(object->pager);
208 
209 		/* terminate this object, and then deallocate shadow */
210 		temp = object->shadow;
211 		vm_object_terminate(object);
212 		object = temp;
213 	}
214 }
215 
216 /* reclaim an object, releasing all underlying abstractions */
217 void
vm_object_terminate(vm_object_t object)218 vm_object_terminate(vm_object_t object)
219 {
220 	vm_page_t p;
221 	vm_object_t shadow_object;
222 
223 	/* if this is the copy object for the shadow, clear */
224 	if ((shadow_object = object->shadow) != NULL) {
225 		if (shadow_object->copy == object)
226 			shadow_object->copy = NULL;
227 	}
228 
229 	/* any I/O references outstanding, if so wait for conclusion */
230 	while (object->paging_in_progress != 0)
231 		(void) tsleep((caddr_t)object, PVM, "objterm", 0);
232 
233 	/* isolate pages, making them "off queue" prior to free */
234 	p = (vm_page_t) queue_first(&object->memq);
235 	while (!queue_end(&object->memq, (queue_entry_t) p)) {
236 
237 		/* release from active queue */
238 		if (p->active) {
239 			queue_remove(&vm_page_queue_active, p, vm_page_t,
240 						pageq);
241 			p->active = FALSE;
242 			vm_page_active_count--;
243 		}
244 
245 		/* release from inactive queue */
246 		if (p->inactive) {
247 			queue_remove(&vm_page_queue_inactive, p, vm_page_t,
248 						pageq);
249 			p->inactive = FALSE;
250 			vm_page_inactive_count--;
251 		}
252 
253 		p = (vm_page_t) queue_next(&p->listq);
254 	}
255 
256 #ifdef	DIAGNOSTIC
257 	if (object->paging_in_progress != 0)
258 		panic("vm_object_deallocate: pageout in progress");
259 #endif
260 
261 	/* force last update of modified pages to external storage */
262 	if (!object->internal)
263 		vm_object_page_clean(object, 0, 0);
264 
265 	/* free objects pages */
266 	while (!queue_empty(&object->memq)) {
267 		p = (vm_page_t) queue_first(&object->memq);
268 		vm_page_free(p);
269 	}
270 
271 	/* free pager (if any) */
272 	if (object->pager != NULL)
273 		vm_pager_deallocate(object->pager);
274 	object->pager = NULL;
275 
276 	/* free object */
277 	free((caddr_t)object, M_VMOBJ);
278 	vm_object_count--;
279 }
280 
281 /* find dirty pages and force them back to external storage */
282 void
vm_object_page_clean(vm_object_t object,vm_offset_t start,vm_offset_t end)283 vm_object_page_clean(vm_object_t object, vm_offset_t start, vm_offset_t end)
284 {
285 	vm_page_t p;
286 
287 	/* no pager, nothing to do. */
288 	if (object->pager == NULL)
289 		return;
290 
291 	/* walk objects queue of pages, looking for dirty pages */
292 again:
293 	p = (vm_page_t) queue_first(&object->memq);
294 	while (!queue_end(&object->memq, (queue_entry_t) p)) {
295 
296 		/* page in clean region of objects logical segment */
297 		if (start == end ||
298 		    p->offset >= start && p->offset < end) {
299 
300 			/* update page dirty and force unmapped */
301 			if (p->clean && pmap_is_modified(VM_PAGE_TO_PHYS(p)))
302 				p->clean = FALSE;
303 			pmap_page_protect(VM_PAGE_TO_PHYS(p), VM_PROT_NONE);
304 
305 			/* if dirty, synchronously write the page */
306 			if (!p->clean) {
307 				p->busy = TRUE;
308 				object->paging_in_progress++;
309 				(void) vm_pager_put(object->pager, p, TRUE);
310 				object->paging_in_progress--;
311 				wakeup((caddr_t) object);
312 				p->busy = FALSE;
313 				PAGE_WAKEUP(p);
314 
315 				/* re examine from start of list */
316 				goto again;
317 			}
318 		}
319 		p = (vm_page_t) queue_next(&p->listq);
320 	}
321 }
322 
323 /* force objects pages to be reclaimable */
324 void
vm_object_deactivate_pages(vm_object_t object)325 vm_object_deactivate_pages(vm_object_t object)
326 {
327 	vm_page_t p, next;
328 
329 	if (object == NULL)
330 		return;
331 
332 	/* walk objects page queue, deactivating pages. */
333 	p = (vm_page_t) queue_first(&object->memq);
334 	while (!queue_end(&object->memq, (queue_entry_t) p)) {
335 		next = (vm_page_t) queue_next(&p->listq);
336 		vm_page_deactivate(p);
337 		p = next;
338 	}
339 }
340 
341 /* reduce the object cache if oversized */
342 static void
vm_object_cache_trim(void)343 vm_object_cache_trim(void)
344 {
345 	vm_object_t	object;
346 
347 	/* if cache is too large ... */
348 	while (vm_object_cached > vm_cache_max) {
349 		object = (vm_object_t) queue_first(&vm_object_cached_list);
350 
351 #ifdef DIAGNOSTIC
352 		if (object != vm_object_lookup(object->pager))
353 			panic("vm_object_cache_trim: object not in cache");
354 #endif
355 
356 		/* force object to lose persistance and be deallocated */
357 		pager_cache(object, FALSE);
358 	}
359 }
360 
361 /* force read-only access to pages in range & mark pages copy-on_write. */
362 void
vm_object_pmap_copy(vm_object_t object,vm_offset_t start,vm_offset_t end)363 vm_object_pmap_copy(vm_object_t object, vm_offset_t start, vm_offset_t end)
364 {
365 	vm_page_t p;
366 
367 	if (object == NULL)
368 		return;
369 
370 	p = (vm_page_t) queue_first(&object->memq);
371 	while (!queue_end(&object->memq, (queue_entry_t) p)) {
372 		if ((start <= p->offset) && (p->offset < end)) {
373 			pmap_page_protect(VM_PAGE_TO_PHYS(p), VM_PROT_READ);
374 			p->copy_on_write = TRUE;
375 		}
376 		p = (vm_page_t) queue_next(&p->listq);
377 	}
378 }
379 
380 /* remove access to pages in range. */
381 void
vm_object_pmap_remove(vm_object_t object,vm_offset_t start,vm_offset_t end)382 vm_object_pmap_remove(vm_object_t object, vm_offset_t start, vm_offset_t end)
383 {
384 	vm_page_t p;
385 
386 	if (object == NULL)
387 		return;
388 
389 	p = (vm_page_t) queue_first(&object->memq);
390 	while (!queue_end(&object->memq, (queue_entry_t) p)) {
391 		if ((start <= p->offset) && (p->offset < end))
392 			pmap_page_protect(VM_PAGE_TO_PHYS(p), VM_PROT_NONE);
393 		p = (vm_page_t) queue_next(&p->listq);
394 	}
395 }
396 
397 /*
398  * copy a range of the object to be used by another map entry by
399  * increasing the references on an existing object. a object is
400  * preceded by a copy object that holds modified pages seperate
401  * from its read-only contents. if not present, the copy object is
402  * created and inserted in front of the supplied object whose pages
403  * are made read-only. only the copy object is shared by new copies.
404  */
405 void
vm_object_copy(vm_object_t src_object,vm_offset_t src_offset,vm_size_t size,vm_object_t * dst_object,vm_offset_t * dst_offset,boolean_t * src_needs_copy)406 vm_object_copy(vm_object_t src_object, vm_offset_t src_offset, vm_size_t size,
407   vm_object_t *dst_object, vm_offset_t *dst_offset, boolean_t *src_needs_copy)
408 {
409 	vm_object_t new_copy, old_copy;
410 	vm_offset_t new_start, new_end;
411 	vm_page_t p;
412 
413 	/* no object yet exists to copy */
414 	if (src_object == NULL) {
415 		*dst_object = NULL;
416 		*dst_offset = 0;
417 		*src_needs_copy = FALSE;
418 		return;
419 	}
420 
421 	/* postpone object generation since no pager or default pager? */
422 	if (src_object->pager == NULL || src_object->internal) {
423 
424 		/* pages must be uniquely cloned if written */
425 		for (p = (vm_page_t) queue_first(&src_object->memq);
426 		     !queue_end(&src_object->memq, (queue_entry_t)p);
427 		     p = (vm_page_t) queue_next(&p->listq)) {
428 			if (src_offset <= p->offset &&
429 			    p->offset < src_offset + size)
430 				p->copy_on_write = TRUE;
431 		}
432 
433 		/* share source object (until either modify, then shadow) */
434 		*dst_object = src_object;
435 		*dst_offset = src_offset;
436 		src_object->ref_count++;
437 		*src_needs_copy = TRUE;
438 		return;
439 	}
440 
441 	/* collapse object chain before increasing it */
442 	vm_object_collapse(src_object);
443 
444 	/* if no modified/external pages in existing copy object, use it. */
445 	if ((old_copy = src_object->copy) != NULL &&
446 	    old_copy->resident_page_count == 0 && old_copy->pager == NULL) {
447 		old_copy->ref_count++;
448 		*dst_object = old_copy;
449 		*dst_offset = src_offset;
450 		*src_needs_copy = FALSE;
451 		return;
452 	}
453 
454 	/* allocate a copy object to entirely shadow current object */
455 	new_copy = vm_object_allocate(src_object->size);
456 	new_start = (vm_offset_t) 0;
457 	new_end   = (vm_offset_t) new_copy->size;
458 
459 	/* check if copy object already inserted in src */
460 	if ((old_copy = src_object->copy) != NULL) {
461 #ifdef DIAGNOSTIC
462 		if (old_copy->shadow != src_object ||
463 		    old_copy->shadow_offset != (vm_offset_t) 0)
464 			panic("vm_object_copy: copy/shadow inconsistency");
465 #endif
466 		/* chain new one in front of old one. new one sees changes. */
467 		src_object->ref_count--;
468 		old_copy->shadow = new_copy;
469 		new_copy->ref_count++;
470 	}
471 
472 	/* incorporate copy object with original that it entirely shadows */
473 	new_copy->shadow = src_object;
474 	new_copy->shadow_offset = new_start;
475 	src_object->ref_count++;
476 	src_object->copy = new_copy;
477 
478 	/* make original object pages read-only, cloned on write into copy object */
479 	p = (vm_page_t) queue_first(&src_object->memq);
480 	while (!queue_end(&src_object->memq, (queue_entry_t) p)) {
481 		if ((new_start <= p->offset) && (p->offset < new_end))
482 			p->copy_on_write = TRUE;
483 		p = (vm_page_t) queue_next(&p->listq);
484 	}
485 
486 	/* pass new copy object back as copy */
487 	*dst_object = new_copy;
488 	*dst_offset = src_offset - new_start;
489 	*src_needs_copy = FALSE;
490 }
491 
492 /* insert an object in front of the current one, which it now shadows a portion of */
493 void
vm_object_shadow(vm_object_t * object,vm_offset_t * offset,vm_size_t length)494 vm_object_shadow(vm_object_t *object, vm_offset_t *offset, vm_size_t length)
495 {
496 	vm_object_t source = *object, result;
497 
498 	/* allocate a object to shadow original */
499 	result = vm_object_allocate(length);
500 #ifdef	DIAGNOSTIC
501 	if (result == NULL)
502 		panic("vm_object_shadow: no object for shadowing");
503 #endif
504 
505 	/* insert shadow ahead of current entry, at desired offset into current*/
506 	result->shadow = source;
507 	result->shadow_offset = *offset;
508 	*offset = 0;
509 	*object = result;
510 }
511 
512 /* hash object lookup on pager instance address */
513 #define vm_object_hash(pager) \
514 	(((unsigned)pager)%VM_OBJECT_HASH_COUNT)
515 
516 /* locate an allocated object (with a pager) by its pager instance */
517 vm_object_t
vm_object_lookup(vm_pager_t pager)518 vm_object_lookup(vm_pager_t pager)
519 {
520 	queue_t bucket;
521 	vm_object_hash_entry_t entry;
522 	vm_object_t object;
523 
524 	/* find associated queue head for this pager */
525 	bucket = &vm_object_hashtable[vm_object_hash(pager)];
526 
527 	/* search queue for an object with this pager */
528 	entry = (vm_object_hash_entry_t) queue_first(bucket);
529 	while (!queue_end(bucket, (queue_entry_t) entry)) {
530 		object = entry->object;
531 
532 		/* found object? */
533 		if (object->pager == pager) {
534 
535 			/* in cache? remove and assert a reference */
536 			if (object->ref_count == 0) {
537 				queue_remove(&vm_object_cached_list, object,
538 				    vm_object_t, cached_list);
539 				vm_object_cached--;
540 			}
541 			object->ref_count++;
542 			return(object);
543 		}
544 		entry = (vm_object_hash_entry_t) queue_next(&entry->hash_links);
545 	}
546 
547 	return(NULL);
548 }
549 
550 
551 /* insert object into hash table so lookup can find it by pager. */
552 void
vm_object_enter(vm_object_t object)553 vm_object_enter(vm_object_t object)
554 {
555 	queue_t	 bucket;
556 	vm_object_hash_entry_t	entry;
557 
558 	/* ignore attempts to cache null objects or pagers */
559 	if (object == NULL || object->pager == NULL)
560 		return;
561 
562 	/* find hash bucket queue header for pager */
563 	bucket = &vm_object_hashtable[vm_object_hash(object->pager)];
564 
565 	/* allocate and insert hash entry in cache */
566 	entry = (vm_object_hash_entry_t)
567 		malloc((u_long)sizeof *entry, M_VMOBJHASH, M_WAITOK);
568 	entry->object = object;
569 	object->can_persist = TRUE;
570 	object->paging_offset = 0;
571 	queue_enter(bucket, entry, vm_object_hash_entry_t, hash_links);
572 }
573 
574 
575 /* remove object associated with pager instance from lookup hash table */
576 void
vm_object_remove(vm_pager_t pager)577 vm_object_remove(vm_pager_t pager)
578 {
579 	queue_t bucket;
580 	vm_object_hash_entry_t entry;
581 	vm_object_t object;
582 
583 	bucket = &vm_object_hashtable[vm_object_hash(pager)];
584 
585 	entry = (vm_object_hash_entry_t) queue_first(bucket);
586 	while (!queue_end(bucket, (queue_entry_t) entry)) {
587 		object = entry->object;
588 		if (object->pager == pager) {
589 			queue_remove(bucket, entry, vm_object_hash_entry_t,
590 					hash_links);
591 			free((caddr_t)entry, M_VMOBJHASH);
592 			break;
593 		}
594 		entry = (vm_object_hash_entry_t) queue_next(&entry->hash_links);
595 	}
596 }
597 
598 /* reduce number of redundant shadow objects in place */
599 void
vm_object_collapse(vm_object_t object)600 vm_object_collapse(vm_object_t object)
601 {
602 	vm_object_t backing_object;
603 	vm_offset_t backing_offset, new_offset;
604 	vm_size_t size;
605 	vm_page_t p, pp;
606 
607 	/* attempt to sucessive collapse/bypass shadows into current object */
608 	while (TRUE) {
609 		/* an idle object doesn't exist without external contents */
610 		if (object == NULL || object->paging_in_progress != 0
611 		    || object->pager != NULL)
612 			return;
613 
614 		/* the object doesn't shadow an internal idle object */
615 		if ((backing_object = object->shadow) == NULL ||
616 		    !backing_object->internal ||
617 		    backing_object->paging_in_progress != 0)
618 			return;
619 
620 		/* the shadowed object is the copy object */
621 		if (backing_object->shadow != NULL &&
622 		    backing_object->shadow->copy != NULL)
623 			return;
624 
625 		backing_offset = object->shadow_offset;
626 		size = object->size;
627 
628 		/* collapse shadow into current object */
629 		if (backing_object->ref_count == 1) {
630 
631 			/* merge shadow's pages into current object */
632 			while (!queue_empty(&backing_object->memq)) {
633 
634 				p = (vm_page_t)
635 					queue_first(&backing_object->memq);
636 
637 				new_offset = (p->offset - backing_offset);
638 
639 				/* free shadow page that exceeds boundaries of current object */
640 				if (p->offset < backing_offset ||
641 				    new_offset >= size)
642 					vm_page_free(p);
643 				else {
644 				    /* if valid page exists in current object, free shadow page */
645 				    pp = vm_page_lookup(object, new_offset);
646 				    if (pp != NULL && !pp->fake)
647 					vm_page_free(p);
648 				    else {
649 					/* free invalid page in current object */
650 					if (pp) {
651 					    /* may be someone waiting for it */
652 					    PAGE_WAKEUP(pp);
653 					    vm_page_free(pp);
654 					}
655 					/* otherwise, move page into current object */
656 					vm_page_rename(p, object, new_offset);
657 				    }
658 				}
659 			}
660 
661 			/* relocate pager (if any) into current object */
662 			object->pager = backing_object->pager;
663 			object->paging_offset += backing_offset;
664 			backing_object->pager = NULL;
665 
666 			/* current object now shadows shadows' shadow */
667 			object->shadow = backing_object->shadow;
668 			object->shadow_offset += backing_object->shadow_offset;
669 #ifdef	DIAGNOSTIC
670 			if (object->shadow != NULL &&
671 			    object->shadow->copy != NULL) {
672 				panic("vm_object_collapse: we collapsed a copy-object!");
673 			}
674 #endif
675 
676 			/* old shadow object reclaimed inline */
677 			vm_object_count--;
678 			free((caddr_t)backing_object, M_VMOBJ);
679 			object_collapses++;
680 		}
681 
682 		/* bypass unused shadow to release reference and allow other collapse */
683 		else {
684 			/* no external page state */
685 			if (backing_object->pager != NULL)
686 				return;
687 
688 			/* scan shadow to find any dependant entries */
689 			p = (vm_page_t) queue_first(&backing_object->memq);
690 			while (!queue_end(&backing_object->memq,
691 					  (queue_entry_t) p)) {
692 
693 				new_offset = (p->offset - backing_offset);
694 
695 				/* shadow has dependant page, failed bypass */
696 				if (p->offset >= backing_offset &&
697 				    new_offset <= size &&
698 				    ((pp = vm_page_lookup(object, new_offset))
699 				      == NULL ||
700 				     pp->fake))
701 					return;
702 
703 				p = (vm_page_t) queue_next(&p->listq);
704 			}
705 
706 			/* current object shadows shadows' shadow instead of shadow */
707 			vm_object_reference(object->shadow = backing_object->shadow);
708 			object->shadow_offset += backing_object->shadow_offset;
709 
710 			/* no longer reference shadow */
711 			backing_object->ref_count--;
712 			object_bypasses ++;
713 		}
714 	}
715 }
716 
717 /* remove access to pages in range and free them. */
718 void
vm_object_page_remove(vm_object_t object,vm_offset_t start,vm_offset_t end)719 vm_object_page_remove(vm_object_t object, vm_offset_t start, vm_offset_t end)
720 {
721 	vm_page_t p, next;
722 
723 	if (object == NULL)
724 		return;
725 
726 	p = (vm_page_t) queue_first(&object->memq);
727 	while (!queue_end(&object->memq, (queue_entry_t) p)) {
728 		next = (vm_page_t) queue_next(&p->listq);
729 		if ((start <= p->offset) && (p->offset < end)) {
730 			pmap_page_protect(VM_PAGE_TO_PHYS(p), VM_PROT_NONE);
731 			vm_page_free(p);
732 		}
733 		p = next;
734 	}
735 }
736 
737 /* combine two like, adjacent anonymous objects into a single object */
738 boolean_t
vm_object_coalesce(vm_object_t prev_object,vm_object_t next_object,vm_offset_t prev_offset,vm_offset_t next_offset,vm_size_t prev_size,vm_size_t next_size)739 vm_object_coalesce(vm_object_t prev_object, vm_object_t next_object,
740     vm_offset_t prev_offset, vm_offset_t next_offset, vm_size_t prev_size,
741     vm_size_t next_size)
742 {
743 	vm_size_t newsize;
744 	vm_offset_t newoffset = prev_offset + prev_size;
745 
746 	/* trivial coalesce */
747 	if (prev_object == NULL && next_object == NULL)
748 		return(TRUE);
749 
750 	/* reduce object shadow list to canonicalize object */
751 	vm_object_collapse(prev_object);
752 
753 	/*
754 	 * can't work if either object multiply referenced, shadows another,
755 	 * or has a copy object (can't tell if isomorphic/adjacent).
756 	 */
757 	if (prev_object->ref_count != 1 || prev_object->pager ||
758 	    prev_object->shadow || prev_object->copy)
759 		return(FALSE);
760 	if (next_object != NULL && (next_object->ref_count != 1 ||
761 	    next_object->pager || next_object->shadow || next_object->copy))
762 		return(FALSE);
763 
764 	/* clear extended region of object */
765 	vm_object_page_remove(prev_object, newoffset, newoffset + next_size);
766 
767 	/* extend object size if new combination exceeds existing size */
768 	newsize = newoffset + next_size;
769 	if (newsize > prev_object->size)
770 		prev_object->size = newsize;
771 
772 	/* if next object has contents, merge them and discard object */
773 	if (next_object != NULL) {
774 		vm_page_t p;
775 
776 		/* move pages to previous object */
777 		while (!queue_empty(&next_object->memq)) {
778 			p = (vm_page_t)queue_first(&next_object->memq);
779 			if (p->offset < next_size)
780 				vm_page_rename(p, prev_object,
781 				    p->offset + newoffset);
782 			else
783 				vm_page_free(p);
784 		}
785 
786 		/* release object */
787 		vm_object_count--;
788 		free((caddr_t)next_object, M_VMOBJ);
789 	}
790 	return(TRUE);
791 }
792 
793 #if defined(DEBUG) || defined(DDB)
794 /*
795  *	vm_object_print:	[ debug ]
796  */
797 void
vm_object_print(vm_object_t object,boolean_t full)798 vm_object_print(vm_object_t object, boolean_t full)
799 {
800 	register vm_page_t	p;
801 	extern indent;
802 
803 	register int count;
804 
805 	if (object == NULL)
806 		return;
807 
808 	iprintf("Object 0x%x: size=0x%x res=%d ref=%d persist %d int %d ",
809 		(int) object, (int) object->size,
810 		object->resident_page_count, object->ref_count,
811 		object->can_persist, object->internal);
812 	printf("pager=0x%x+0x%x, shadow=(0x%x)+0x%x\n",
813 	       (int) object->pager, (int) object->paging_offset,
814 	       (int) object->shadow, (int) object->shadow_offset);
815 	printf("cache: next=0x%x, prev=0x%x\n",
816 	       object->cached_list.next, object->cached_list.prev);
817 
818 	if (!full)
819 		return;
820 
821 	indent += 2;
822 	count = 0;
823 	p = (vm_page_t) queue_first(&object->memq);
824 	while (!queue_end(&object->memq, (queue_entry_t) p)) {
825 		if (count == 0)
826 			iprintf("memory:=");
827 		else if (count == 6) {
828 			pg("\n");
829 			iprintf(" ...");
830 			count = 0;
831 		} else
832 			printf(",");
833 		count++;
834 
835 		printf("(m=%x off=0x%x,page=0x%x)", p, p->offset, VM_PAGE_TO_PHYS(p));
836 		p = (vm_page_t) queue_next(&p->listq);
837 	}
838 	if (count != 0)
839 		printf("\n");
840 	indent -= 2;
841 }
842 
843 #ifndef nope
queue_check(queue_chain_t * q)844 queue_check(queue_chain_t *q) {
845 
846 	vm_page_t f, l, n, p, m;
847 	int count = 100000;
848 	int nelmt = 1, npanic = 0, ppanic = 0;
849 
850 	/* walk forward links, checking reverse */
851 	m = f = (vm_page_t) queue_first(q);
852 	l = (vm_page_t) queue_last(q);
853 /*printf("f %x l %x ", f, l); */
854 	for (m = f; !queue_end(q, (queue_entry_t) m) && npanic == 0 ; m = n) {
855 
856 		if (m->object != (vm_object_t) q) {
857 			printf("object %x\n", m->object);
858 			npanic++;
859 			break;
860 		}
861 
862 		n = (vm_page_t) queue_next(&m->listq);
863 		p = (vm_page_t) queue_prev(&m->listq);
864 /*printf("m %x (p %x n %x) ", m, p, n); */
865 		if (m == n) {
866 			printf("%d.%x: next(m) == m\n", nelmt, m);
867 			npanic++;
868 		} else if (m == l && queue_end(q, (queue_entry_t)n) == 0) {
869 			printf("%d.%x: last link not end\n", nelmt, l);
870 			npanic++;
871 		} else if (queue_end(q, (queue_entry_t) n) == 0 &&
872 		    m != (vm_page_t) queue_prev(&n->listq)) {
873 			printf("%d.%x: prev(next(m)) != m (%x != %x)\n",
874 				nelmt+1, n, m, queue_prev(&n->listq));
875 			vm_page_print(n);
876 			npanic++;
877 		}
878 		if (m == p) {
879 			printf("%d.%x: prev(m) == m \n", nelmt, m);
880 			npanic++;
881 		} else if (m == f && queue_end(q, (queue_entry_t)p) == 0) {
882 			printf("%d.%x: first link\n", nelmt, p);
883 			npanic++;
884 		} else if (queue_end(q, (queue_entry_t) p) == 0 &&
885 		    m != (vm_page_t) queue_next(&p->listq)) {
886 			printf("%d.%x: next(prev(m)) != m (%x != %x)\n",
887 				nelmt-1, p, m, queue_next(&p->listq));
888 			vm_page_print(p);
889 			npanic++;
890 		}
891 		if (vm_Page_check(m))
892 			nelmt++;
893 		else
894 			npanic++;
895 		if (count-- < 0) {
896 			printf("circular queue(n)\n");
897 			npanic++;
898 		}
899 		/*m = n;*/
900 	}
901 	if (npanic)
902 		vm_page_print(m);
903 
904 	if (npanic || ppanic)
905 		panic("queue");
906 }
907 #endif
908 #endif
909