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