]> git.saurik.com Git - apple/xnu.git/blob - osfmk/vm/bsd_vm.c
ef9254714251e5b140cc6ffd885600732a978ba7
[apple/xnu.git] / osfmk / vm / bsd_vm.c
1 /*
2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23 #include <sys/errno.h>
24
25 #include <mach/mach_types.h>
26 #include <mach/mach_traps.h>
27 #include <mach/host_priv.h>
28 #include <mach/kern_return.h>
29 #include <mach/memory_object_control.h>
30 #include <mach/memory_object_types.h>
31 #include <mach/port.h>
32 #include <mach/policy.h>
33 #include <mach/upl.h>
34 #include <mach/thread_act.h>
35
36 #include <kern/host.h>
37 #include <kern/thread.h>
38
39 #include <ipc/ipc_port.h>
40 #include <ipc/ipc_space.h>
41
42 #include <default_pager/default_pager_types.h>
43 #include <default_pager/default_pager_object_server.h>
44
45 #include <vm/vm_map.h>
46 #include <vm/vm_pageout.h>
47 #include <vm/memory_object.h>
48 #include <vm/vm_pageout.h>
49 #include <vm/vm_protos.h>
50
51 /* BSD VM COMPONENT INTERFACES */
52 int
53 get_map_nentries(
54 vm_map_t);
55
56 vm_offset_t
57 get_map_start(
58 vm_map_t);
59
60 vm_offset_t
61 get_map_end(
62 vm_map_t);
63
64 /*
65 *
66 */
67 int
68 get_map_nentries(
69 vm_map_t map)
70 {
71 return(map->hdr.nentries);
72 }
73
74 mach_vm_offset_t
75 mach_get_vm_start(vm_map_t map)
76 {
77 return( vm_map_first_entry(map)->vme_start);
78 }
79
80 mach_vm_offset_t
81 mach_get_vm_end(vm_map_t map)
82 {
83 return( vm_map_last_entry(map)->vme_end);
84 }
85
86 /*
87 * Legacy routines to get the start and end for a vm_map_t. They
88 * return them in the vm_offset_t format. So, they should only be
89 * called on maps that are the same size as the kernel map for
90 * accurate results.
91 */
92 vm_offset_t
93 get_vm_start(
94 vm_map_t map)
95 {
96 return(CAST_DOWN(vm_offset_t, vm_map_first_entry(map)->vme_start));
97 }
98
99 vm_offset_t
100 get_vm_end(
101 vm_map_t map)
102 {
103 return(CAST_DOWN(vm_offset_t, vm_map_last_entry(map)->vme_end));
104 }
105
106 /*
107 * BSD VNODE PAGER
108 */
109
110 const struct memory_object_pager_ops vnode_pager_ops = {
111 vnode_pager_reference,
112 vnode_pager_deallocate,
113 vnode_pager_init,
114 vnode_pager_terminate,
115 vnode_pager_data_request,
116 vnode_pager_data_return,
117 vnode_pager_data_initialize,
118 vnode_pager_data_unlock,
119 vnode_pager_synchronize,
120 vnode_pager_unmap,
121 "vnode pager"
122 };
123
124 typedef struct vnode_pager {
125 memory_object_pager_ops_t pager_ops; /* == &vnode_pager_ops */
126 unsigned int pager_ikot; /* JMM: fake ip_kotype() */
127 unsigned int ref_count; /* reference count */
128 memory_object_control_t control_handle; /* mem object control handle */
129 struct vnode *vnode_handle; /* vnode handle */
130 } *vnode_pager_t;
131
132
133 ipc_port_t
134 trigger_name_to_port( /* forward */
135 mach_port_t);
136
137 kern_return_t
138 vnode_pager_cluster_read( /* forward */
139 vnode_pager_t,
140 vm_object_offset_t,
141 vm_size_t);
142
143 void
144 vnode_pager_cluster_write( /* forward */
145 vnode_pager_t,
146 vm_object_offset_t,
147 vm_size_t,
148 vm_object_offset_t *,
149 int *,
150 int);
151
152
153 vnode_pager_t
154 vnode_object_create( /* forward */
155 struct vnode *);
156
157 vnode_pager_t
158 vnode_pager_lookup( /* forward */
159 memory_object_t);
160
161 zone_t vnode_pager_zone;
162
163
164 #define VNODE_PAGER_NULL ((vnode_pager_t) 0)
165
166 /* TODO: Should be set dynamically by vnode_pager_init() */
167 #define CLUSTER_SHIFT 1
168
169 /* TODO: Should be set dynamically by vnode_pager_bootstrap() */
170 #define MAX_VNODE 10000
171
172
173 #if DEBUG
174 int pagerdebug=0;
175
176 #define PAGER_ALL 0xffffffff
177 #define PAGER_INIT 0x00000001
178 #define PAGER_PAGEIN 0x00000002
179
180 #define PAGER_DEBUG(LEVEL, A) {if ((pagerdebug & LEVEL)==LEVEL){printf A;}}
181 #else
182 #define PAGER_DEBUG(LEVEL, A)
183 #endif
184
185 /*
186 * Routine: macx_triggers
187 * Function:
188 * Syscall interface to set the call backs for low and
189 * high water marks.
190 */
191 int
192 macx_triggers(
193 struct macx_triggers_args *args)
194 {
195 int hi_water = args->hi_water;
196 int low_water = args->low_water;
197 int flags = args->flags;
198 mach_port_t trigger_name = args->alert_port;
199 kern_return_t kr;
200 memory_object_default_t default_pager;
201 ipc_port_t trigger_port;
202
203 default_pager = MEMORY_OBJECT_DEFAULT_NULL;
204 kr = host_default_memory_manager(host_priv_self(),
205 &default_pager, 0);
206 if(kr != KERN_SUCCESS) {
207 return EINVAL;
208 }
209
210 if ((flags & SWAP_ENCRYPT_ON) &&
211 (flags & SWAP_ENCRYPT_OFF)) {
212 /* can't have it both ways */
213 return EINVAL;
214 }
215
216 if (default_pager_init_flag == 0) {
217 start_def_pager(NULL);
218 default_pager_init_flag = 1;
219 }
220
221 if (flags & SWAP_ENCRYPT_ON) {
222 /* ENCRYPTED SWAP: tell default_pager to encrypt */
223 default_pager_triggers(default_pager,
224 0, 0,
225 SWAP_ENCRYPT_ON,
226 IP_NULL);
227 } else if (flags & SWAP_ENCRYPT_OFF) {
228 /* ENCRYPTED SWAP: tell default_pager not to encrypt */
229 default_pager_triggers(default_pager,
230 0, 0,
231 SWAP_ENCRYPT_OFF,
232 IP_NULL);
233 }
234
235 if (flags & HI_WAT_ALERT) {
236 trigger_port = trigger_name_to_port(trigger_name);
237 if(trigger_port == NULL) {
238 return EINVAL;
239 }
240 /* trigger_port is locked and active */
241 ipc_port_make_send_locked(trigger_port);
242 /* now unlocked */
243 default_pager_triggers(default_pager,
244 hi_water, low_water,
245 HI_WAT_ALERT, trigger_port);
246 }
247
248 if (flags & LO_WAT_ALERT) {
249 trigger_port = trigger_name_to_port(trigger_name);
250 if(trigger_port == NULL) {
251 return EINVAL;
252 }
253 /* trigger_port is locked and active */
254 ipc_port_make_send_locked(trigger_port);
255 /* and now its unlocked */
256 default_pager_triggers(default_pager,
257 hi_water, low_water,
258 LO_WAT_ALERT, trigger_port);
259 }
260
261 /*
262 * Set thread scheduling priority and policy for the current thread
263 * it is assumed for the time being that the thread setting the alert
264 * is the same one which will be servicing it.
265 *
266 * XXX This does not belong in the kernel XXX
267 */
268 {
269 thread_precedence_policy_data_t pre;
270 thread_extended_policy_data_t ext;
271
272 ext.timeshare = FALSE;
273 pre.importance = INT32_MAX;
274
275 thread_policy_set(current_thread(),
276 THREAD_EXTENDED_POLICY,
277 (thread_policy_t)&ext,
278 THREAD_EXTENDED_POLICY_COUNT);
279
280 thread_policy_set(current_thread(),
281 THREAD_PRECEDENCE_POLICY,
282 (thread_policy_t)&pre,
283 THREAD_PRECEDENCE_POLICY_COUNT);
284 }
285
286 current_thread()->options |= TH_OPT_VMPRIV;
287
288 return 0;
289 }
290
291 /*
292 *
293 */
294 ipc_port_t
295 trigger_name_to_port(
296 mach_port_t trigger_name)
297 {
298 ipc_port_t trigger_port;
299 ipc_space_t space;
300
301 if (trigger_name == 0)
302 return (NULL);
303
304 space = current_space();
305 if(ipc_port_translate_receive(space, (mach_port_name_t)trigger_name,
306 &trigger_port) != KERN_SUCCESS)
307 return (NULL);
308 return trigger_port;
309 }
310
311
312 extern int uiomove64(addr64_t, int, void *);
313 #define MAX_RUN 32
314
315 int
316 memory_object_control_uiomove(
317 memory_object_control_t control,
318 memory_object_offset_t offset,
319 void * uio,
320 int start_offset,
321 int io_requested,
322 int mark_dirty)
323 {
324 vm_object_t object;
325 vm_page_t dst_page;
326 int xsize;
327 int retval = 0;
328 int cur_run;
329 int cur_needed;
330 int i;
331 vm_page_t page_run[MAX_RUN];
332
333
334 object = memory_object_control_to_vm_object(control);
335 if (object == VM_OBJECT_NULL) {
336 return (0);
337 }
338 assert(!object->internal);
339
340 vm_object_lock(object);
341
342 if (mark_dirty && object->copy != VM_OBJECT_NULL) {
343 /*
344 * We can't modify the pages without honoring
345 * copy-on-write obligations first, so fall off
346 * this optimized path and fall back to the regular
347 * path.
348 */
349 vm_object_unlock(object);
350 return 0;
351 }
352
353 while (io_requested && retval == 0) {
354
355 cur_needed = (start_offset + io_requested + (PAGE_SIZE - 1)) / PAGE_SIZE;
356
357 if (cur_needed > MAX_RUN)
358 cur_needed = MAX_RUN;
359
360 for (cur_run = 0; cur_run < cur_needed; ) {
361
362 if ((dst_page = vm_page_lookup(object, offset)) == VM_PAGE_NULL)
363 break;
364 /*
365 * Sync up on getting the busy bit
366 */
367 if ((dst_page->busy || dst_page->cleaning)) {
368 /*
369 * someone else is playing with the page... if we've
370 * already collected pages into this run, go ahead
371 * and process now, we can't block on this
372 * page while holding other pages in the BUSY state
373 * otherwise we will wait
374 */
375 if (cur_run)
376 break;
377 PAGE_SLEEP(object, dst_page, THREAD_UNINT);
378 continue;
379 }
380 /*
381 * this routine is only called when copying
382 * to/from real files... no need to consider
383 * encrypted swap pages
384 */
385 assert(!dst_page->encrypted);
386
387 if (mark_dirty)
388 dst_page->dirty = TRUE;
389 dst_page->busy = TRUE;
390
391 page_run[cur_run++] = dst_page;
392
393 offset += PAGE_SIZE_64;
394 }
395 if (cur_run == 0)
396 /*
397 * we hit a 'hole' in the cache
398 * we bail at this point
399 * we'll unlock the object below
400 */
401 break;
402 vm_object_unlock(object);
403
404 for (i = 0; i < cur_run; i++) {
405
406 dst_page = page_run[i];
407
408 if ((xsize = PAGE_SIZE - start_offset) > io_requested)
409 xsize = io_requested;
410
411 if ( (retval = uiomove64((addr64_t)(((addr64_t)(dst_page->phys_page) << 12) + start_offset), xsize, uio)) )
412 break;
413
414 io_requested -= xsize;
415 start_offset = 0;
416 }
417 vm_object_lock(object);
418
419 for (i = 0; i < cur_run; i++) {
420 dst_page = page_run[i];
421
422 PAGE_WAKEUP_DONE(dst_page);
423 }
424 }
425 vm_object_unlock(object);
426
427 return (retval);
428 }
429
430
431 /*
432 *
433 */
434 void
435 vnode_pager_bootstrap(void)
436 {
437 register vm_size_t size;
438
439 size = (vm_size_t) sizeof(struct vnode_pager);
440 vnode_pager_zone = zinit(size, (vm_size_t) MAX_VNODE*size,
441 PAGE_SIZE, "vnode pager structures");
442 #ifdef __i386__
443 apple_protect_pager_bootstrap();
444 #endif /* __i386__ */
445 return;
446 }
447
448 /*
449 *
450 */
451 memory_object_t
452 vnode_pager_setup(
453 struct vnode *vp,
454 __unused memory_object_t pager)
455 {
456 vnode_pager_t vnode_object;
457
458 vnode_object = vnode_object_create(vp);
459 if (vnode_object == VNODE_PAGER_NULL)
460 panic("vnode_pager_setup: vnode_object_create() failed");
461 return((memory_object_t)vnode_object);
462 }
463
464 /*
465 *
466 */
467 kern_return_t
468 vnode_pager_init(memory_object_t mem_obj,
469 memory_object_control_t control,
470 #if !DEBUG
471 __unused
472 #endif
473 vm_size_t pg_size)
474 {
475 vnode_pager_t vnode_object;
476 kern_return_t kr;
477 memory_object_attr_info_data_t attributes;
478
479
480 PAGER_DEBUG(PAGER_ALL, ("vnode_pager_init: %p, %p, %x\n", mem_obj, control, pg_size));
481
482 if (control == MEMORY_OBJECT_CONTROL_NULL)
483 return KERN_INVALID_ARGUMENT;
484
485 vnode_object = vnode_pager_lookup(mem_obj);
486
487 memory_object_control_reference(control);
488
489 vnode_object->control_handle = control;
490
491 attributes.copy_strategy = MEMORY_OBJECT_COPY_DELAY;
492 /* attributes.cluster_size = (1 << (CLUSTER_SHIFT + PAGE_SHIFT));*/
493 attributes.cluster_size = (1 << (PAGE_SHIFT));
494 attributes.may_cache_object = TRUE;
495 attributes.temporary = TRUE;
496
497 kr = memory_object_change_attributes(
498 control,
499 MEMORY_OBJECT_ATTRIBUTE_INFO,
500 (memory_object_info_t) &attributes,
501 MEMORY_OBJECT_ATTR_INFO_COUNT);
502 if (kr != KERN_SUCCESS)
503 panic("vnode_pager_init: memory_object_change_attributes() failed");
504
505 return(KERN_SUCCESS);
506 }
507
508 /*
509 *
510 */
511 kern_return_t
512 vnode_pager_data_return(
513 memory_object_t mem_obj,
514 memory_object_offset_t offset,
515 vm_size_t data_cnt,
516 memory_object_offset_t *resid_offset,
517 int *io_error,
518 __unused boolean_t dirty,
519 __unused boolean_t kernel_copy,
520 int upl_flags)
521 {
522 register vnode_pager_t vnode_object;
523
524 vnode_object = vnode_pager_lookup(mem_obj);
525
526 vnode_pager_cluster_write(vnode_object, offset, data_cnt, resid_offset, io_error, upl_flags);
527
528 return KERN_SUCCESS;
529 }
530
531 kern_return_t
532 vnode_pager_data_initialize(
533 __unused memory_object_t mem_obj,
534 __unused memory_object_offset_t offset,
535 __unused vm_size_t data_cnt)
536 {
537 panic("vnode_pager_data_initialize");
538 return KERN_FAILURE;
539 }
540
541 kern_return_t
542 vnode_pager_data_unlock(
543 __unused memory_object_t mem_obj,
544 __unused memory_object_offset_t offset,
545 __unused vm_size_t size,
546 __unused vm_prot_t desired_access)
547 {
548 return KERN_FAILURE;
549 }
550
551 kern_return_t
552 vnode_pager_get_object_size(
553 memory_object_t mem_obj,
554 memory_object_offset_t *length)
555 {
556 vnode_pager_t vnode_object;
557
558 if (mem_obj->mo_pager_ops != &vnode_pager_ops) {
559 *length = 0;
560 return KERN_INVALID_ARGUMENT;
561 }
562
563 vnode_object = vnode_pager_lookup(mem_obj);
564
565 *length = vnode_pager_get_filesize(vnode_object->vnode_handle);
566 return KERN_SUCCESS;
567 }
568
569 kern_return_t
570 vnode_pager_get_object_pathname(
571 memory_object_t mem_obj,
572 char *pathname,
573 vm_size_t *length_p)
574 {
575 vnode_pager_t vnode_object;
576
577 if (mem_obj->mo_pager_ops != &vnode_pager_ops) {
578 return KERN_INVALID_ARGUMENT;
579 }
580
581 vnode_object = vnode_pager_lookup(mem_obj);
582
583 return vnode_pager_get_pathname(vnode_object->vnode_handle,
584 pathname,
585 length_p);
586 }
587
588 kern_return_t
589 vnode_pager_get_object_filename(
590 memory_object_t mem_obj,
591 char **filename)
592 {
593 vnode_pager_t vnode_object;
594
595 if (mem_obj->mo_pager_ops != &vnode_pager_ops) {
596 return KERN_INVALID_ARGUMENT;
597 }
598
599 vnode_object = vnode_pager_lookup(mem_obj);
600
601 return vnode_pager_get_filename(vnode_object->vnode_handle,
602 filename);
603 }
604
605 /*
606 *
607 */
608 kern_return_t
609 vnode_pager_data_request(
610 memory_object_t mem_obj,
611 memory_object_offset_t offset,
612 vm_size_t length,
613 #if !DEBUG
614 __unused
615 #endif
616 vm_prot_t protection_required)
617 {
618 register vnode_pager_t vnode_object;
619
620 PAGER_DEBUG(PAGER_ALL, ("vnode_pager_data_request: %x, %x, %x, %x\n", mem_obj, offset, length, protection_required));
621
622 vnode_object = vnode_pager_lookup(mem_obj);
623
624 PAGER_DEBUG(PAGER_PAGEIN, ("vnode_pager_data_request: %x, %x, %x, %x, vnode_object %x\n", mem_obj, offset, length, protection_required, vnode_object));
625
626 return vnode_pager_cluster_read(vnode_object, offset, length);
627 }
628
629 /*
630 *
631 */
632 void
633 vnode_pager_reference(
634 memory_object_t mem_obj)
635 {
636 register vnode_pager_t vnode_object;
637 unsigned int new_ref_count;
638
639 vnode_object = vnode_pager_lookup(mem_obj);
640 new_ref_count = hw_atomic_add(&vnode_object->ref_count, 1);
641 assert(new_ref_count > 1);
642 }
643
644 /*
645 *
646 */
647 void
648 vnode_pager_deallocate(
649 memory_object_t mem_obj)
650 {
651 register vnode_pager_t vnode_object;
652
653 PAGER_DEBUG(PAGER_ALL, ("vnode_pager_deallocate: %x\n", mem_obj));
654
655 vnode_object = vnode_pager_lookup(mem_obj);
656
657 if (hw_atomic_sub(&vnode_object->ref_count, 1) == 0) {
658 if (vnode_object->vnode_handle != NULL) {
659 vnode_pager_vrele(vnode_object->vnode_handle);
660 }
661 zfree(vnode_pager_zone, vnode_object);
662 }
663 return;
664 }
665
666 /*
667 *
668 */
669 kern_return_t
670 vnode_pager_terminate(
671 #if !DEBUG
672 __unused
673 #endif
674 memory_object_t mem_obj)
675 {
676 PAGER_DEBUG(PAGER_ALL, ("vnode_pager_terminate: %x\n", mem_obj));
677
678 return(KERN_SUCCESS);
679 }
680
681 /*
682 *
683 */
684 kern_return_t
685 vnode_pager_synchronize(
686 memory_object_t mem_obj,
687 memory_object_offset_t offset,
688 vm_size_t length,
689 __unused vm_sync_t sync_flags)
690 {
691 register vnode_pager_t vnode_object;
692
693 PAGER_DEBUG(PAGER_ALL, ("vnode_pager_synchronize: %x\n", mem_obj));
694
695 vnode_object = vnode_pager_lookup(mem_obj);
696
697 memory_object_synchronize_completed(vnode_object->control_handle, offset, length);
698
699 return (KERN_SUCCESS);
700 }
701
702 /*
703 *
704 */
705 kern_return_t
706 vnode_pager_unmap(
707 memory_object_t mem_obj)
708 {
709 register vnode_pager_t vnode_object;
710
711 PAGER_DEBUG(PAGER_ALL, ("vnode_pager_unmap: %x\n", mem_obj));
712
713 vnode_object = vnode_pager_lookup(mem_obj);
714
715 ubc_unmap(vnode_object->vnode_handle);
716 return KERN_SUCCESS;
717 }
718
719
720 /*
721 *
722 */
723 void
724 vnode_pager_cluster_write(
725 vnode_pager_t vnode_object,
726 vm_object_offset_t offset,
727 vm_size_t cnt,
728 vm_object_offset_t * resid_offset,
729 int * io_error,
730 int upl_flags)
731 {
732 vm_size_t size;
733 upl_t upl = NULL;
734 int request_flags;
735 int errno;
736
737 if (upl_flags & UPL_MSYNC) {
738
739 upl_flags |= UPL_VNODE_PAGER;
740
741 if ( (upl_flags & UPL_IOSYNC) && io_error)
742 upl_flags |= UPL_KEEPCACHED;
743
744 while (cnt) {
745 kern_return_t kr;
746
747 size = (cnt < (PAGE_SIZE * MAX_UPL_TRANSFER)) ? cnt : (PAGE_SIZE * MAX_UPL_TRANSFER); /* effective max */
748
749 request_flags = UPL_RET_ONLY_DIRTY | UPL_COPYOUT_FROM | UPL_CLEAN_IN_PLACE |
750 UPL_SET_INTERNAL | UPL_SET_LITE;
751
752 kr = memory_object_upl_request(vnode_object->control_handle,
753 offset, size, &upl, NULL, NULL, request_flags);
754 if (kr != KERN_SUCCESS)
755 panic("vnode_pager_cluster_write: upl request failed\n");
756
757 vnode_pageout(vnode_object->vnode_handle,
758 upl, (vm_offset_t)0, offset, size, upl_flags, &errno);
759
760 if ( (upl_flags & UPL_KEEPCACHED) ) {
761 if ( (*io_error = errno) )
762 break;
763 }
764 cnt -= size;
765 offset += size;
766 }
767 if (resid_offset)
768 *resid_offset = offset;
769
770 } else {
771 vm_object_offset_t vnode_size;
772 vm_object_offset_t base_offset;
773 vm_object_t object;
774 vm_page_t target_page;
775 int ticket;
776
777 /*
778 * this is the pageout path
779 */
780 vnode_size = vnode_pager_get_filesize(vnode_object->vnode_handle);
781
782 if (vnode_size > (offset + PAGE_SIZE)) {
783 /*
784 * preset the maximum size of the cluster
785 * and put us on a nice cluster boundary...
786 * and then clip the size to insure we
787 * don't request past the end of the underlying file
788 */
789 size = PAGE_SIZE * MAX_UPL_TRANSFER;
790 base_offset = offset & ~((signed)(size - 1));
791
792 if ((base_offset + size) > vnode_size)
793 size = round_page_32(((vm_size_t)(vnode_size - base_offset)));
794 } else {
795 /*
796 * we've been requested to page out a page beyond the current
797 * end of the 'file'... don't try to cluster in this case...
798 * we still need to send this page through because it might
799 * be marked precious and the underlying filesystem may need
800 * to do something with it (besides page it out)...
801 */
802 base_offset = offset;
803 size = PAGE_SIZE;
804 }
805 object = memory_object_control_to_vm_object(vnode_object->control_handle);
806
807 if (object == VM_OBJECT_NULL)
808 panic("vnode_pager_cluster_write: NULL vm_object in control handle\n");
809
810 request_flags = UPL_NOBLOCK | UPL_FOR_PAGEOUT | UPL_CLEAN_IN_PLACE |
811 UPL_RET_ONLY_DIRTY | UPL_COPYOUT_FROM |
812 UPL_SET_INTERNAL | UPL_SET_LITE;
813
814 vm_object_lock(object);
815
816 if ((target_page = vm_page_lookup(object, offset)) != VM_PAGE_NULL) {
817 /*
818 * only pick up pages whose ticket number matches
819 * the ticket number of the page orginally targeted
820 * for pageout
821 */
822 ticket = target_page->page_ticket;
823
824 request_flags |= ((ticket << UPL_PAGE_TICKET_SHIFT) & UPL_PAGE_TICKET_MASK);
825 }
826 vm_object_unlock(object);
827
828 vm_object_upl_request(object, base_offset, size,
829 &upl, NULL, NULL, request_flags);
830 if (upl == NULL)
831 panic("vnode_pager_cluster_write: upl request failed\n");
832
833 vnode_pageout(vnode_object->vnode_handle,
834 upl, (vm_offset_t)0, upl->offset, upl->size, UPL_VNODE_PAGER, NULL);
835 }
836 }
837
838
839 /*
840 *
841 */
842 kern_return_t
843 vnode_pager_cluster_read(
844 vnode_pager_t vnode_object,
845 vm_object_offset_t offset,
846 vm_size_t cnt)
847 {
848 int local_error = 0;
849 int kret;
850
851 assert(! (cnt & PAGE_MASK));
852
853 kret = vnode_pagein(vnode_object->vnode_handle,
854 (upl_t) NULL,
855 (vm_offset_t) NULL,
856 offset,
857 cnt,
858 0,
859 &local_error);
860 /*
861 if(kret == PAGER_ABSENT) {
862 Need to work out the defs here, 1 corresponds to PAGER_ABSENT
863 defined in bsd/vm/vm_pager.h However, we should not be including
864 that file here it is a layering violation.
865 */
866 if (kret == 1) {
867 int uplflags;
868 upl_t upl = NULL;
869 unsigned int count = 0;
870 kern_return_t kr;
871
872 uplflags = (UPL_NO_SYNC |
873 UPL_CLEAN_IN_PLACE |
874 UPL_SET_INTERNAL);
875 count = 0;
876 kr = memory_object_upl_request(vnode_object->control_handle,
877 offset, cnt,
878 &upl, NULL, &count, uplflags);
879 if (kr == KERN_SUCCESS) {
880 upl_abort(upl, 0);
881 upl_deallocate(upl);
882 } else {
883 /*
884 * We couldn't gather the page list, probably
885 * because the memory object doesn't have a link
886 * to a VM object anymore (forced unmount, for
887 * example). Just return an error to the vm_fault()
888 * path and let it handle it.
889 */
890 }
891
892 return KERN_FAILURE;
893 }
894
895 return KERN_SUCCESS;
896
897 }
898
899
900 /*
901 *
902 */
903 void
904 vnode_pager_release_from_cache(
905 int *cnt)
906 {
907 memory_object_free_from_cache(
908 &realhost, &vnode_pager_ops, cnt);
909 }
910
911 /*
912 *
913 */
914 vnode_pager_t
915 vnode_object_create(
916 struct vnode *vp)
917 {
918 register vnode_pager_t vnode_object;
919
920 vnode_object = (struct vnode_pager *) zalloc(vnode_pager_zone);
921 if (vnode_object == VNODE_PAGER_NULL)
922 return(VNODE_PAGER_NULL);
923
924 /*
925 * The vm_map call takes both named entry ports and raw memory
926 * objects in the same parameter. We need to make sure that
927 * vm_map does not see this object as a named entry port. So,
928 * we reserve the second word in the object for a fake ip_kotype
929 * setting - that will tell vm_map to use it as a memory object.
930 */
931 vnode_object->pager_ops = &vnode_pager_ops;
932 vnode_object->pager_ikot = IKOT_MEMORY_OBJECT;
933 vnode_object->ref_count = 1;
934 vnode_object->control_handle = MEMORY_OBJECT_CONTROL_NULL;
935 vnode_object->vnode_handle = vp;
936
937 return(vnode_object);
938 }
939
940 /*
941 *
942 */
943 vnode_pager_t
944 vnode_pager_lookup(
945 memory_object_t name)
946 {
947 vnode_pager_t vnode_object;
948
949 vnode_object = (vnode_pager_t)name;
950 assert(vnode_object->pager_ops == &vnode_pager_ops);
951 return (vnode_object);
952 }
953
954
955 /*********************** proc_info implementation *************/
956
957 #include <sys/bsdtask_info.h>
958
959 static int fill_vnodeinfoforaddr( vm_map_entry_t entry, uint32_t * vnodeaddr, uint32_t * vid);
960
961
962 int
963 fill_procregioninfo(task_t task, uint64_t arg, struct proc_regioninfo_internal *pinfo, uint32_t *vnodeaddr, uint32_t *vid)
964 {
965
966 vm_map_t map = task->map;
967 vm_map_offset_t address = (vm_map_offset_t )arg;
968 vm_map_entry_t tmp_entry;
969 vm_map_entry_t entry;
970 vm_map_offset_t start;
971 vm_region_extended_info_data_t extended;
972 vm_region_top_info_data_t top;
973
974
975 if (map == VM_MAP_NULL)
976 return(0);
977
978 vm_map_lock_read(map);
979
980 start = address;
981 if (!vm_map_lookup_entry(map, start, &tmp_entry)) {
982 if ((entry = tmp_entry->vme_next) == vm_map_to_entry(map)) {
983 vm_map_unlock_read(map);
984 return(0);
985 }
986 } else {
987 entry = tmp_entry;
988 }
989
990 start = entry->vme_start;
991
992 pinfo->pri_offset = entry->offset;
993 pinfo->pri_protection = entry->protection;
994 pinfo->pri_max_protection = entry->max_protection;
995 pinfo->pri_inheritance = entry->inheritance;
996 pinfo->pri_behavior = entry->behavior;
997 pinfo->pri_user_wired_count = entry->user_wired_count;
998 pinfo->pri_user_tag = entry->alias;
999
1000 if (entry->is_sub_map) {
1001 pinfo->pri_flags |= PROC_REGION_SUBMAP;
1002 } else {
1003 if (entry->is_shared)
1004 pinfo->pri_flags |= PROC_REGION_SHARED;
1005 }
1006
1007
1008 extended.protection = entry->protection;
1009 extended.user_tag = entry->alias;
1010 extended.pages_resident = 0;
1011 extended.pages_swapped_out = 0;
1012 extended.pages_shared_now_private = 0;
1013 extended.pages_dirtied = 0;
1014 extended.external_pager = 0;
1015 extended.shadow_depth = 0;
1016
1017 vm_map_region_walk(map, start, entry, entry->offset, entry->vme_end - start, &extended);
1018
1019 if (extended.external_pager && extended.ref_count == 2 && extended.share_mode == SM_SHARED)
1020 extended.share_mode = SM_PRIVATE;
1021
1022 top.private_pages_resident = 0;
1023 top.shared_pages_resident = 0;
1024 vm_map_region_top_walk(entry, &top);
1025
1026
1027 pinfo->pri_pages_resident = extended.pages_resident;
1028 pinfo->pri_pages_shared_now_private = extended.pages_shared_now_private;
1029 pinfo->pri_pages_swapped_out = extended.pages_swapped_out;
1030 pinfo->pri_pages_dirtied = extended.pages_dirtied;
1031 pinfo->pri_ref_count = extended.ref_count;
1032 pinfo->pri_shadow_depth = extended.shadow_depth;
1033 pinfo->pri_share_mode = extended.share_mode;
1034
1035 pinfo->pri_private_pages_resident = top.private_pages_resident;
1036 pinfo->pri_shared_pages_resident = top.shared_pages_resident;
1037 pinfo->pri_obj_id = top.obj_id;
1038
1039 pinfo->pri_address = (uint64_t)start;
1040 pinfo->pri_size = (uint64_t)(entry->vme_end - start);
1041 pinfo->pri_depth = 0;
1042
1043 if ((vnodeaddr != 0) && (entry->is_sub_map == 0)) {
1044 *vnodeaddr = (uint32_t)0;
1045
1046 if (fill_vnodeinfoforaddr(entry, vnodeaddr, vid) ==0) {
1047 vm_map_unlock_read(map);
1048 return(1);
1049 }
1050 }
1051
1052 vm_map_unlock_read(map);
1053 return(1);
1054 }
1055
1056 static int
1057 fill_vnodeinfoforaddr(
1058 vm_map_entry_t entry,
1059 uint32_t * vnodeaddr,
1060 uint32_t * vid)
1061 {
1062 vm_object_t top_object, object;
1063 memory_object_t memory_object;
1064 memory_object_pager_ops_t pager_ops;
1065 kern_return_t kr;
1066 int shadow_depth;
1067
1068
1069 if (entry->is_sub_map) {
1070 return(0);
1071 } else {
1072 /*
1073 * The last object in the shadow chain has the
1074 * relevant pager information.
1075 */
1076 top_object = entry->object.vm_object;
1077 if (top_object == VM_OBJECT_NULL) {
1078 object = VM_OBJECT_NULL;
1079 shadow_depth = 0;
1080 } else {
1081 vm_object_lock(top_object);
1082 for (object = top_object, shadow_depth = 0;
1083 object->shadow != VM_OBJECT_NULL;
1084 object = object->shadow, shadow_depth++) {
1085 vm_object_lock(object->shadow);
1086 vm_object_unlock(object);
1087 }
1088 }
1089 }
1090
1091 if (object == VM_OBJECT_NULL) {
1092 return(0);
1093 } else if (object->internal) {
1094 vm_object_unlock(object);
1095 return(0);
1096 } else if (! object->pager_ready ||
1097 object->terminating ||
1098 ! object->alive) {
1099 vm_object_unlock(object);
1100 return(0);
1101 } else {
1102 memory_object = object->pager;
1103 pager_ops = memory_object->mo_pager_ops;
1104 if (pager_ops == &vnode_pager_ops) {
1105 kr = vnode_pager_get_object_vnode(
1106 memory_object,
1107 vnodeaddr, vid);
1108 if (kr != KERN_SUCCESS) {
1109 vm_object_unlock(object);
1110 return(0);
1111 }
1112 } else {
1113 vm_object_unlock(object);
1114 return(0);
1115 }
1116 }
1117 vm_object_unlock(object);
1118 return(1);
1119 }
1120
1121 kern_return_t
1122 vnode_pager_get_object_vnode (
1123 memory_object_t mem_obj,
1124 uint32_t * vnodeaddr,
1125 uint32_t * vid)
1126 {
1127 vnode_pager_t vnode_object;
1128
1129 vnode_object = vnode_pager_lookup(mem_obj);
1130 if (vnode_object->vnode_handle) {
1131 *vnodeaddr = (uint32_t)vnode_object->vnode_handle;
1132 *vid = (uint32_t)vnode_vid((void *)vnode_object->vnode_handle);
1133
1134 return(KERN_SUCCESS);
1135 }
1136
1137 return(KERN_FAILURE);
1138 }
1139