]> git.saurik.com Git - apple/xnu.git/blob - osfmk/vm/vm_swapfile_pager.c
388d0fb569162029fc4e03f27e106fd0a03c3dfb
[apple/xnu.git] / osfmk / vm / vm_swapfile_pager.c
1 /*
2 * Copyright (c) 2008-2020 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #include <mach/kern_return.h>
30 #include <mach/memory_object_control.h>
31 #include <mach/upl.h>
32
33 #include <kern/ipc_kobject.h>
34 #include <kern/kalloc.h>
35 #include <kern/queue.h>
36
37 #include <vm/memory_object.h>
38 #include <vm/vm_kern.h>
39 #include <vm/vm_map.h>
40 #include <vm/vm_pageout.h>
41 #include <vm/vm_protos.h>
42
43
44 /*
45 * APPLE SWAPFILE MEMORY PAGER
46 *
47 * This external memory manager (EMM) handles mappings of the swap files.
48 * Swap files are not regular files and are used solely to store contents of
49 * anonymous memory mappings while not resident in memory.
50 * There's no valid reason to map a swap file. This just puts extra burden
51 * on the system, is potentially a security issue and is not reliable since
52 * the contents can change at any time with pageout operations.
53 * Here are some of the issues with mapping a swap file.
54 * * PERFORMANCE:
55 * Each page in the swap file belong to an anonymous memory object. Mapping
56 * the swap file makes those pages also accessible via a vnode memory
57 * object and each page can now be resident twice.
58 * * SECURITY:
59 * Mapping a swap file allows access to other processes' memory. Swap files
60 * are only accessible by the "root" super-user, who can already access any
61 * process's memory, so this is not a real issue but if permissions on the
62 * swap file got changed, it could become one.
63 * Swap files are not "zero-filled" on creation, so until their contents are
64 * overwritten with pageout operations, they still contain whatever was on
65 * the disk blocks they were allocated. The "super-user" could see the
66 * contents of free blocks anyway, so this is not a new security issue but
67 * it may be perceive as one.
68 *
69 * We can't legitimately prevent a user process with appropriate privileges
70 * from mapping a swap file, but we can prevent it from accessing its actual
71 * contents.
72 * This pager mostly handles page-in request (from memory_object_data_request())
73 * for swap file mappings and just returns bogus data.
74 * Pageouts are not handled, so mmap() has to make sure it does not allow
75 * writable (i.e. MAP_SHARED and PROT_WRITE) mappings of swap files.
76 */
77
78 /* forward declarations */
79 void swapfile_pager_reference(memory_object_t mem_obj);
80 void swapfile_pager_deallocate(memory_object_t mem_obj);
81 kern_return_t swapfile_pager_init(memory_object_t mem_obj,
82 memory_object_control_t control,
83 memory_object_cluster_size_t pg_size);
84 kern_return_t swapfile_pager_terminate(memory_object_t mem_obj);
85 kern_return_t swapfile_pager_data_request(memory_object_t mem_obj,
86 memory_object_offset_t offset,
87 memory_object_cluster_size_t length,
88 vm_prot_t protection_required,
89 memory_object_fault_info_t fault_info);
90 kern_return_t swapfile_pager_data_return(memory_object_t mem_obj,
91 memory_object_offset_t offset,
92 memory_object_cluster_size_t data_cnt,
93 memory_object_offset_t *resid_offset,
94 int *io_error,
95 boolean_t dirty,
96 boolean_t kernel_copy,
97 int upl_flags);
98 kern_return_t swapfile_pager_data_initialize(memory_object_t mem_obj,
99 memory_object_offset_t offset,
100 memory_object_cluster_size_t data_cnt);
101 kern_return_t swapfile_pager_data_unlock(memory_object_t mem_obj,
102 memory_object_offset_t offset,
103 memory_object_size_t size,
104 vm_prot_t desired_access);
105 kern_return_t swapfile_pager_synchronize(memory_object_t mem_obj,
106 memory_object_offset_t offset,
107 memory_object_size_t length,
108 vm_sync_t sync_flags);
109 kern_return_t swapfile_pager_map(memory_object_t mem_obj,
110 vm_prot_t prot);
111 kern_return_t swapfile_pager_last_unmap(memory_object_t mem_obj);
112
113 /*
114 * Vector of VM operations for this EMM.
115 * These routines are invoked by VM via the memory_object_*() interfaces.
116 */
117 const struct memory_object_pager_ops swapfile_pager_ops = {
118 .memory_object_reference = swapfile_pager_reference,
119 .memory_object_deallocate = swapfile_pager_deallocate,
120 .memory_object_init = swapfile_pager_init,
121 .memory_object_terminate = swapfile_pager_terminate,
122 .memory_object_data_request = swapfile_pager_data_request,
123 .memory_object_data_return = swapfile_pager_data_return,
124 .memory_object_data_initialize = swapfile_pager_data_initialize,
125 .memory_object_data_unlock = swapfile_pager_data_unlock,
126 .memory_object_synchronize = swapfile_pager_synchronize,
127 .memory_object_map = swapfile_pager_map,
128 .memory_object_last_unmap = swapfile_pager_last_unmap,
129 .memory_object_data_reclaim = NULL,
130 .memory_object_backing_object = NULL,
131 .memory_object_pager_name = "swapfile pager"
132 };
133
134 /*
135 * The "swapfile_pager" describes a memory object backed by
136 * the "swapfile" EMM.
137 */
138 typedef struct swapfile_pager {
139 /* mandatory generic header */
140 struct memory_object swp_pgr_hdr;
141
142 /* pager-specific data */
143 queue_chain_t pager_queue; /* next & prev pagers */
144 unsigned int ref_count; /* reference count */
145 boolean_t is_ready; /* is this pager ready ? */
146 boolean_t is_mapped; /* is this pager mapped ? */
147 struct vnode *swapfile_vnode;/* the swapfile's vnode */
148 } *swapfile_pager_t;
149 #define SWAPFILE_PAGER_NULL ((swapfile_pager_t) NULL)
150
151 /*
152 * List of memory objects managed by this EMM.
153 * The list is protected by the "swapfile_pager_lock" lock.
154 */
155 int swapfile_pager_count = 0; /* number of pagers */
156 queue_head_t swapfile_pager_queue = QUEUE_HEAD_INITIALIZER(swapfile_pager_queue);
157 LCK_GRP_DECLARE(swapfile_pager_lck_grp, "swapfile pager");
158 LCK_MTX_DECLARE(swapfile_pager_lock, &swapfile_pager_lck_grp);
159
160 /*
161 * Statistics & counters.
162 */
163 int swapfile_pager_count_max = 0;
164
165 /* internal prototypes */
166 swapfile_pager_t swapfile_pager_create(struct vnode *vp);
167 swapfile_pager_t swapfile_pager_lookup(memory_object_t mem_obj);
168 void swapfile_pager_dequeue(swapfile_pager_t pager);
169 void swapfile_pager_deallocate_internal(swapfile_pager_t pager,
170 boolean_t locked);
171 void swapfile_pager_terminate_internal(swapfile_pager_t pager);
172
173
174 #if DEBUG
175 int swapfile_pagerdebug = 0;
176 #define PAGER_ALL 0xffffffff
177 #define PAGER_INIT 0x00000001
178 #define PAGER_PAGEIN 0x00000002
179
180 #define PAGER_DEBUG(LEVEL, A) \
181 MACRO_BEGIN \
182 if ((swapfile_pagerdebug & LEVEL)==LEVEL) { \
183 printf A; \
184 } \
185 MACRO_END
186 #else
187 #define PAGER_DEBUG(LEVEL, A)
188 #endif
189
190
191 /*
192 * swapfile_pager_init()
193 *
194 * Initialize the memory object and makes it ready to be used and mapped.
195 */
196 kern_return_t
197 swapfile_pager_init(
198 memory_object_t mem_obj,
199 memory_object_control_t control,
200 #if !DEBUG
201 __unused
202 #endif
203 memory_object_cluster_size_t pg_size)
204 {
205 swapfile_pager_t pager;
206 kern_return_t kr;
207 memory_object_attr_info_data_t attributes;
208
209 PAGER_DEBUG(PAGER_ALL,
210 ("swapfile_pager_init: %p, %p, %x\n",
211 mem_obj, control, pg_size));
212
213 if (control == MEMORY_OBJECT_CONTROL_NULL) {
214 return KERN_INVALID_ARGUMENT;
215 }
216
217 pager = swapfile_pager_lookup(mem_obj);
218
219 memory_object_control_reference(control);
220
221 pager->swp_pgr_hdr.mo_control = control;
222
223 attributes.copy_strategy = MEMORY_OBJECT_COPY_DELAY;
224 attributes.cluster_size = (1 << (PAGE_SHIFT));
225 attributes.may_cache_object = FALSE;
226 attributes.temporary = TRUE;
227
228 kr = memory_object_change_attributes(
229 control,
230 MEMORY_OBJECT_ATTRIBUTE_INFO,
231 (memory_object_info_t) &attributes,
232 MEMORY_OBJECT_ATTR_INFO_COUNT);
233 if (kr != KERN_SUCCESS) {
234 panic("swapfile_pager_init: "
235 "memory_object_change_attributes() failed");
236 }
237
238 return KERN_SUCCESS;
239 }
240
241 /*
242 * swapfile_data_return()
243 *
244 * Handles page-out requests from VM. This should never happen since
245 * the pages provided by this EMM are not supposed to be dirty or dirtied
246 * and VM should simply discard the contents and reclaim the pages if it
247 * needs to.
248 */
249 kern_return_t
250 swapfile_pager_data_return(
251 __unused memory_object_t mem_obj,
252 __unused memory_object_offset_t offset,
253 __unused memory_object_cluster_size_t data_cnt,
254 __unused memory_object_offset_t *resid_offset,
255 __unused int *io_error,
256 __unused boolean_t dirty,
257 __unused boolean_t kernel_copy,
258 __unused int upl_flags)
259 {
260 panic("swapfile_pager_data_return: should never get called");
261 return KERN_FAILURE;
262 }
263
264 kern_return_t
265 swapfile_pager_data_initialize(
266 __unused memory_object_t mem_obj,
267 __unused memory_object_offset_t offset,
268 __unused memory_object_cluster_size_t data_cnt)
269 {
270 panic("swapfile_pager_data_initialize: should never get called");
271 return KERN_FAILURE;
272 }
273
274 kern_return_t
275 swapfile_pager_data_unlock(
276 __unused memory_object_t mem_obj,
277 __unused memory_object_offset_t offset,
278 __unused memory_object_size_t size,
279 __unused vm_prot_t desired_access)
280 {
281 return KERN_FAILURE;
282 }
283
284 /*
285 * swapfile_pager_data_request()
286 *
287 * Handles page-in requests from VM.
288 */
289 kern_return_t
290 swapfile_pager_data_request(
291 memory_object_t mem_obj,
292 memory_object_offset_t offset,
293 memory_object_cluster_size_t length,
294 #if !DEBUG
295 __unused
296 #endif
297 vm_prot_t protection_required,
298 __unused memory_object_fault_info_t mo_fault_info)
299 {
300 swapfile_pager_t pager;
301 memory_object_control_t mo_control;
302 upl_t upl;
303 int upl_flags;
304 upl_size_t upl_size;
305 upl_page_info_t *upl_pl = NULL;
306 unsigned int pl_count;
307 vm_object_t dst_object;
308 kern_return_t kr, retval;
309 vm_map_offset_t kernel_mapping;
310 vm_offset_t dst_vaddr;
311 char *dst_ptr;
312 vm_offset_t cur_offset;
313 vm_map_entry_t map_entry;
314
315 PAGER_DEBUG(PAGER_ALL, ("swapfile_pager_data_request: %p, %llx, %x, %x\n", mem_obj, offset, length, protection_required));
316
317 kernel_mapping = 0;
318 upl = NULL;
319 upl_pl = NULL;
320
321 pager = swapfile_pager_lookup(mem_obj);
322 assert(pager->is_ready);
323 assert(pager->ref_count > 1); /* pager is alive and mapped */
324
325 PAGER_DEBUG(PAGER_PAGEIN, ("swapfile_pager_data_request: %p, %llx, %x, %x, pager %p\n", mem_obj, offset, length, protection_required, pager));
326
327 /*
328 * Gather in a UPL all the VM pages requested by VM.
329 */
330 mo_control = pager->swp_pgr_hdr.mo_control;
331
332 upl_size = length;
333 upl_flags =
334 UPL_RET_ONLY_ABSENT |
335 UPL_SET_LITE |
336 UPL_NO_SYNC |
337 UPL_CLEAN_IN_PLACE | /* triggers UPL_CLEAR_DIRTY */
338 UPL_SET_INTERNAL;
339 pl_count = 0;
340 kr = memory_object_upl_request(mo_control,
341 offset, upl_size,
342 &upl, NULL, NULL, upl_flags, VM_KERN_MEMORY_OSFMK);
343 if (kr != KERN_SUCCESS) {
344 retval = kr;
345 goto done;
346 }
347 dst_object = mo_control->moc_object;
348 assert(dst_object != VM_OBJECT_NULL);
349
350
351 /*
352 * Reserve a virtual page in the kernel address space to map each
353 * destination physical page when it's its turn to be processed.
354 */
355 vm_object_reference(kernel_object); /* ref. for mapping */
356 kr = vm_map_find_space(kernel_map,
357 &kernel_mapping,
358 PAGE_SIZE_64,
359 0,
360 0,
361 VM_MAP_KERNEL_FLAGS_NONE,
362 VM_KERN_MEMORY_NONE,
363 &map_entry);
364 if (kr != KERN_SUCCESS) {
365 vm_object_deallocate(kernel_object);
366 retval = kr;
367 goto done;
368 }
369 VME_OBJECT_SET(map_entry, kernel_object);
370 VME_OFFSET_SET(map_entry, kernel_mapping - VM_MIN_KERNEL_ADDRESS);
371 vm_map_unlock(kernel_map);
372 dst_vaddr = CAST_DOWN(vm_offset_t, kernel_mapping);
373 dst_ptr = (char *) dst_vaddr;
374
375 /*
376 * Fill in the contents of the pages requested by VM.
377 */
378 upl_pl = UPL_GET_INTERNAL_PAGE_LIST(upl);
379 pl_count = length / PAGE_SIZE;
380 for (cur_offset = 0; cur_offset < length; cur_offset += PAGE_SIZE) {
381 ppnum_t dst_pnum;
382
383 if (!upl_page_present(upl_pl, (int)(cur_offset / PAGE_SIZE))) {
384 /* this page is not in the UPL: skip it */
385 continue;
386 }
387
388 /*
389 * Establish an explicit pmap mapping of the destination
390 * physical page.
391 * We can't do a regular VM mapping because the VM page
392 * is "busy".
393 */
394 dst_pnum = (ppnum_t)
395 upl_phys_page(upl_pl, (int)(cur_offset / PAGE_SIZE));
396 assert(dst_pnum != 0);
397 retval = pmap_enter(kernel_pmap,
398 kernel_mapping,
399 dst_pnum,
400 VM_PROT_READ | VM_PROT_WRITE,
401 VM_PROT_NONE,
402 0,
403 TRUE);
404
405 assert(retval == KERN_SUCCESS);
406
407 if (retval != KERN_SUCCESS) {
408 goto done;
409 }
410
411 memset(dst_ptr, '\0', PAGE_SIZE);
412 /* add an end-of-line to keep line counters happy */
413 dst_ptr[PAGE_SIZE - 1] = '\n';
414
415 /*
416 * Remove the pmap mapping of the destination page
417 * in the kernel.
418 */
419 pmap_remove(kernel_pmap,
420 (addr64_t) kernel_mapping,
421 (addr64_t) (kernel_mapping + PAGE_SIZE_64));
422 }
423
424 retval = KERN_SUCCESS;
425 done:
426 if (upl != NULL) {
427 /* clean up the UPL */
428
429 /*
430 * The pages are currently dirty because we've just been
431 * writing on them, but as far as we're concerned, they're
432 * clean since they contain their "original" contents as
433 * provided by us, the pager.
434 * Tell the UPL to mark them "clean".
435 */
436 upl_clear_dirty(upl, TRUE);
437
438 /* abort or commit the UPL */
439 if (retval != KERN_SUCCESS) {
440 upl_abort(upl, 0);
441 } else {
442 boolean_t empty;
443 assertf(page_aligned(upl->u_offset) && page_aligned(upl->u_size),
444 "upl %p offset 0x%llx size 0x%x",
445 upl, upl->u_offset, upl->u_size);
446 upl_commit_range(upl, 0, upl->u_size,
447 UPL_COMMIT_CS_VALIDATED,
448 upl_pl, pl_count, &empty);
449 }
450
451 /* and deallocate the UPL */
452 upl_deallocate(upl);
453 upl = NULL;
454 }
455 if (kernel_mapping != 0) {
456 /* clean up the mapping of the source and destination pages */
457 kr = vm_map_remove(kernel_map,
458 kernel_mapping,
459 kernel_mapping + PAGE_SIZE_64,
460 VM_MAP_REMOVE_NO_FLAGS);
461 assert(kr == KERN_SUCCESS);
462 kernel_mapping = 0;
463 dst_vaddr = 0;
464 }
465
466 return retval;
467 }
468
469 /*
470 * swapfile_pager_reference()
471 *
472 * Get a reference on this memory object.
473 * For external usage only. Assumes that the initial reference count is not 0,
474 * i.e one should not "revive" a dead pager this way.
475 */
476 void
477 swapfile_pager_reference(
478 memory_object_t mem_obj)
479 {
480 swapfile_pager_t pager;
481
482 pager = swapfile_pager_lookup(mem_obj);
483
484 lck_mtx_lock(&swapfile_pager_lock);
485 assert(pager->ref_count > 0);
486 pager->ref_count++;
487 lck_mtx_unlock(&swapfile_pager_lock);
488 }
489
490
491 /*
492 * swapfile_pager_dequeue:
493 *
494 * Removes a pager from the list of pagers.
495 *
496 * The caller must hold "swapfile_pager_lock".
497 */
498 void
499 swapfile_pager_dequeue(
500 swapfile_pager_t pager)
501 {
502 assert(!pager->is_mapped);
503
504 queue_remove(&swapfile_pager_queue,
505 pager,
506 swapfile_pager_t,
507 pager_queue);
508 pager->pager_queue.next = NULL;
509 pager->pager_queue.prev = NULL;
510
511 swapfile_pager_count--;
512 }
513
514 /*
515 * swapfile_pager_terminate_internal:
516 *
517 * Trigger the asynchronous termination of the memory object associated
518 * with this pager.
519 * When the memory object is terminated, there will be one more call
520 * to memory_object_deallocate() (i.e. swapfile_pager_deallocate())
521 * to finish the clean up.
522 *
523 * "swapfile_pager_lock" should not be held by the caller.
524 * We don't need the lock because the pager has already been removed from
525 * the pagers' list and is now ours exclusively.
526 */
527 void
528 swapfile_pager_terminate_internal(
529 swapfile_pager_t pager)
530 {
531 assert(pager->is_ready);
532 assert(!pager->is_mapped);
533
534 if (pager->swapfile_vnode != NULL) {
535 pager->swapfile_vnode = NULL;
536 }
537
538 /* trigger the destruction of the memory object */
539 memory_object_destroy(pager->swp_pgr_hdr.mo_control, 0);
540 }
541
542 /*
543 * swapfile_pager_deallocate_internal()
544 *
545 * Release a reference on this pager and free it when the last
546 * reference goes away.
547 * Can be called with swapfile_pager_lock held or not but always returns
548 * with it unlocked.
549 */
550 void
551 swapfile_pager_deallocate_internal(
552 swapfile_pager_t pager,
553 boolean_t locked)
554 {
555 if (!locked) {
556 lck_mtx_lock(&swapfile_pager_lock);
557 }
558
559 /* drop a reference on this pager */
560 pager->ref_count--;
561
562 if (pager->ref_count == 1) {
563 /*
564 * Only the "named" reference is left, which means that
565 * no one is really holding on to this pager anymore.
566 * Terminate it.
567 */
568 swapfile_pager_dequeue(pager);
569 /* the pager is all ours: no need for the lock now */
570 lck_mtx_unlock(&swapfile_pager_lock);
571 swapfile_pager_terminate_internal(pager);
572 } else if (pager->ref_count == 0) {
573 /*
574 * Dropped the existence reference; the memory object has
575 * been terminated. Do some final cleanup and release the
576 * pager structure.
577 */
578 lck_mtx_unlock(&swapfile_pager_lock);
579 if (pager->swp_pgr_hdr.mo_control != MEMORY_OBJECT_CONTROL_NULL) {
580 memory_object_control_deallocate(pager->swp_pgr_hdr.mo_control);
581 pager->swp_pgr_hdr.mo_control = MEMORY_OBJECT_CONTROL_NULL;
582 }
583 kfree(pager, sizeof(*pager));
584 pager = SWAPFILE_PAGER_NULL;
585 } else {
586 /* there are still plenty of references: keep going... */
587 lck_mtx_unlock(&swapfile_pager_lock);
588 }
589
590 /* caution: lock is not held on return... */
591 }
592
593 /*
594 * swapfile_pager_deallocate()
595 *
596 * Release a reference on this pager and free it when the last
597 * reference goes away.
598 */
599 void
600 swapfile_pager_deallocate(
601 memory_object_t mem_obj)
602 {
603 swapfile_pager_t pager;
604
605 PAGER_DEBUG(PAGER_ALL, ("swapfile_pager_deallocate: %p\n", mem_obj));
606 pager = swapfile_pager_lookup(mem_obj);
607 swapfile_pager_deallocate_internal(pager, FALSE);
608 }
609
610 /*
611 *
612 */
613 kern_return_t
614 swapfile_pager_terminate(
615 #if !DEBUG
616 __unused
617 #endif
618 memory_object_t mem_obj)
619 {
620 PAGER_DEBUG(PAGER_ALL, ("swapfile_pager_terminate: %p\n", mem_obj));
621
622 return KERN_SUCCESS;
623 }
624
625 /*
626 *
627 */
628 kern_return_t
629 swapfile_pager_synchronize(
630 __unused memory_object_t mem_obbj,
631 __unused memory_object_offset_t offset,
632 __unused memory_object_size_t length,
633 __unused vm_sync_t sync_flags)
634 {
635 panic("swapfile_pager_synchronize: memory_object_synchronize no longer supported\n");
636 return KERN_FAILURE;
637 }
638
639 /*
640 * swapfile_pager_map()
641 *
642 * This allows VM to let us, the EMM, know that this memory object
643 * is currently mapped one or more times. This is called by VM each time
644 * the memory object gets mapped and we take one extra reference on the
645 * memory object to account for all its mappings.
646 */
647 kern_return_t
648 swapfile_pager_map(
649 memory_object_t mem_obj,
650 __unused vm_prot_t prot)
651 {
652 swapfile_pager_t pager;
653
654 PAGER_DEBUG(PAGER_ALL, ("swapfile_pager_map: %p\n", mem_obj));
655
656 pager = swapfile_pager_lookup(mem_obj);
657
658 lck_mtx_lock(&swapfile_pager_lock);
659 assert(pager->is_ready);
660 assert(pager->ref_count > 0); /* pager is alive */
661 if (pager->is_mapped == FALSE) {
662 /*
663 * First mapping of this pager: take an extra reference
664 * that will remain until all the mappings of this pager
665 * are removed.
666 */
667 pager->is_mapped = TRUE;
668 pager->ref_count++;
669 }
670 lck_mtx_unlock(&swapfile_pager_lock);
671
672 return KERN_SUCCESS;
673 }
674
675 /*
676 * swapfile_pager_last_unmap()
677 *
678 * This is called by VM when this memory object is no longer mapped anywhere.
679 */
680 kern_return_t
681 swapfile_pager_last_unmap(
682 memory_object_t mem_obj)
683 {
684 swapfile_pager_t pager;
685
686 PAGER_DEBUG(PAGER_ALL,
687 ("swapfile_pager_last_unmap: %p\n", mem_obj));
688
689 pager = swapfile_pager_lookup(mem_obj);
690
691 lck_mtx_lock(&swapfile_pager_lock);
692 if (pager->is_mapped) {
693 /*
694 * All the mappings are gone, so let go of the one extra
695 * reference that represents all the mappings of this pager.
696 */
697 pager->is_mapped = FALSE;
698 swapfile_pager_deallocate_internal(pager, TRUE);
699 /* caution: deallocate_internal() released the lock ! */
700 } else {
701 lck_mtx_unlock(&swapfile_pager_lock);
702 }
703
704 return KERN_SUCCESS;
705 }
706
707
708 /*
709 *
710 */
711 swapfile_pager_t
712 swapfile_pager_lookup(
713 memory_object_t mem_obj)
714 {
715 swapfile_pager_t pager;
716
717 assert(mem_obj->mo_pager_ops == &swapfile_pager_ops);
718 __IGNORE_WCASTALIGN(pager = (swapfile_pager_t) mem_obj);
719 assert(pager->ref_count > 0);
720 return pager;
721 }
722
723 swapfile_pager_t
724 swapfile_pager_create(
725 struct vnode *vp)
726 {
727 swapfile_pager_t pager, pager2;
728 memory_object_control_t control;
729 kern_return_t kr;
730
731 pager = (swapfile_pager_t) kalloc(sizeof(*pager));
732 if (pager == SWAPFILE_PAGER_NULL) {
733 return SWAPFILE_PAGER_NULL;
734 }
735
736 /*
737 * The vm_map call takes both named entry ports and raw memory
738 * objects in the same parameter. We need to make sure that
739 * vm_map does not see this object as a named entry port. So,
740 * we reserve the second word in the object for a fake ip_kotype
741 * setting - that will tell vm_map to use it as a memory object.
742 */
743 pager->swp_pgr_hdr.mo_ikot = IKOT_MEMORY_OBJECT;
744 pager->swp_pgr_hdr.mo_pager_ops = &swapfile_pager_ops;
745 pager->swp_pgr_hdr.mo_control = MEMORY_OBJECT_CONTROL_NULL;
746
747 pager->is_ready = FALSE;/* not ready until it has a "name" */
748 pager->ref_count = 1; /* setup reference */
749 pager->is_mapped = FALSE;
750 pager->swapfile_vnode = vp;
751
752 lck_mtx_lock(&swapfile_pager_lock);
753 /* see if anyone raced us to create a pager for the same object */
754 queue_iterate(&swapfile_pager_queue,
755 pager2,
756 swapfile_pager_t,
757 pager_queue) {
758 if (pager2->swapfile_vnode == vp) {
759 break;
760 }
761 }
762 if (!queue_end(&swapfile_pager_queue,
763 (queue_entry_t) pager2)) {
764 /* while we hold the lock, transfer our setup ref to winner */
765 pager2->ref_count++;
766 /* we lost the race, down with the loser... */
767 lck_mtx_unlock(&swapfile_pager_lock);
768 pager->swapfile_vnode = NULL;
769 kfree(pager, sizeof(*pager));
770 /* ... and go with the winner */
771 pager = pager2;
772 /* let the winner make sure the pager gets ready */
773 return pager;
774 }
775
776 /* enter new pager at the head of our list of pagers */
777 queue_enter_first(&swapfile_pager_queue,
778 pager,
779 swapfile_pager_t,
780 pager_queue);
781 swapfile_pager_count++;
782 if (swapfile_pager_count > swapfile_pager_count_max) {
783 swapfile_pager_count_max = swapfile_pager_count;
784 }
785 lck_mtx_unlock(&swapfile_pager_lock);
786
787 kr = memory_object_create_named((memory_object_t) pager,
788 0,
789 &control);
790 assert(kr == KERN_SUCCESS);
791
792 memory_object_mark_trusted(control);
793
794 lck_mtx_lock(&swapfile_pager_lock);
795 /* the new pager is now ready to be used */
796 pager->is_ready = TRUE;
797 lck_mtx_unlock(&swapfile_pager_lock);
798
799 /* wakeup anyone waiting for this pager to be ready */
800 thread_wakeup(&pager->is_ready);
801
802 return pager;
803 }
804
805 /*
806 * swapfile_pager_setup()
807 *
808 * Provide the caller with a memory object backed by the provided
809 * "backing_object" VM object. If such a memory object already exists,
810 * re-use it, otherwise create a new memory object.
811 */
812 memory_object_t
813 swapfile_pager_setup(
814 struct vnode *vp)
815 {
816 swapfile_pager_t pager;
817
818 lck_mtx_lock(&swapfile_pager_lock);
819
820 queue_iterate(&swapfile_pager_queue,
821 pager,
822 swapfile_pager_t,
823 pager_queue) {
824 if (pager->swapfile_vnode == vp) {
825 break;
826 }
827 }
828 if (queue_end(&swapfile_pager_queue,
829 (queue_entry_t) pager)) {
830 /* no existing pager for this backing object */
831 pager = SWAPFILE_PAGER_NULL;
832 } else {
833 /* make sure pager doesn't disappear */
834 pager->ref_count++;
835 }
836
837 lck_mtx_unlock(&swapfile_pager_lock);
838
839 if (pager == SWAPFILE_PAGER_NULL) {
840 pager = swapfile_pager_create(vp);
841 if (pager == SWAPFILE_PAGER_NULL) {
842 return MEMORY_OBJECT_NULL;
843 }
844 }
845
846 lck_mtx_lock(&swapfile_pager_lock);
847 while (!pager->is_ready) {
848 lck_mtx_sleep(&swapfile_pager_lock,
849 LCK_SLEEP_DEFAULT,
850 &pager->is_ready,
851 THREAD_UNINT);
852 }
853 lck_mtx_unlock(&swapfile_pager_lock);
854
855 return (memory_object_t) pager;
856 }
857
858 memory_object_control_t
859 swapfile_pager_control(
860 memory_object_t mem_obj)
861 {
862 swapfile_pager_t pager;
863
864 if (mem_obj == MEMORY_OBJECT_NULL ||
865 mem_obj->mo_pager_ops != &swapfile_pager_ops) {
866 return MEMORY_OBJECT_CONTROL_NULL;
867 }
868 pager = swapfile_pager_lookup(mem_obj);
869 return pager->swp_pgr_hdr.mo_control;
870 }