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