2 * Copyright (c) 2000-2001 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 #include <sys/errno.h>
27 #include <kern/host.h>
28 #include <mach/mach_types.h>
29 #include <vm/vm_map.h>
30 #include <vm/vm_kern.h>
31 #include <vm/vm_pageout.h>
32 #include <mach/kern_return.h>
33 #include <mach/memory_object_types.h>
34 #include <mach/port.h>
35 #include <mach/policy.h>
36 #include <ipc/ipc_port.h>
37 #include <ipc/ipc_space.h>
38 #include <kern/thread.h>
39 #include <vm/memory_object.h>
40 #include <vm/vm_pageout.h>
42 #include <default_pager/default_pager_types.h>
44 /* BSD VM COMPONENT INTERFACES */
64 return(map
->hdr
.nentries
);
74 return(vm_map_first_entry(map
)->vme_start
);
84 return(vm_map_last_entry(map
)->vme_end
);
91 /* until component support available */
92 int vnode_pager_workaround
;
94 typedef int vnode_port_t
;
96 typedef struct vnode_pager
{
97 int *pager
; /* pager workaround pointer */
98 unsigned int pager_ikot
; /* JMM: fake ip_kotype() */
99 unsigned int ref_count
; /* reference count */
100 memory_object_control_t control_handle
; /* mem object control handle */
101 vnode_port_t vnode_handle
; /* vnode handle */
106 trigger_name_to_port(
110 vnode_pager_bootstrap(
114 vnode_pager_alloc_map(
126 memory_object_control_t
,
130 vnode_pager_get_object_size(
132 memory_object_offset_t
*);
135 vnode_pager_data_request(
137 memory_object_offset_t
,
142 vnode_pager_data_return(
144 memory_object_offset_t
,
150 vnode_pager_data_initialize(
152 memory_object_offset_t
,
156 vnode_pager_deallocate(
160 vnode_pager_terminate(
164 vnode_pager_cluster_read(
170 vnode_pager_cluster_write(
196 vnode_pager_get_filesize(
208 vnode_pager_release_from_cache(
211 zone_t vnode_pager_zone
;
214 #define VNODE_PAGER_NULL ((vnode_pager_t) 0)
216 /* TODO: Should be set dynamically by vnode_pager_init() */
217 #define CLUSTER_SHIFT 1
219 /* TODO: Should be set dynamically by vnode_pager_bootstrap() */
220 #define MAX_VNODE 10000
226 #define PAGER_ALL 0xffffffff
227 #define PAGER_INIT 0x00000001
228 #define PAGER_PAGEIN 0x00000002
230 #define PAGER_DEBUG(LEVEL, A) {if ((pagerdebug & LEVEL)==LEVEL){printf A;}}
232 #define PAGER_DEBUG(LEVEL, A)
236 * Routine: macx_triggers
238 * Syscall interface to set the call backs for low and
246 mach_port_t trigger_name
)
249 memory_object_default_t default_pager
;
250 ipc_port_t trigger_port
;
252 default_pager
= MEMORY_OBJECT_DEFAULT_NULL
;
253 kr
= host_default_memory_manager(host_priv_self(),
255 if(kr
!= KERN_SUCCESS
) {
258 if (flags
& HI_WAT_ALERT
) {
259 trigger_port
= trigger_name_to_port(trigger_name
);
260 if(trigger_port
== NULL
) {
263 /* trigger_port is locked and active */
264 ipc_port_make_send_locked(trigger_port
);
266 default_pager_triggers(default_pager
,
268 HI_WAT_ALERT
, trigger_port
);
271 if (flags
& LO_WAT_ALERT
) {
272 trigger_port
= trigger_name_to_port(trigger_name
);
273 if(trigger_port
== NULL
) {
276 /* trigger_port is locked and active */
277 ipc_port_make_send_locked(trigger_port
);
278 /* and now its unlocked */
279 default_pager_triggers(default_pager
,
281 LO_WAT_ALERT
, trigger_port
);
285 * Set thread scheduling priority and policy for the current thread
286 * it is assumed for the time being that the thread setting the alert
287 * is the same one which will be servicing it.
289 * XXX This does not belong in the kernel XXX
292 thread_precedence_policy_data_t pre
;
293 thread_extended_policy_data_t ext
;
295 ext
.timeshare
= FALSE
;
296 pre
.importance
= INT32_MAX
;
298 thread_policy_set(current_act(),
299 THREAD_EXTENDED_POLICY
, (thread_policy_t
)&ext
,
300 THREAD_EXTENDED_POLICY_COUNT
);
302 thread_policy_set(current_act(),
303 THREAD_PRECEDENCE_POLICY
, (thread_policy_t
)&pre
,
304 THREAD_PRECEDENCE_POLICY_COUNT
);
307 current_thread()->vm_privilege
= TRUE
;
314 trigger_name_to_port(
315 mach_port_t trigger_name
)
317 ipc_port_t trigger_port
;
320 if (trigger_name
== 0)
323 space
= current_space();
324 if(ipc_port_translate_receive(space
, (mach_port_name_t
)trigger_name
,
325 &trigger_port
) != KERN_SUCCESS
)
334 vnode_pager_bootstrap(void)
336 register vm_size_t size
;
338 size
= (vm_size_t
) sizeof(struct vnode_pager
);
339 vnode_pager_zone
= zinit(size
, (vm_size_t
) MAX_VNODE
*size
,
340 PAGE_SIZE
, "vnode pager structures");
350 memory_object_t pager
)
352 vnode_pager_t vnode_object
;
354 vnode_object
= vnode_object_create(vp
);
355 if (vnode_object
== VNODE_PAGER_NULL
)
356 panic("vnode_pager_setup: vnode_object_create() failed");
357 return((memory_object_t
)vnode_object
);
364 vnode_pager_init(memory_object_t mem_obj
,
365 memory_object_control_t control
,
368 vnode_pager_t vnode_object
;
370 memory_object_attr_info_data_t attributes
;
373 PAGER_DEBUG(PAGER_ALL
, ("vnode_pager_init: %x, %x, %x\n", pager
, pager_request
, pg_size
));
375 if (control
== MEMORY_OBJECT_CONTROL_NULL
)
376 return KERN_INVALID_ARGUMENT
;
378 vnode_object
= vnode_pager_lookup(mem_obj
);
380 memory_object_control_reference(control
);
381 vnode_object
->control_handle
= control
;
383 attributes
.copy_strategy
= MEMORY_OBJECT_COPY_DELAY
;
384 /* attributes.cluster_size = (1 << (CLUSTER_SHIFT + PAGE_SHIFT));*/
385 attributes
.cluster_size
= (1 << (PAGE_SHIFT
));
386 attributes
.may_cache_object
= TRUE
;
387 attributes
.temporary
= TRUE
;
389 kr
= memory_object_change_attributes(
391 MEMORY_OBJECT_ATTRIBUTE_INFO
,
392 (memory_object_info_t
) &attributes
,
393 MEMORY_OBJECT_ATTR_INFO_COUNT
);
394 if (kr
!= KERN_SUCCESS
)
395 panic("vnode_pager_init: memory_object_change_attributes() failed");
397 return(KERN_SUCCESS
);
404 vnode_pager_data_return(
405 memory_object_t mem_obj
,
406 memory_object_offset_t offset
,
409 boolean_t kernel_copy
)
411 register vnode_pager_t vnode_object
;
413 vnode_object
= vnode_pager_lookup(mem_obj
);
415 vnode_pager_cluster_write(vnode_object
, offset
, data_cnt
);
421 vnode_pager_data_initialize(
422 memory_object_t mem_obj
,
423 memory_object_offset_t offset
,
430 vnode_pager_data_unlock(
431 memory_object_t mem_obj
,
432 memory_object_offset_t offset
,
434 vm_prot_t desired_access
)
440 vnode_pager_get_object_size(
441 memory_object_t mem_obj
,
442 memory_object_offset_t
*length
)
444 vnode_pager_t vnode_object
;
446 vnode_object
= vnode_pager_lookup(mem_obj
);
448 *length
= vnode_pager_get_filesize(vnode_object
->vnode_handle
);
456 vnode_pager_data_request(
457 memory_object_t mem_obj
,
458 memory_object_offset_t offset
,
460 vm_prot_t protection_required
)
462 register vnode_pager_t vnode_object
;
464 PAGER_DEBUG(PAGER_ALL
, ("vnode_pager_data_request: %x, %x, %x, %x\n", mem_obj
, offset
, length
, protection_required
));
466 vnode_object
= vnode_pager_lookup(mem_obj
);
468 PAGER_DEBUG(PAGER_PAGEIN
, ("vnode_pager_data_request: %x, %x, %x, %x, vnode_object %x\n", mem_obj
, offset
, length
, protection_required
, vnode_object
));
470 vnode_pager_cluster_read(vnode_object
, offset
, length
);
479 vnode_pager_reference(
480 memory_object_t mem_obj
)
482 register vnode_pager_t vnode_object
;
483 unsigned int new_ref_count
;
485 vnode_object
= vnode_pager_lookup(mem_obj
);
486 new_ref_count
= hw_atomic_add(&vnode_object
->ref_count
, 1);
487 assert(new_ref_count
> 1);
494 vnode_pager_deallocate(
495 memory_object_t mem_obj
)
497 register vnode_pager_t vnode_object
;
499 PAGER_DEBUG(PAGER_ALL
, ("vnode_pager_deallocate: %x\n", mem_obj
));
501 vnode_object
= vnode_pager_lookup(mem_obj
);
503 if (hw_atomic_sub(&vnode_object
->ref_count
, 1) == 0) {
504 if (vnode_object
->vnode_handle
!= (vnode_port_t
) NULL
) {
505 vnode_pager_vrele(vnode_object
->vnode_handle
);
507 zfree(vnode_pager_zone
, (vm_offset_t
) vnode_object
);
516 vnode_pager_terminate(
517 memory_object_t mem_obj
)
519 PAGER_DEBUG(PAGER_ALL
, ("vnode_pager_terminate: %x\n", mem_obj
));
521 return(KERN_SUCCESS
);
528 vnode_pager_synchronize(
529 memory_object_t mem_obj
,
530 memory_object_offset_t offset
,
532 vm_sync_t sync_flags
)
534 register vnode_pager_t vnode_object
;
536 PAGER_DEBUG(PAGER_ALL
, ("vnode_pager_synchronize: %x\n", mem_obj
));
538 vnode_object
= vnode_pager_lookup(mem_obj
);
540 memory_object_synchronize_completed(vnode_object
->control_handle
, offset
, length
);
542 return (KERN_SUCCESS
);
550 memory_object_t mem_obj
)
552 register vnode_pager_t vnode_object
;
554 PAGER_DEBUG(PAGER_ALL
, ("vnode_pager_unmap: %x\n", mem_obj
));
556 vnode_object
= vnode_pager_lookup(mem_obj
);
558 ubc_unmap(vnode_object
->vnode_handle
);
567 vnode_pager_cluster_write(
568 vnode_pager_t vnode_object
,
569 vm_object_offset_t offset
,
577 if (cnt
& PAGE_MASK
) {
578 panic("vs_cluster_write: cnt not a multiple of PAGE_SIZE");
580 size
= (cnt
< (PAGE_SIZE
*32)) ? cnt
: (PAGE_SIZE
*32); /* effective min */
584 kret
= vnode_pageout(vnode_object
->vnode_handle
,
585 (upl_t
)NULL
, (vm_offset_t
)NULL
,
586 offset
, size
, 0, &local_error
);
588 if(kret == PAGER_ABSENT) {
589 Need to work out the defs here, 1 corresponds to
590 PAGER_ABSENT defined in bsd/vm/vm_pager.h However,
591 we should not be including that file here it is a
600 uplflags
= (UPL_NO_SYNC
| UPL_CLEAN_IN_PLACE
|
601 UPL_SET_INTERNAL
| UPL_COPYOUT_FROM
);
603 kr
= memory_object_upl_request(
604 vnode_object
->control_handle
,
605 offset
, size
, &upl
, NULL
, &count
, uplflags
);
606 if(kr
!= KERN_SUCCESS
) {
607 panic("vnode_pager_cluster_write: upl request failed\n");
616 if (local_error
!= 0) {
622 size
= (cnt
< (PAGE_SIZE
*32)) ? cnt
: (PAGE_SIZE
*32); /* effective min */
626 return(KERN_FAILURE
);
628 return(KERN_SUCCESS
);
637 vnode_pager_cluster_read(
638 vnode_pager_t vnode_object
,
639 vm_object_offset_t offset
,
646 if(cnt
& PAGE_MASK
) {
647 panic("vs_cluster_read: cnt not a multiple of PAGE_SIZE");
650 kret
= vnode_pagein(vnode_object
->vnode_handle
, (upl_t
)NULL
, (vm_offset_t
)NULL
, offset
, cnt
, 0, &local_error
);
652 if(kret == PAGER_ABSENT) {
653 Need to work out the defs here, 1 corresponds to PAGER_ABSENT
654 defined in bsd/vm/vm_pager.h However, we should not be including
655 that file here it is a layering violation.
663 uplflags
= (UPL_NO_SYNC
|
664 UPL_CLEAN_IN_PLACE
| UPL_SET_INTERNAL
);
666 kr
= memory_object_upl_request(
667 vnode_object
->control_handle
, offset
, cnt
,
668 &upl
, NULL
, &count
, uplflags
);
669 if(kr
!= KERN_SUCCESS
) {
670 panic("vnode_pager_cluster_read: upl request failed\n");
679 return(KERN_FAILURE
);
681 return(KERN_SUCCESS
);
690 vnode_pager_release_from_cache(
693 memory_object_free_from_cache(
694 &realhost
, &vnode_pager_workaround
, cnt
);
704 register vnode_pager_t vnode_object
;
706 vnode_object
= (struct vnode_pager
*) zalloc(vnode_pager_zone
);
707 if (vnode_object
== VNODE_PAGER_NULL
)
708 return(VNODE_PAGER_NULL
);
711 * The vm_map call takes both named entry ports and raw memory
712 * objects in the same parameter. We need to make sure that
713 * vm_map does not see this object as a named entry port. So,
714 * we reserve the second word in the object for a fake ip_kotype
715 * setting - that will tell vm_map to use it as a memory object.
717 vnode_object
->pager
= &vnode_pager_workaround
;
718 vnode_object
->pager_ikot
= IKOT_MEMORY_OBJECT
;
719 vnode_object
->ref_count
= 1;
720 vnode_object
->control_handle
= MEMORY_OBJECT_CONTROL_NULL
;
721 vnode_object
->vnode_handle
= vp
;
723 return(vnode_object
);
731 memory_object_t name
)
733 vnode_pager_t vnode_object
;
735 vnode_object
= (vnode_pager_t
)name
;
736 assert(vnode_object
->pager
== &vnode_pager_workaround
);
737 return (vnode_object
);