]> git.saurik.com Git - apple/xnu.git/blob - osfmk/vm/vm_swapfile_pager.c
xnu-7195.60.75.tar.gz
[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_pager_name = "swapfile pager"
131 };
132
133 /*
134 * The "swapfile_pager" describes a memory object backed by
135 * the "swapfile" EMM.
136 */
137 typedef struct swapfile_pager {
138 /* mandatory generic header */
139 struct memory_object swp_pgr_hdr;
140
141 /* pager-specific data */
142 queue_chain_t pager_queue; /* next & prev pagers */
143 unsigned int ref_count; /* reference count */
144 boolean_t is_ready; /* is this pager ready ? */
145 boolean_t is_mapped; /* is this pager mapped ? */
146 struct vnode *swapfile_vnode;/* the swapfile's vnode */
147 } *swapfile_pager_t;
148 #define SWAPFILE_PAGER_NULL ((swapfile_pager_t) NULL)
149
150 /*
151 * List of memory objects managed by this EMM.
152 * The list is protected by the "swapfile_pager_lock" lock.
153 */
154 int swapfile_pager_count = 0; /* number of pagers */
155 queue_head_t swapfile_pager_queue = QUEUE_HEAD_INITIALIZER(swapfile_pager_queue);
156 LCK_GRP_DECLARE(swapfile_pager_lck_grp, "swapfile pager");
157 LCK_MTX_DECLARE(swapfile_pager_lock, &swapfile_pager_lck_grp);
158
159 /*
160 * Statistics & counters.
161 */
162 int swapfile_pager_count_max = 0;
163
164 /* internal prototypes */
165 swapfile_pager_t swapfile_pager_create(struct vnode *vp);
166 swapfile_pager_t swapfile_pager_lookup(memory_object_t mem_obj);
167 void swapfile_pager_dequeue(swapfile_pager_t pager);
168 void swapfile_pager_deallocate_internal(swapfile_pager_t pager,
169 boolean_t locked);
170 void swapfile_pager_terminate_internal(swapfile_pager_t pager);
171
172
173 #if DEBUG
174 int swapfile_pagerdebug = 0;
175 #define PAGER_ALL 0xffffffff
176 #define PAGER_INIT 0x00000001
177 #define PAGER_PAGEIN 0x00000002
178
179 #define PAGER_DEBUG(LEVEL, A) \
180 MACRO_BEGIN \
181 if ((swapfile_pagerdebug & LEVEL)==LEVEL) { \
182 printf A; \
183 } \
184 MACRO_END
185 #else
186 #define PAGER_DEBUG(LEVEL, A)
187 #endif
188
189
190 /*
191 * swapfile_pager_init()
192 *
193 * Initialize the memory object and makes it ready to be used and mapped.
194 */
195 kern_return_t
196 swapfile_pager_init(
197 memory_object_t mem_obj,
198 memory_object_control_t control,
199 #if !DEBUG
200 __unused
201 #endif
202 memory_object_cluster_size_t pg_size)
203 {
204 swapfile_pager_t pager;
205 kern_return_t kr;
206 memory_object_attr_info_data_t attributes;
207
208 PAGER_DEBUG(PAGER_ALL,
209 ("swapfile_pager_init: %p, %p, %x\n",
210 mem_obj, control, pg_size));
211
212 if (control == MEMORY_OBJECT_CONTROL_NULL) {
213 return KERN_INVALID_ARGUMENT;
214 }
215
216 pager = swapfile_pager_lookup(mem_obj);
217
218 memory_object_control_reference(control);
219
220 pager->swp_pgr_hdr.mo_control = control;
221
222 attributes.copy_strategy = MEMORY_OBJECT_COPY_DELAY;
223 attributes.cluster_size = (1 << (PAGE_SHIFT));
224 attributes.may_cache_object = FALSE;
225 attributes.temporary = TRUE;
226
227 kr = memory_object_change_attributes(
228 control,
229 MEMORY_OBJECT_ATTRIBUTE_INFO,
230 (memory_object_info_t) &attributes,
231 MEMORY_OBJECT_ATTR_INFO_COUNT);
232 if (kr != KERN_SUCCESS) {
233 panic("swapfile_pager_init: "
234 "memory_object_change_attributes() failed");
235 }
236
237 return KERN_SUCCESS;
238 }
239
240 /*
241 * swapfile_data_return()
242 *
243 * Handles page-out requests from VM. This should never happen since
244 * the pages provided by this EMM are not supposed to be dirty or dirtied
245 * and VM should simply discard the contents and reclaim the pages if it
246 * needs to.
247 */
248 kern_return_t
249 swapfile_pager_data_return(
250 __unused memory_object_t mem_obj,
251 __unused memory_object_offset_t offset,
252 __unused memory_object_cluster_size_t data_cnt,
253 __unused memory_object_offset_t *resid_offset,
254 __unused int *io_error,
255 __unused boolean_t dirty,
256 __unused boolean_t kernel_copy,
257 __unused int upl_flags)
258 {
259 panic("swapfile_pager_data_return: should never get called");
260 return KERN_FAILURE;
261 }
262
263 kern_return_t
264 swapfile_pager_data_initialize(
265 __unused memory_object_t mem_obj,
266 __unused memory_object_offset_t offset,
267 __unused memory_object_cluster_size_t data_cnt)
268 {
269 panic("swapfile_pager_data_initialize: should never get called");
270 return KERN_FAILURE;
271 }
272
273 kern_return_t
274 swapfile_pager_data_unlock(
275 __unused memory_object_t mem_obj,
276 __unused memory_object_offset_t offset,
277 __unused memory_object_size_t size,
278 __unused vm_prot_t desired_access)
279 {
280 return KERN_FAILURE;
281 }
282
283 /*
284 * swapfile_pager_data_request()
285 *
286 * Handles page-in requests from VM.
287 */
288 kern_return_t
289 swapfile_pager_data_request(
290 memory_object_t mem_obj,
291 memory_object_offset_t offset,
292 memory_object_cluster_size_t length,
293 #if !DEBUG
294 __unused
295 #endif
296 vm_prot_t protection_required,
297 __unused memory_object_fault_info_t mo_fault_info)
298 {
299 swapfile_pager_t pager;
300 memory_object_control_t mo_control;
301 upl_t upl;
302 int upl_flags;
303 upl_size_t upl_size;
304 upl_page_info_t *upl_pl = NULL;
305 unsigned int pl_count;
306 vm_object_t dst_object;
307 kern_return_t kr, retval;
308 vm_map_offset_t kernel_mapping;
309 vm_offset_t dst_vaddr;
310 char *dst_ptr;
311 vm_offset_t cur_offset;
312 vm_map_entry_t map_entry;
313
314 PAGER_DEBUG(PAGER_ALL, ("swapfile_pager_data_request: %p, %llx, %x, %x\n", mem_obj, offset, length, protection_required));
315
316 kernel_mapping = 0;
317 upl = NULL;
318 upl_pl = NULL;
319
320 pager = swapfile_pager_lookup(mem_obj);
321 assert(pager->is_ready);
322 assert(pager->ref_count > 1); /* pager is alive and mapped */
323
324 PAGER_DEBUG(PAGER_PAGEIN, ("swapfile_pager_data_request: %p, %llx, %x, %x, pager %p\n", mem_obj, offset, length, protection_required, pager));
325
326 /*
327 * Gather in a UPL all the VM pages requested by VM.
328 */
329 mo_control = pager->swp_pgr_hdr.mo_control;
330
331 upl_size = length;
332 upl_flags =
333 UPL_RET_ONLY_ABSENT |
334 UPL_SET_LITE |
335 UPL_NO_SYNC |
336 UPL_CLEAN_IN_PLACE | /* triggers UPL_CLEAR_DIRTY */
337 UPL_SET_INTERNAL;
338 pl_count = 0;
339 kr = memory_object_upl_request(mo_control,
340 offset, upl_size,
341 &upl, NULL, NULL, upl_flags, VM_KERN_MEMORY_OSFMK);
342 if (kr != KERN_SUCCESS) {
343 retval = kr;
344 goto done;
345 }
346 dst_object = mo_control->moc_object;
347 assert(dst_object != VM_OBJECT_NULL);
348
349
350 /*
351 * Reserve a virtual page in the kernel address space to map each
352 * destination physical page when it's its turn to be processed.
353 */
354 vm_object_reference(kernel_object); /* ref. for mapping */
355 kr = vm_map_find_space(kernel_map,
356 &kernel_mapping,
357 PAGE_SIZE_64,
358 0,
359 0,
360 VM_MAP_KERNEL_FLAGS_NONE,
361 VM_KERN_MEMORY_NONE,
362 &map_entry);
363 if (kr != KERN_SUCCESS) {
364 vm_object_deallocate(kernel_object);
365 retval = kr;
366 goto done;
367 }
368 VME_OBJECT_SET(map_entry, kernel_object);
369 VME_OFFSET_SET(map_entry, kernel_mapping - VM_MIN_KERNEL_ADDRESS);
370 vm_map_unlock(kernel_map);
371 dst_vaddr = CAST_DOWN(vm_offset_t, kernel_mapping);
372 dst_ptr = (char *) dst_vaddr;
373
374 /*
375 * Fill in the contents of the pages requested by VM.
376 */
377 upl_pl = UPL_GET_INTERNAL_PAGE_LIST(upl);
378 pl_count = length / PAGE_SIZE;
379 for (cur_offset = 0; cur_offset < length; cur_offset += PAGE_SIZE) {
380 ppnum_t dst_pnum;
381
382 if (!upl_page_present(upl_pl, (int)(cur_offset / PAGE_SIZE))) {
383 /* this page is not in the UPL: skip it */
384 continue;
385 }
386
387 /*
388 * Establish an explicit pmap mapping of the destination
389 * physical page.
390 * We can't do a regular VM mapping because the VM page
391 * is "busy".
392 */
393 dst_pnum = (ppnum_t)
394 upl_phys_page(upl_pl, (int)(cur_offset / PAGE_SIZE));
395 assert(dst_pnum != 0);
396 retval = pmap_enter(kernel_pmap,
397 kernel_mapping,
398 dst_pnum,
399 VM_PROT_READ | VM_PROT_WRITE,
400 VM_PROT_NONE,
401 0,
402 TRUE);
403
404 assert(retval == KERN_SUCCESS);
405
406 if (retval != KERN_SUCCESS) {
407 goto done;
408 }
409
410 memset(dst_ptr, '\0', PAGE_SIZE);
411 /* add an end-of-line to keep line counters happy */
412 dst_ptr[PAGE_SIZE - 1] = '\n';
413
414 /*
415 * Remove the pmap mapping of the destination page
416 * in the kernel.
417 */
418 pmap_remove(kernel_pmap,
419 (addr64_t) kernel_mapping,
420 (addr64_t) (kernel_mapping + PAGE_SIZE_64));
421 }
422
423 retval = KERN_SUCCESS;
424 done:
425 if (upl != NULL) {
426 /* clean up the UPL */
427
428 /*
429 * The pages are currently dirty because we've just been
430 * writing on them, but as far as we're concerned, they're
431 * clean since they contain their "original" contents as
432 * provided by us, the pager.
433 * Tell the UPL to mark them "clean".
434 */
435 upl_clear_dirty(upl, TRUE);
436
437 /* abort or commit the UPL */
438 if (retval != KERN_SUCCESS) {
439 upl_abort(upl, 0);
440 } else {
441 boolean_t empty;
442 assertf(page_aligned(upl->u_offset) && page_aligned(upl->u_size),
443 "upl %p offset 0x%llx size 0x%x",
444 upl, upl->u_offset, upl->u_size);
445 upl_commit_range(upl, 0, upl->u_size,
446 UPL_COMMIT_CS_VALIDATED,
447 upl_pl, pl_count, &empty);
448 }
449
450 /* and deallocate the UPL */
451 upl_deallocate(upl);
452 upl = NULL;
453 }
454 if (kernel_mapping != 0) {
455 /* clean up the mapping of the source and destination pages */
456 kr = vm_map_remove(kernel_map,
457 kernel_mapping,
458 kernel_mapping + PAGE_SIZE_64,
459 VM_MAP_REMOVE_NO_FLAGS);
460 assert(kr == KERN_SUCCESS);
461 kernel_mapping = 0;
462 dst_vaddr = 0;
463 }
464
465 return retval;
466 }
467
468 /*
469 * swapfile_pager_reference()
470 *
471 * Get a reference on this memory object.
472 * For external usage only. Assumes that the initial reference count is not 0,
473 * i.e one should not "revive" a dead pager this way.
474 */
475 void
476 swapfile_pager_reference(
477 memory_object_t mem_obj)
478 {
479 swapfile_pager_t pager;
480
481 pager = swapfile_pager_lookup(mem_obj);
482
483 lck_mtx_lock(&swapfile_pager_lock);
484 assert(pager->ref_count > 0);
485 pager->ref_count++;
486 lck_mtx_unlock(&swapfile_pager_lock);
487 }
488
489
490 /*
491 * swapfile_pager_dequeue:
492 *
493 * Removes a pager from the list of pagers.
494 *
495 * The caller must hold "swapfile_pager_lock".
496 */
497 void
498 swapfile_pager_dequeue(
499 swapfile_pager_t pager)
500 {
501 assert(!pager->is_mapped);
502
503 queue_remove(&swapfile_pager_queue,
504 pager,
505 swapfile_pager_t,
506 pager_queue);
507 pager->pager_queue.next = NULL;
508 pager->pager_queue.prev = NULL;
509
510 swapfile_pager_count--;
511 }
512
513 /*
514 * swapfile_pager_terminate_internal:
515 *
516 * Trigger the asynchronous termination of the memory object associated
517 * with this pager.
518 * When the memory object is terminated, there will be one more call
519 * to memory_object_deallocate() (i.e. swapfile_pager_deallocate())
520 * to finish the clean up.
521 *
522 * "swapfile_pager_lock" should not be held by the caller.
523 * We don't need the lock because the pager has already been removed from
524 * the pagers' list and is now ours exclusively.
525 */
526 void
527 swapfile_pager_terminate_internal(
528 swapfile_pager_t pager)
529 {
530 assert(pager->is_ready);
531 assert(!pager->is_mapped);
532
533 if (pager->swapfile_vnode != NULL) {
534 pager->swapfile_vnode = NULL;
535 }
536
537 /* trigger the destruction of the memory object */
538 memory_object_destroy(pager->swp_pgr_hdr.mo_control, 0);
539 }
540
541 /*
542 * swapfile_pager_deallocate_internal()
543 *
544 * Release a reference on this pager and free it when the last
545 * reference goes away.
546 * Can be called with swapfile_pager_lock held or not but always returns
547 * with it unlocked.
548 */
549 void
550 swapfile_pager_deallocate_internal(
551 swapfile_pager_t pager,
552 boolean_t locked)
553 {
554 if (!locked) {
555 lck_mtx_lock(&swapfile_pager_lock);
556 }
557
558 /* drop a reference on this pager */
559 pager->ref_count--;
560
561 if (pager->ref_count == 1) {
562 /*
563 * Only the "named" reference is left, which means that
564 * no one is really holding on to this pager anymore.
565 * Terminate it.
566 */
567 swapfile_pager_dequeue(pager);
568 /* the pager is all ours: no need for the lock now */
569 lck_mtx_unlock(&swapfile_pager_lock);
570 swapfile_pager_terminate_internal(pager);
571 } else if (pager->ref_count == 0) {
572 /*
573 * Dropped the existence reference; the memory object has
574 * been terminated. Do some final cleanup and release the
575 * pager structure.
576 */
577 lck_mtx_unlock(&swapfile_pager_lock);
578 if (pager->swp_pgr_hdr.mo_control != MEMORY_OBJECT_CONTROL_NULL) {
579 memory_object_control_deallocate(pager->swp_pgr_hdr.mo_control);
580 pager->swp_pgr_hdr.mo_control = MEMORY_OBJECT_CONTROL_NULL;
581 }
582 kfree(pager, sizeof(*pager));
583 pager = SWAPFILE_PAGER_NULL;
584 } else {
585 /* there are still plenty of references: keep going... */
586 lck_mtx_unlock(&swapfile_pager_lock);
587 }
588
589 /* caution: lock is not held on return... */
590 }
591
592 /*
593 * swapfile_pager_deallocate()
594 *
595 * Release a reference on this pager and free it when the last
596 * reference goes away.
597 */
598 void
599 swapfile_pager_deallocate(
600 memory_object_t mem_obj)
601 {
602 swapfile_pager_t pager;
603
604 PAGER_DEBUG(PAGER_ALL, ("swapfile_pager_deallocate: %p\n", mem_obj));
605 pager = swapfile_pager_lookup(mem_obj);
606 swapfile_pager_deallocate_internal(pager, FALSE);
607 }
608
609 /*
610 *
611 */
612 kern_return_t
613 swapfile_pager_terminate(
614 #if !DEBUG
615 __unused
616 #endif
617 memory_object_t mem_obj)
618 {
619 PAGER_DEBUG(PAGER_ALL, ("swapfile_pager_terminate: %p\n", mem_obj));
620
621 return KERN_SUCCESS;
622 }
623
624 /*
625 *
626 */
627 kern_return_t
628 swapfile_pager_synchronize(
629 __unused memory_object_t mem_obbj,
630 __unused memory_object_offset_t offset,
631 __unused memory_object_size_t length,
632 __unused vm_sync_t sync_flags)
633 {
634 panic("swapfile_pager_synchronize: memory_object_synchronize no longer supported\n");
635 return KERN_FAILURE;
636 }
637
638 /*
639 * swapfile_pager_map()
640 *
641 * This allows VM to let us, the EMM, know that this memory object
642 * is currently mapped one or more times. This is called by VM each time
643 * the memory object gets mapped and we take one extra reference on the
644 * memory object to account for all its mappings.
645 */
646 kern_return_t
647 swapfile_pager_map(
648 memory_object_t mem_obj,
649 __unused vm_prot_t prot)
650 {
651 swapfile_pager_t pager;
652
653 PAGER_DEBUG(PAGER_ALL, ("swapfile_pager_map: %p\n", mem_obj));
654
655 pager = swapfile_pager_lookup(mem_obj);
656
657 lck_mtx_lock(&swapfile_pager_lock);
658 assert(pager->is_ready);
659 assert(pager->ref_count > 0); /* pager is alive */
660 if (pager->is_mapped == FALSE) {
661 /*
662 * First mapping of this pager: take an extra reference
663 * that will remain until all the mappings of this pager
664 * are removed.
665 */
666 pager->is_mapped = TRUE;
667 pager->ref_count++;
668 }
669 lck_mtx_unlock(&swapfile_pager_lock);
670
671 return KERN_SUCCESS;
672 }
673
674 /*
675 * swapfile_pager_last_unmap()
676 *
677 * This is called by VM when this memory object is no longer mapped anywhere.
678 */
679 kern_return_t
680 swapfile_pager_last_unmap(
681 memory_object_t mem_obj)
682 {
683 swapfile_pager_t pager;
684
685 PAGER_DEBUG(PAGER_ALL,
686 ("swapfile_pager_last_unmap: %p\n", mem_obj));
687
688 pager = swapfile_pager_lookup(mem_obj);
689
690 lck_mtx_lock(&swapfile_pager_lock);
691 if (pager->is_mapped) {
692 /*
693 * All the mappings are gone, so let go of the one extra
694 * reference that represents all the mappings of this pager.
695 */
696 pager->is_mapped = FALSE;
697 swapfile_pager_deallocate_internal(pager, TRUE);
698 /* caution: deallocate_internal() released the lock ! */
699 } else {
700 lck_mtx_unlock(&swapfile_pager_lock);
701 }
702
703 return KERN_SUCCESS;
704 }
705
706
707 /*
708 *
709 */
710 swapfile_pager_t
711 swapfile_pager_lookup(
712 memory_object_t mem_obj)
713 {
714 swapfile_pager_t pager;
715
716 assert(mem_obj->mo_pager_ops == &swapfile_pager_ops);
717 __IGNORE_WCASTALIGN(pager = (swapfile_pager_t) mem_obj);
718 assert(pager->ref_count > 0);
719 return pager;
720 }
721
722 swapfile_pager_t
723 swapfile_pager_create(
724 struct vnode *vp)
725 {
726 swapfile_pager_t pager, pager2;
727 memory_object_control_t control;
728 kern_return_t kr;
729
730 pager = (swapfile_pager_t) kalloc(sizeof(*pager));
731 if (pager == SWAPFILE_PAGER_NULL) {
732 return SWAPFILE_PAGER_NULL;
733 }
734
735 /*
736 * The vm_map call takes both named entry ports and raw memory
737 * objects in the same parameter. We need to make sure that
738 * vm_map does not see this object as a named entry port. So,
739 * we reserve the second word in the object for a fake ip_kotype
740 * setting - that will tell vm_map to use it as a memory object.
741 */
742 pager->swp_pgr_hdr.mo_ikot = IKOT_MEMORY_OBJECT;
743 pager->swp_pgr_hdr.mo_pager_ops = &swapfile_pager_ops;
744 pager->swp_pgr_hdr.mo_control = MEMORY_OBJECT_CONTROL_NULL;
745
746 pager->is_ready = FALSE;/* not ready until it has a "name" */
747 pager->ref_count = 1; /* setup reference */
748 pager->is_mapped = FALSE;
749 pager->swapfile_vnode = vp;
750
751 lck_mtx_lock(&swapfile_pager_lock);
752 /* see if anyone raced us to create a pager for the same object */
753 queue_iterate(&swapfile_pager_queue,
754 pager2,
755 swapfile_pager_t,
756 pager_queue) {
757 if (pager2->swapfile_vnode == vp) {
758 break;
759 }
760 }
761 if (!queue_end(&swapfile_pager_queue,
762 (queue_entry_t) pager2)) {
763 /* while we hold the lock, transfer our setup ref to winner */
764 pager2->ref_count++;
765 /* we lost the race, down with the loser... */
766 lck_mtx_unlock(&swapfile_pager_lock);
767 pager->swapfile_vnode = NULL;
768 kfree(pager, sizeof(*pager));
769 /* ... and go with the winner */
770 pager = pager2;
771 /* let the winner make sure the pager gets ready */
772 return pager;
773 }
774
775 /* enter new pager at the head of our list of pagers */
776 queue_enter_first(&swapfile_pager_queue,
777 pager,
778 swapfile_pager_t,
779 pager_queue);
780 swapfile_pager_count++;
781 if (swapfile_pager_count > swapfile_pager_count_max) {
782 swapfile_pager_count_max = swapfile_pager_count;
783 }
784 lck_mtx_unlock(&swapfile_pager_lock);
785
786 kr = memory_object_create_named((memory_object_t) pager,
787 0,
788 &control);
789 assert(kr == KERN_SUCCESS);
790
791 memory_object_mark_trusted(control);
792
793 lck_mtx_lock(&swapfile_pager_lock);
794 /* the new pager is now ready to be used */
795 pager->is_ready = TRUE;
796 lck_mtx_unlock(&swapfile_pager_lock);
797
798 /* wakeup anyone waiting for this pager to be ready */
799 thread_wakeup(&pager->is_ready);
800
801 return pager;
802 }
803
804 /*
805 * swapfile_pager_setup()
806 *
807 * Provide the caller with a memory object backed by the provided
808 * "backing_object" VM object. If such a memory object already exists,
809 * re-use it, otherwise create a new memory object.
810 */
811 memory_object_t
812 swapfile_pager_setup(
813 struct vnode *vp)
814 {
815 swapfile_pager_t pager;
816
817 lck_mtx_lock(&swapfile_pager_lock);
818
819 queue_iterate(&swapfile_pager_queue,
820 pager,
821 swapfile_pager_t,
822 pager_queue) {
823 if (pager->swapfile_vnode == vp) {
824 break;
825 }
826 }
827 if (queue_end(&swapfile_pager_queue,
828 (queue_entry_t) pager)) {
829 /* no existing pager for this backing object */
830 pager = SWAPFILE_PAGER_NULL;
831 } else {
832 /* make sure pager doesn't disappear */
833 pager->ref_count++;
834 }
835
836 lck_mtx_unlock(&swapfile_pager_lock);
837
838 if (pager == SWAPFILE_PAGER_NULL) {
839 pager = swapfile_pager_create(vp);
840 if (pager == SWAPFILE_PAGER_NULL) {
841 return MEMORY_OBJECT_NULL;
842 }
843 }
844
845 lck_mtx_lock(&swapfile_pager_lock);
846 while (!pager->is_ready) {
847 lck_mtx_sleep(&swapfile_pager_lock,
848 LCK_SLEEP_DEFAULT,
849 &pager->is_ready,
850 THREAD_UNINT);
851 }
852 lck_mtx_unlock(&swapfile_pager_lock);
853
854 return (memory_object_t) pager;
855 }
856
857 memory_object_control_t
858 swapfile_pager_control(
859 memory_object_t mem_obj)
860 {
861 swapfile_pager_t pager;
862
863 if (mem_obj == MEMORY_OBJECT_NULL ||
864 mem_obj->mo_pager_ops != &swapfile_pager_ops) {
865 return MEMORY_OBJECT_CONTROL_NULL;
866 }
867 pager = swapfile_pager_lookup(mem_obj);
868 return pager->swp_pgr_hdr.mo_control;
869 }