2 * Copyright (c) 2000-2013 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include "vm_compressor_backing_store.h"
30 #include <vm/vm_protos.h>
32 #include <IOKit/IOHibernatePrivate.h>
35 boolean_t compressor_store_stop_compaction
= FALSE
;
36 boolean_t vm_swap_up
= FALSE
;
37 boolean_t vm_swapfile_mgmt_needed
= FALSE
;
39 int swapper_throttle
= -1;
40 boolean_t swapper_throttle_inited
= FALSE
;
41 uint64_t vm_swapout_thread_id
;
43 uint64_t vm_swap_put_failures
= 0;
44 uint64_t vm_swap_get_failures
= 0;
45 int vm_num_swap_files
= 0;
46 int vm_swapout_thread_processed_segments
= 0;
47 int vm_swapout_thread_awakened
= 0;
48 int vm_swapfile_mgmt_thread_awakened
= 0;
49 int vm_swapfile_mgmt_thread_running
= 0;
51 unsigned int vm_swapfile_total_segs_alloced
= 0;
52 unsigned int vm_swapfile_total_segs_used
= 0;
55 #define SWAP_READY 0x1 /* Swap file is ready to be used */
56 #define SWAP_RECLAIM 0x2 /* Swap file is marked to be reclaimed */
57 #define SWAP_WANTED 0x4 /* Swap file has waiters */
58 #define SWAP_REUSE 0x8 /* Swap file is on the Q and has a name. Reuse after init-ing.*/
61 queue_head_t swp_queue
; /* list of swap files */
62 char *swp_path
; /* saved pathname of swap file */
63 struct vnode
*swp_vp
; /* backing vnode */
64 uint64_t swp_size
; /* size of this swap file */
65 uint8_t *swp_bitmap
; /* bitmap showing the alloced/freed slots in the swap file */
66 unsigned int swp_pathlen
; /* length of pathname */
67 unsigned int swp_nsegs
; /* #segments we can use */
68 unsigned int swp_nseginuse
; /* #segments in use */
69 unsigned int swp_index
; /* index of this swap file */
70 unsigned int swp_flags
; /* state of swap file */
71 unsigned int swp_free_hint
; /* offset of 1st free chunk */
72 unsigned int swp_io_count
; /* count of outstanding I/Os */
73 c_segment_t
*swp_csegs
; /* back pointers to the c_segments. Used during swap reclaim. */
75 struct trim_list
*swp_delayed_trim_list_head
;
76 unsigned int swp_delayed_trim_count
;
77 boolean_t swp_trim_supported
;
80 queue_head_t swf_global_queue
;
82 #define VM_SWAPFILE_DELAYED_TRIM_MAX 128
84 extern clock_sec_t dont_trim_until_ts
;
85 clock_sec_t vm_swapfile_last_failed_to_create_ts
= 0;
87 static void vm_swapout_thread_throttle_adjust(void);
88 static void vm_swap_free_now(struct swapfile
*swf
, uint64_t f_offset
);
89 static void vm_swapout_thread(void);
90 static void vm_swapfile_mgmt_thread(void);
91 static void vm_swap_defragment();
92 static void vm_swap_handle_delayed_trims(boolean_t
);
93 static void vm_swap_do_delayed_trim();
96 #define VM_SWAPFILE_DELAYED_CREATE 30
97 #define VM_SWAP_SHOULD_DEFRAGMENT() (c_swappedout_sparse_count > (vm_swapfile_total_segs_used / 4) ? 1 : 0)
98 #define VM_SWAP_SHOULD_RECLAIM() (((vm_swapfile_total_segs_alloced - vm_swapfile_total_segs_used) >= SWAPFILE_RECLAIM_THRESHOLD_SEGS) ? 1 : 0)
99 #define VM_SWAP_SHOULD_CREATE(cur_ts) (((vm_swapfile_total_segs_alloced - vm_swapfile_total_segs_used) < (unsigned int)VM_SWAPFILE_HIWATER_SEGS) && \
100 ((cur_ts - vm_swapfile_last_failed_to_create_ts) > VM_SWAPFILE_DELAYED_CREATE) ? 1 : 0)
101 #define VM_SWAP_SHOULD_TRIM(swf) ((swf->swp_delayed_trim_count >= VM_SWAPFILE_DELAYED_TRIM_MAX) ? 1 : 0)
104 #define VM_SWAP_BUSY() ((c_swapout_count && (swapper_throttle == THROTTLE_LEVEL_COMPRESSOR_TIER1 || swapper_throttle == THROTTLE_LEVEL_COMPRESSOR_TIER0)) ? 1 : 0)
107 #if CHECKSUM_THE_SWAP
108 extern unsigned int hash_string(char *cp
, int len
);
112 extern boolean_t swap_crypt_ctx_initialized
;
113 extern void swap_crypt_ctx_initialize(void);
114 extern const unsigned char swap_crypt_null_iv
[AES_BLOCK_SIZE
];
115 extern aes_ctx swap_crypt_ctx
;
116 extern unsigned long vm_page_encrypt_counter
;
117 extern unsigned long vm_page_decrypt_counter
;
120 extern void vm_pageout_io_throttle(void);
122 struct swapfile
*vm_swapfile_for_handle(uint64_t);
125 * Called with the vm_swap_data_lock held.
129 vm_swapfile_for_handle(uint64_t f_offset
)
132 uint64_t file_offset
= 0;
133 unsigned int swapfile_index
= 0;
134 struct swapfile
* swf
= NULL
;
136 file_offset
= (f_offset
& SWAP_SLOT_MASK
);
137 swapfile_index
= (f_offset
>> SWAP_DEVICE_SHIFT
);
139 swf
= (struct swapfile
*) queue_first(&swf_global_queue
);
141 while(queue_end(&swf_global_queue
, (queue_entry_t
)swf
) == FALSE
) {
143 if (swapfile_index
== swf
->swp_index
) {
147 swf
= (struct swapfile
*) queue_next(&swf
->swp_queue
);
150 if (queue_end(&swf_global_queue
, (queue_entry_t
) swf
)) {
160 static boolean_t vm_swap_try_init
= FALSE
;
161 thread_t thread
= NULL
;
163 if (vm_swap_try_init
== TRUE
) {
167 vm_swap_try_init
= TRUE
;
169 lck_grp_attr_setdefault(&vm_swap_data_lock_grp_attr
);
170 lck_grp_init(&vm_swap_data_lock_grp
,
172 &vm_swap_data_lock_grp_attr
);
173 lck_attr_setdefault(&vm_swap_data_lock_attr
);
174 lck_mtx_init_ext(&vm_swap_data_lock
,
175 &vm_swap_data_lock_ext
,
176 &vm_swap_data_lock_grp
,
177 &vm_swap_data_lock_attr
);
179 queue_init(&swf_global_queue
);
181 if (vm_swap_create_file()) {
183 if (kernel_thread_start_priority((thread_continue_t
)vm_swapout_thread
, NULL
,
184 BASEPRI_PREEMPT
- 1, &thread
) != KERN_SUCCESS
) {
185 panic("vm_swapout_thread: create failed");
187 thread
->options
|= TH_OPT_VMPRIV
;
188 vm_swapout_thread_id
= thread
->thread_id
;
190 thread_deallocate(thread
);
192 if (kernel_thread_start_priority((thread_continue_t
)vm_swapfile_mgmt_thread
, NULL
,
193 BASEPRI_PREEMPT
- 1, &thread
) != KERN_SUCCESS
) {
194 panic("vm_swapfile_mgmt_thread: create failed");
196 thread
->options
|= TH_OPT_VMPRIV
;
198 thread_deallocate(thread
);
201 if (swap_crypt_ctx_initialized
== FALSE
) {
202 swap_crypt_ctx_initialize();
208 #if SANITY_CHECK_SWAP_ROUTINES
209 extern lck_attr_t
*vm_compressor_lck_attr
;
210 extern lck_grp_t
*vm_compressor_lck_grp
;
213 * Changes COMPRESSED_SWAP_CHUNK_SIZE to make it (4*KB).
214 * Changes MIN_SWAP_FILE_SIZE to (4*KB).
215 * Changes MAX_SWAP_FILE_SIZE to (4*KB).
216 * That will then cause the below allocations to create
217 * 4 new swap files and put/get/free from them.
220 c_segment_t c_seg
= NULL
, c_seg1
= NULL
, c_seg2
= NULL
, c_seg3
= NULL
;
221 vm_offset_t addr
= 0;
222 vm_offset_t dup_addr
= 0;
223 kern_return_t kr
= KERN_SUCCESS
;
224 uint64_t f_offset
= 0;
225 uint64_t f_offset1
= 0;
226 uint64_t f_offset2
= 0;
227 uint64_t f_offset3
= 0;
229 if ((kr
= kernel_memory_allocate(kernel_map
,
231 4 * COMPRESSED_SWAP_CHUNK_SIZE
,
234 printf("kernel_memory_allocate failed with %d\n", kr
);
238 if ((kr
= kernel_memory_allocate(kernel_map
,
240 4 * COMPRESSED_SWAP_CHUNK_SIZE
,
243 printf("kernel_memory_allocate failed with %d\n", kr
);
247 c_seg
= (c_segment_t
) kalloc(sizeof(*c_seg
));
248 memset(c_seg
, 0, sizeof(*c_seg
));
249 #if __i386__ || __x86_64__
250 lck_mtx_init(&c_seg
->c_lock
, vm_compressor_lck_grp
, vm_compressor_lck_attr
);
251 #else /* __i386__ || __x86_64__ */
252 lck_spin_init(&c_seg
->c_lock
, vm_compressor_lck_grp
, vm_compressor_lck_attr
);
253 #endif /* __i386__ || __x86_64__ */
256 c_seg1
= (c_segment_t
) kalloc(sizeof(*c_seg
));
257 memset(c_seg1
, 0, sizeof(*c_seg
));
258 #if __i386__ || __x86_64__
259 lck_mtx_init(&c_seg1
->c_lock
, vm_compressor_lck_grp
, vm_compressor_lck_attr
);
260 #else /* __i386__ || __x86_64__ */
261 lck_spin_init(&c_seg1
->c_lock
, vm_compressor_lck_grp
, vm_compressor_lck_attr
);
262 #endif /* __i386__ || __x86_64__ */
265 c_seg2
= (c_segment_t
) kalloc(sizeof(*c_seg
));
266 memset(c_seg2
, 0, sizeof(*c_seg
));
267 #if __i386__ || __x86_64__
268 lck_mtx_init(&c_seg2
->c_lock
, vm_compressor_lck_grp
, vm_compressor_lck_attr
);
269 #else /* __i386__ || __x86_64__ */
270 lck_spin_init(&c_seg2
->c_lock
, vm_compressor_lck_grp
, vm_compressor_lck_attr
);
271 #endif /* __i386__ || __x86_64__ */
274 c_seg3
= (c_segment_t
) kalloc(sizeof(*c_seg
));
275 memset(c_seg3
, 0, sizeof(*c_seg
));
276 #if __i386__ || __x86_64__
277 lck_mtx_init(&c_seg3
->c_lock
, vm_compressor_lck_grp
, vm_compressor_lck_attr
);
278 #else /* __i386__ || __x86_64__ */
279 lck_spin_init(&c_seg3
->c_lock
, vm_compressor_lck_grp
, vm_compressor_lck_attr
);
280 #endif /* __i386__ || __x86_64__ */
283 memset((void*)addr
, (int) 'a', PAGE_SIZE_64
);
284 memset((void*)(addr
+ PAGE_SIZE_64
), (int) 'b', PAGE_SIZE_64
);
285 memset((void*)(addr
+ (2 * PAGE_SIZE_64
)), (int) 'c', PAGE_SIZE_64
);
286 memset((void*)(addr
+ (3 * PAGE_SIZE_64
)), (int) 'd', PAGE_SIZE_64
);
288 vm_swap_put(addr
, &f_offset
, PAGE_SIZE_64
, c_seg
);
289 c_seg
->c_store
.c_swap_handle
= f_offset
;
291 vm_swap_put(addr
+ PAGE_SIZE_64
, &f_offset1
, PAGE_SIZE_64
, c_seg1
);
292 c_seg1
->c_store
.c_swap_handle
= f_offset1
;
294 vm_swap_put(addr
+ (2 * PAGE_SIZE_64
), &f_offset2
, PAGE_SIZE_64
, c_seg2
);
295 c_seg2
->c_store
.c_swap_handle
= f_offset2
;
297 vm_swap_put(addr
+ (3 * PAGE_SIZE_64
), &f_offset3
, PAGE_SIZE_64
, c_seg3
);
298 c_seg3
->c_store
.c_swap_handle
= f_offset3
;
300 //vm_swap_free(f_offset);
301 vm_swap_get(dup_addr
, f_offset
, PAGE_SIZE_64
);
303 //vm_swap_free(f_offset1);
305 vm_swap_get(dup_addr
+ PAGE_SIZE_64
, c_seg1
->c_store
.c_swap_handle
, PAGE_SIZE_64
);
307 //vm_swap_free(f_offset2);
309 vm_swap_get(dup_addr
+ (2 * PAGE_SIZE_64
), c_seg2
->c_store
.c_swap_handle
, PAGE_SIZE_64
);
311 //vm_swap_free(f_offset3);
313 vm_swap_get(dup_addr
+ (3 * PAGE_SIZE_64
), c_seg3
->c_store
.c_swap_handle
, PAGE_SIZE_64
);
315 if (memcmp((void*)addr
, (void*)dup_addr
, PAGE_SIZE_64
)) {
316 panic("First page data mismatch\n");
321 if (memcmp((void*)(addr
+ PAGE_SIZE_64
), (void*)(dup_addr
+ PAGE_SIZE_64
), PAGE_SIZE_64
)) {
322 panic("Second page data mismatch 0x%lx, 0x%lxn", addr
, dup_addr
);
327 if (memcmp((void*)(addr
+ (2 * PAGE_SIZE_64
)), (void*)(dup_addr
+ (2 * PAGE_SIZE_64
)), PAGE_SIZE_64
)) {
328 panic("Third page data mismatch\n");
333 if (memcmp((void*)(addr
+ (3 * PAGE_SIZE_64
)), (void*)(dup_addr
+ (3 * PAGE_SIZE_64
)), PAGE_SIZE_64
)) {
334 panic("Fourth page data mismatch 0x%lx, 0x%lxn", addr
, dup_addr
);
340 printf("Sanity check %s\n", ((kr
!= KERN_SUCCESS
) ? "FAILED" : "SUCCEEDED"));
341 kfree((void*)addr
, 4 * COMPRESSED_SWAP_CHUNK_SIZE
);
343 kfree((void*)dup_addr
, 4 * COMPRESSED_SWAP_CHUNK_SIZE
);
346 #endif /* SANITY_CHECK_SWAP_ROUTINES */
349 printf("VM Swap Subsystem is %s\n", (vm_swap_up
== TRUE
) ? "ON" : "OFF");
354 vm_swap_encrypt(c_segment_t c_seg
)
356 vm_offset_t kernel_vaddr
= 0;
360 unsigned char aes_iv
[AES_BLOCK_SIZE
];
364 assert(swap_crypt_ctx_initialized
);
366 bzero(&encrypt_iv
.aes_iv
[0], sizeof (encrypt_iv
.aes_iv
));
368 encrypt_iv
.c_seg
= (void*)c_seg
;
370 /* encrypt the "initial vector" */
371 aes_encrypt_cbc((const unsigned char *) &encrypt_iv
.aes_iv
[0],
374 &encrypt_iv
.aes_iv
[0],
375 &swap_crypt_ctx
.encrypt
);
377 kernel_vaddr
= (vm_offset_t
) c_seg
->c_store
.c_buffer
;
378 size
= round_page_32(C_SEG_OFFSET_TO_BYTES(c_seg
->c_populated_offset
));
381 * Encrypt the c_segment.
383 aes_encrypt_cbc((const unsigned char *) kernel_vaddr
,
384 &encrypt_iv
.aes_iv
[0],
385 (unsigned int)(size
/ AES_BLOCK_SIZE
),
386 (unsigned char *) kernel_vaddr
,
387 &swap_crypt_ctx
.encrypt
);
389 vm_page_encrypt_counter
+= (size
/PAGE_SIZE_64
);
393 vm_swap_decrypt(c_segment_t c_seg
)
396 vm_offset_t kernel_vaddr
= 0;
400 unsigned char aes_iv
[AES_BLOCK_SIZE
];
405 assert(swap_crypt_ctx_initialized
);
408 * Prepare an "initial vector" for the decryption.
409 * It has to be the same as the "initial vector" we
410 * used to encrypt that page.
412 bzero(&decrypt_iv
.aes_iv
[0], sizeof (decrypt_iv
.aes_iv
));
414 decrypt_iv
.c_seg
= (void*)c_seg
;
416 /* encrypt the "initial vector" */
417 aes_encrypt_cbc((const unsigned char *) &decrypt_iv
.aes_iv
[0],
420 &decrypt_iv
.aes_iv
[0],
421 &swap_crypt_ctx
.encrypt
);
423 kernel_vaddr
= (vm_offset_t
) c_seg
->c_store
.c_buffer
;
424 size
= round_page_32(C_SEG_OFFSET_TO_BYTES(c_seg
->c_populated_offset
));
427 * Decrypt the c_segment.
429 aes_decrypt_cbc((const unsigned char *) kernel_vaddr
,
430 &decrypt_iv
.aes_iv
[0],
431 (unsigned int) (size
/ AES_BLOCK_SIZE
),
432 (unsigned char *) kernel_vaddr
,
433 &swap_crypt_ctx
.decrypt
);
435 vm_page_decrypt_counter
+= (size
/PAGE_SIZE_64
);
441 vm_swap_consider_defragmenting()
443 if (compressor_store_stop_compaction
== FALSE
&& !VM_SWAP_BUSY() && (VM_SWAP_SHOULD_DEFRAGMENT() || VM_SWAP_SHOULD_RECLAIM())) {
445 if (!vm_swapfile_mgmt_thread_running
) {
446 lck_mtx_lock(&vm_swap_data_lock
);
448 if (!vm_swapfile_mgmt_thread_running
)
449 thread_wakeup((event_t
) &vm_swapfile_mgmt_needed
);
451 lck_mtx_unlock(&vm_swap_data_lock
);
457 int vm_swap_defragment_yielded
= 0;
458 int vm_swap_defragment_swapin
= 0;
459 int vm_swap_defragment_free
= 0;
460 int vm_swap_defragment_busy
= 0;
469 * have to grab the master lock w/o holding
470 * any locks in spin mode
472 PAGE_REPLACEMENT_DISALLOWED(TRUE
);
474 lck_mtx_lock_spin_always(c_list_lock
);
476 while (!queue_empty(&c_swappedout_sparse_list_head
)) {
478 if (compressor_store_stop_compaction
== TRUE
|| VM_SWAP_BUSY()) {
479 vm_swap_defragment_yielded
++;
482 c_seg
= (c_segment_t
)queue_first(&c_swappedout_sparse_list_head
);
484 lck_mtx_lock_spin_always(&c_seg
->c_lock
);
486 assert(c_seg
->c_on_swappedout_sparse_q
);
489 lck_mtx_unlock_always(c_list_lock
);
491 PAGE_REPLACEMENT_DISALLOWED(FALSE
);
493 * c_seg_wait_on_busy consumes c_seg->c_lock
495 c_seg_wait_on_busy(c_seg
);
497 PAGE_REPLACEMENT_DISALLOWED(TRUE
);
499 lck_mtx_lock_spin_always(c_list_lock
);
501 vm_swap_defragment_busy
++;
504 if (c_seg
->c_bytes_used
== 0) {
506 * c_seg_free_locked consumes the c_list_lock
509 c_seg_free_locked(c_seg
);
511 vm_swap_defragment_free
++;
513 lck_mtx_unlock_always(c_list_lock
);
515 c_seg_swapin(c_seg
, TRUE
);
516 lck_mtx_unlock_always(&c_seg
->c_lock
);
518 vm_swap_defragment_swapin
++;
520 PAGE_REPLACEMENT_DISALLOWED(FALSE
);
522 vm_pageout_io_throttle();
525 * because write waiters have privilege over readers,
526 * dropping and immediately retaking the master lock will
527 * still allow any thread waiting to acquire the
528 * master lock exclusively an opportunity to take it
530 PAGE_REPLACEMENT_DISALLOWED(TRUE
);
532 lck_mtx_lock_spin_always(c_list_lock
);
534 lck_mtx_unlock_always(c_list_lock
);
536 PAGE_REPLACEMENT_DISALLOWED(FALSE
);
542 vm_swapfile_mgmt_thread(void)
545 boolean_t did_work
= FALSE
;
549 vm_swapfile_mgmt_thread_awakened
++;
550 vm_swapfile_mgmt_thread_running
= 1;
555 if (vm_swap_up
== FALSE
)
558 clock_get_system_nanotime(&sec
, &nsec
);
561 * walk through the list of swap files
562 * and do the delayed frees/trims for
563 * any swap file whose count of delayed
564 * frees is above the batch limit
566 vm_swap_handle_delayed_trims(FALSE
);
568 if (VM_SWAP_SHOULD_CREATE(sec
)) {
569 if (vm_swap_create_file() == TRUE
)
572 vm_swapfile_last_failed_to_create_ts
= sec
;
573 HIBLOG("vm_swap_create_file failed @ %lu secs\n", sec
);
576 if (VM_SWAP_SHOULD_DEFRAGMENT()) {
577 proc_set_task_policy_thread(kernel_task
, current_thread()->thread_id
,
578 TASK_POLICY_INTERNAL
, TASK_POLICY_IO
, THROTTLE_LEVEL_COMPRESSOR_TIER2
);
580 vm_swap_defragment();
585 proc_set_task_policy_thread(kernel_task
, current_thread()->thread_id
,
586 TASK_POLICY_INTERNAL
, TASK_POLICY_IO
, THROTTLE_LEVEL_COMPRESSOR_TIER1
);
588 if (VM_SWAP_SHOULD_RECLAIM()) {
589 proc_set_task_policy_thread(kernel_task
, current_thread()->thread_id
,
590 TASK_POLICY_INTERNAL
, TASK_POLICY_IO
, THROTTLE_LEVEL_COMPRESSOR_TIER2
);
592 vm_swap_defragment();
598 proc_set_task_policy_thread(kernel_task
, current_thread()->thread_id
,
599 TASK_POLICY_INTERNAL
, TASK_POLICY_IO
, THROTTLE_LEVEL_COMPRESSOR_TIER1
);
602 } while (did_work
== TRUE
);
604 lck_mtx_lock(&vm_swap_data_lock
);
606 clock_get_system_nanotime(&sec
, &nsec
);
608 if (vm_swap_up
== TRUE
&& (VM_SWAP_SHOULD_CREATE(sec
) || ((!VM_SWAP_BUSY() && compressor_store_stop_compaction
== FALSE
) &&
609 (VM_SWAP_SHOULD_DEFRAGMENT() || VM_SWAP_SHOULD_RECLAIM())))) {
610 lck_mtx_unlock(&vm_swap_data_lock
);
614 vm_swapfile_mgmt_thread_running
= 0;
616 assert_wait((event_t
)&vm_swapfile_mgmt_needed
, THREAD_UNINT
);
618 lck_mtx_unlock(&vm_swap_data_lock
);
620 thread_block((thread_continue_t
)vm_swapfile_mgmt_thread
);
627 int swapper_entered_T0
= 0;
628 int swapper_entered_T1
= 0;
629 int swapper_entered_T2
= 0;
632 vm_swapout_thread_throttle_adjust(void)
634 int swapper_throttle_new
;
636 if (swapper_throttle_inited
== FALSE
) {
638 * force this thread to be set to the correct
641 swapper_throttle_new
= THROTTLE_LEVEL_COMPRESSOR_TIER2
;
642 swapper_throttle
= THROTTLE_LEVEL_COMPRESSOR_TIER1
;
643 swapper_throttle_inited
= TRUE
;
644 swapper_entered_T2
++;
647 swapper_throttle_new
= swapper_throttle
;
650 switch(swapper_throttle
) {
652 case THROTTLE_LEVEL_COMPRESSOR_TIER2
:
654 if (SWAPPER_NEEDS_TO_UNTHROTTLE() || swapout_target_age
|| hibernate_flushing
== TRUE
) {
655 swapper_throttle_new
= THROTTLE_LEVEL_COMPRESSOR_TIER1
;
656 swapper_entered_T1
++;
661 case THROTTLE_LEVEL_COMPRESSOR_TIER1
:
663 if (VM_PAGEOUT_SCAN_NEEDS_TO_THROTTLE()) {
664 swapper_throttle_new
= THROTTLE_LEVEL_COMPRESSOR_TIER0
;
665 swapper_entered_T0
++;
668 if (COMPRESSOR_NEEDS_TO_SWAP() == 0 && swapout_target_age
== 0 && hibernate_flushing
== FALSE
) {
669 swapper_throttle_new
= THROTTLE_LEVEL_COMPRESSOR_TIER2
;
670 swapper_entered_T2
++;
675 case THROTTLE_LEVEL_COMPRESSOR_TIER0
:
677 if (COMPRESSOR_NEEDS_TO_SWAP() == 0) {
678 swapper_throttle_new
= THROTTLE_LEVEL_COMPRESSOR_TIER2
;
679 swapper_entered_T2
++;
682 if (SWAPPER_NEEDS_TO_UNTHROTTLE() == 0) {
683 swapper_throttle_new
= THROTTLE_LEVEL_COMPRESSOR_TIER1
;
684 swapper_entered_T1
++;
690 if (swapper_throttle
!= swapper_throttle_new
) {
691 proc_set_task_policy_thread(kernel_task
, vm_swapout_thread_id
,
692 TASK_POLICY_INTERNAL
, TASK_POLICY_IO
, swapper_throttle_new
);
693 proc_set_task_policy_thread(kernel_task
, vm_swapout_thread_id
,
694 TASK_POLICY_INTERNAL
, TASK_POLICY_PASSIVE_IO
, TASK_POLICY_ENABLE
);
696 swapper_throttle
= swapper_throttle_new
;
702 vm_swapout_thread(void)
704 uint64_t f_offset
= 0;
706 c_segment_t c_seg
= NULL
;
707 kern_return_t kr
= KERN_SUCCESS
;
708 vm_offset_t addr
= 0;
710 vm_swapout_thread_awakened
++;
712 lck_mtx_lock_spin_always(c_list_lock
);
714 while (!queue_empty(&c_swapout_list_head
)) {
716 c_seg
= (c_segment_t
)queue_first(&c_swapout_list_head
);
718 lck_mtx_lock_spin_always(&c_seg
->c_lock
);
720 assert(c_seg
->c_on_swapout_q
);
723 lck_mtx_unlock_always(c_list_lock
);
725 c_seg_wait_on_busy(c_seg
);
727 lck_mtx_lock_spin_always(c_list_lock
);
731 queue_remove(&c_swapout_list_head
, c_seg
, c_segment_t
, c_age_list
);
732 c_seg
->c_on_swapout_q
= 0;
735 vm_swapout_thread_processed_segments
++;
737 thread_wakeup((event_t
)&compaction_swapper_running
);
739 size
= round_page_32(C_SEG_OFFSET_TO_BYTES(c_seg
->c_populated_offset
));
742 c_seg_free_locked(c_seg
);
743 goto c_seg_was_freed
;
746 c_seg
->c_busy_swapping
= 1;
748 lck_mtx_unlock_always(c_list_lock
);
750 addr
= (vm_offset_t
) c_seg
->c_store
.c_buffer
;
752 lck_mtx_unlock_always(&c_seg
->c_lock
);
754 #if CHECKSUM_THE_SWAP
755 c_seg
->cseg_hash
= hash_string((char*)addr
, (int)size
);
756 c_seg
->cseg_swap_size
= size
;
757 #endif /* CHECKSUM_THE_SWAP */
760 vm_swap_encrypt(c_seg
);
763 vm_swapout_thread_throttle_adjust();
765 kr
= vm_swap_put((vm_offset_t
) addr
, &f_offset
, size
, c_seg
);
767 PAGE_REPLACEMENT_DISALLOWED(TRUE
);
769 lck_mtx_lock_spin_always(c_list_lock
);
770 lck_mtx_lock_spin_always(&c_seg
->c_lock
);
772 if (kr
== KERN_SUCCESS
) {
774 if (C_SEG_ONDISK_IS_SPARSE(c_seg
) && hibernate_flushing
== FALSE
) {
776 c_seg_insert_into_q(&c_swappedout_sparse_list_head
, c_seg
);
777 c_seg
->c_on_swappedout_sparse_q
= 1;
778 c_swappedout_sparse_count
++;
781 if (hibernate_flushing
== TRUE
&& (c_seg
->c_generation_id
>= first_c_segment_to_warm_generation_id
&&
782 c_seg
->c_generation_id
<= last_c_segment_to_warm_generation_id
))
783 queue_enter_first(&c_swappedout_list_head
, c_seg
, c_segment_t
, c_age_list
);
785 queue_enter(&c_swappedout_list_head
, c_seg
, c_segment_t
, c_age_list
);
786 c_seg
->c_on_swappedout_q
= 1;
787 c_swappedout_count
++;
789 c_seg
->c_store
.c_swap_handle
= f_offset
;
792 VM_STAT_INCR_BY(swapouts
, size
>> PAGE_SHIFT
);
794 if (c_seg
->c_bytes_used
)
795 OSAddAtomic64(-c_seg
->c_bytes_used
, &compressor_bytes_used
);
798 vm_swap_decrypt(c_seg
);
800 c_seg_insert_into_q(&c_age_list_head
, c_seg
);
801 c_seg
->c_on_age_q
= 1;
804 vm_swap_put_failures
++;
806 lck_mtx_unlock_always(c_list_lock
);
808 c_seg
->c_busy_swapping
= 0;
810 C_SEG_WAKEUP_DONE(c_seg
);
812 if (c_seg
->c_must_free
)
815 lck_mtx_unlock_always(&c_seg
->c_lock
);
817 if (kr
== KERN_SUCCESS
)
818 kernel_memory_depopulate(kernel_map
, (vm_offset_t
) addr
, size
, KMA_COMPRESSOR
);
820 PAGE_REPLACEMENT_DISALLOWED(FALSE
);
822 if (kr
== KERN_SUCCESS
)
823 kmem_free(kernel_map
, (vm_offset_t
) addr
, C_SEG_ALLOCSIZE
);
825 vm_pageout_io_throttle();
827 if (c_swapout_count
== 0)
828 vm_swap_consider_defragmenting();
830 lck_mtx_lock_spin_always(c_list_lock
);
833 assert_wait((event_t
)&c_swapout_list_head
, THREAD_UNINT
);
835 lck_mtx_unlock_always(c_list_lock
);
837 thread_block((thread_continue_t
)vm_swapout_thread
);
843 vm_swap_create_file()
847 boolean_t swap_file_created
= FALSE
;
848 boolean_t swap_file_reuse
= FALSE
;
849 struct swapfile
*swf
= NULL
;
852 if (DEFAULT_PAGER_IS_ACTIVE
|| DEFAULT_FREEZER_IS_ACTIVE
) {
856 * Any swapfile structure ready for re-use?
859 lck_mtx_lock(&vm_swap_data_lock
);
861 swf
= (struct swapfile
*) queue_first(&swf_global_queue
);
863 while (queue_end(&swf_global_queue
, (queue_entry_t
)swf
) == FALSE
) {
864 if (swf
->swp_flags
== SWAP_REUSE
) {
865 swap_file_reuse
= TRUE
;
868 swf
= (struct swapfile
*) queue_next(&swf
->swp_queue
);
871 lck_mtx_unlock(&vm_swap_data_lock
);
873 if (swap_file_reuse
== FALSE
) {
875 namelen
= SWAPFILENAME_LEN
+ SWAPFILENAME_INDEX_LEN
+ 1;
877 swf
= (struct swapfile
*) kalloc(sizeof *swf
);
878 memset(swf
, 0, sizeof(*swf
));
880 swf
->swp_index
= vm_num_swap_files
+ 1;
881 swf
->swp_pathlen
= namelen
;
882 swf
->swp_path
= (char*)kalloc(swf
->swp_pathlen
);
884 memset(swf
->swp_path
, 0, namelen
);
886 snprintf(swf
->swp_path
, namelen
, "%s%d", SWAP_FILE_NAME
, vm_num_swap_files
+ 1);
889 vm_swapfile_open(swf
->swp_path
, &swf
->swp_vp
);
891 if (swf
->swp_vp
== NULL
) {
892 if (swap_file_reuse
== FALSE
) {
893 kfree(swf
->swp_path
, swf
->swp_pathlen
);
894 kfree(swf
, sizeof *swf
);
898 size
= MAX_SWAP_FILE_SIZE
;
900 while (size
>= MIN_SWAP_FILE_SIZE
) {
902 if (vm_swapfile_preallocate(swf
->swp_vp
, &size
) == 0) {
904 int num_bytes_for_bitmap
= 0;
906 swap_file_created
= TRUE
;
908 swf
->swp_size
= size
;
909 swf
->swp_nsegs
= (unsigned int) (size
/ COMPRESSED_SWAP_CHUNK_SIZE
);
910 swf
->swp_nseginuse
= 0;
911 swf
->swp_free_hint
= 0;
913 num_bytes_for_bitmap
= MAX((swf
->swp_nsegs
>> 3) , 1);
915 * Allocate a bitmap that describes the
916 * number of segments held by this swapfile.
918 swf
->swp_bitmap
= (uint8_t*)kalloc(num_bytes_for_bitmap
);
919 memset(swf
->swp_bitmap
, 0, num_bytes_for_bitmap
);
921 swf
->swp_csegs
= (c_segment_t
*) kalloc(swf
->swp_nsegs
* sizeof(c_segment_t
));
922 memset(swf
->swp_csegs
, 0, (swf
->swp_nsegs
* sizeof(c_segment_t
)));
925 * passing a NULL trim_list into vnode_trim_list
926 * will return ENOTSUP if trim isn't supported
929 if (vnode_trim_list(swf
->swp_vp
, NULL
))
930 swf
->swp_trim_supported
= FALSE
;
932 swf
->swp_trim_supported
= TRUE
;
934 lck_mtx_lock(&vm_swap_data_lock
);
936 swf
->swp_flags
= SWAP_READY
;
938 if (swap_file_reuse
== FALSE
) {
939 queue_enter(&swf_global_queue
, swf
, struct swapfile
*, swp_queue
);
944 vm_swapfile_total_segs_alloced
+= swf
->swp_nsegs
;
946 lck_mtx_unlock(&vm_swap_data_lock
);
948 thread_wakeup((event_t
) &vm_num_swap_files
);
956 if (swap_file_created
== FALSE
) {
958 vm_swapfile_close((uint64_t)(swf
->swp_path
), swf
->swp_vp
);
962 if (swap_file_reuse
== FALSE
) {
963 kfree(swf
->swp_path
, swf
->swp_pathlen
);
964 kfree(swf
, sizeof *swf
);
967 return swap_file_created
;
972 vm_swap_get(vm_offset_t addr
, uint64_t f_offset
, uint64_t size
)
974 struct swapfile
*swf
= NULL
;
975 uint64_t file_offset
= 0;
982 lck_mtx_lock(&vm_swap_data_lock
);
984 swf
= vm_swapfile_for_handle(f_offset
);
987 if ((swf
->swp_flags
& SWAP_READY
) || (swf
->swp_flags
& SWAP_RECLAIM
)) {
990 file_offset
= (f_offset
& SWAP_SLOT_MASK
);
992 lck_mtx_unlock(&vm_swap_data_lock
);
996 lck_mtx_unlock(&vm_swap_data_lock
);
1001 lck_mtx_unlock(&vm_swap_data_lock
);
1002 return KERN_FAILURE
;
1005 retval
= vm_swapfile_io(swf
->swp_vp
, file_offset
, addr
, (int)(size
/ PAGE_SIZE_64
), SWAP_READ
);
1008 * Free this slot in the swap structure.
1010 vm_swap_free(f_offset
);
1012 lck_mtx_lock(&vm_swap_data_lock
);
1013 swf
->swp_io_count
--;
1015 if ((swf
->swp_flags
& SWAP_WANTED
) && swf
->swp_io_count
== 0) {
1017 swf
->swp_flags
&= ~SWAP_WANTED
;
1018 thread_wakeup((event_t
) &swf
->swp_flags
);
1021 VM_STAT_INCR_BY(swapins
, size
>> PAGE_SHIFT
);
1022 lck_mtx_unlock(&vm_swap_data_lock
);
1025 return KERN_SUCCESS
;
1027 vm_swap_get_failures
++;
1028 return KERN_FAILURE
;
1033 vm_swap_put(vm_offset_t addr
, uint64_t *f_offset
, uint64_t size
, c_segment_t c_seg
)
1035 unsigned int segidx
= 0;
1036 struct swapfile
*swf
= NULL
;
1037 uint64_t file_offset
= 0;
1038 uint64_t swapfile_index
= 0;
1039 unsigned int byte_for_segidx
= 0;
1040 unsigned int offset_within_byte
= 0;
1041 boolean_t swf_eligible
= FALSE
;
1042 boolean_t waiting
= FALSE
;
1047 if (addr
== 0 || f_offset
== NULL
) {
1048 return KERN_FAILURE
;
1051 lck_mtx_lock(&vm_swap_data_lock
);
1053 swf
= (struct swapfile
*) queue_first(&swf_global_queue
);
1055 while(queue_end(&swf_global_queue
, (queue_entry_t
)swf
) == FALSE
) {
1057 segidx
= swf
->swp_free_hint
;
1059 swf_eligible
= (swf
->swp_flags
& SWAP_READY
) && (swf
->swp_nseginuse
< swf
->swp_nsegs
);
1063 while(segidx
< swf
->swp_nsegs
) {
1065 byte_for_segidx
= segidx
>> 3;
1066 offset_within_byte
= segidx
% 8;
1068 if ((swf
->swp_bitmap
)[byte_for_segidx
] & (1 << offset_within_byte
)) {
1073 (swf
->swp_bitmap
)[byte_for_segidx
] |= (1 << offset_within_byte
);
1075 file_offset
= segidx
* COMPRESSED_SWAP_CHUNK_SIZE
;
1076 swf
->swp_nseginuse
++;
1077 swf
->swp_io_count
++;
1078 swapfile_index
= swf
->swp_index
;
1080 vm_swapfile_total_segs_used
++;
1082 clock_get_system_nanotime(&sec
, &nsec
);
1084 if (VM_SWAP_SHOULD_CREATE(sec
) && !vm_swapfile_mgmt_thread_running
)
1085 thread_wakeup((event_t
) &vm_swapfile_mgmt_needed
);
1087 lck_mtx_unlock(&vm_swap_data_lock
);
1092 swf
= (struct swapfile
*) queue_next(&swf
->swp_queue
);
1094 assert(queue_end(&swf_global_queue
, (queue_entry_t
) swf
));
1097 * we've run out of swap segments, but may not
1098 * be in a position to immediately create a new swap
1099 * file if we've recently failed to create due to a lack
1100 * of free space in the root filesystem... we'll try
1101 * to kick that create off, but in any event we're going
1102 * to take a breather (up to 1 second) so that we're not caught in a tight
1103 * loop back in "vm_compressor_compact_and_swap" trying to stuff
1104 * segments into swap files only to have them immediately put back
1105 * on the c_age queue due to vm_swap_put failing.
1107 * if we're doing these puts due to a hibernation flush,
1108 * no need to block... setting hibernate_no_swapspace to TRUE,
1109 * will cause "vm_compressor_compact_and_swap" to immediately abort
1111 clock_get_system_nanotime(&sec
, &nsec
);
1113 if (VM_SWAP_SHOULD_CREATE(sec
) && !vm_swapfile_mgmt_thread_running
)
1114 thread_wakeup((event_t
) &vm_swapfile_mgmt_needed
);
1116 if (hibernate_flushing
== FALSE
|| VM_SWAP_SHOULD_CREATE(sec
)) {
1118 assert_wait_timeout((event_t
) &vm_num_swap_files
, THREAD_INTERRUPTIBLE
, 1000, 1000*NSEC_PER_USEC
);
1120 hibernate_no_swapspace
= TRUE
;
1122 lck_mtx_unlock(&vm_swap_data_lock
);
1124 if (waiting
== TRUE
)
1125 thread_block(THREAD_CONTINUE_NULL
);
1127 return KERN_FAILURE
;
1130 error
= vm_swapfile_io(swf
->swp_vp
, file_offset
, addr
, (int) (size
/ PAGE_SIZE_64
), SWAP_WRITE
);
1132 lck_mtx_lock(&vm_swap_data_lock
);
1134 swf
->swp_csegs
[segidx
] = c_seg
;
1136 swf
->swp_io_count
--;
1138 *f_offset
= (swapfile_index
<< SWAP_DEVICE_SHIFT
) | file_offset
;
1140 if ((swf
->swp_flags
& SWAP_WANTED
) && swf
->swp_io_count
== 0) {
1142 swf
->swp_flags
&= ~SWAP_WANTED
;
1143 thread_wakeup((event_t
) &swf
->swp_flags
);
1146 lck_mtx_unlock(&vm_swap_data_lock
);
1148 #if SANITY_CHECK_SWAP_ROUTINES
1149 printf("Returned 0x%llx as offset\n", *f_offset
);
1150 #endif /* SANITY_CHECK_SWAP_ROUTINES */
1153 vm_swap_free(*f_offset
);
1155 return KERN_FAILURE
;
1157 return KERN_SUCCESS
;
1163 vm_swap_free_now(struct swapfile
*swf
, uint64_t f_offset
)
1165 uint64_t file_offset
= 0;
1166 unsigned int segidx
= 0;
1169 if ((swf
->swp_flags
& SWAP_READY
) || (swf
->swp_flags
& SWAP_RECLAIM
)) {
1171 unsigned int byte_for_segidx
= 0;
1172 unsigned int offset_within_byte
= 0;
1174 file_offset
= (f_offset
& SWAP_SLOT_MASK
);
1175 segidx
= (unsigned int) (file_offset
/ COMPRESSED_SWAP_CHUNK_SIZE
);
1177 byte_for_segidx
= segidx
>> 3;
1178 offset_within_byte
= segidx
% 8;
1180 if ((swf
->swp_bitmap
)[byte_for_segidx
] & (1 << offset_within_byte
)) {
1182 (swf
->swp_bitmap
)[byte_for_segidx
] &= ~(1 << offset_within_byte
);
1184 swf
->swp_csegs
[segidx
] = NULL
;
1186 swf
->swp_nseginuse
--;
1187 vm_swapfile_total_segs_used
--;
1189 if (segidx
< swf
->swp_free_hint
) {
1190 swf
->swp_free_hint
= segidx
;
1193 if (VM_SWAP_SHOULD_RECLAIM() && !vm_swapfile_mgmt_thread_running
)
1194 thread_wakeup((event_t
) &vm_swapfile_mgmt_needed
);
1196 lck_mtx_unlock(&vm_swap_data_lock
);
1200 uint32_t vm_swap_free_now_count
= 0;
1201 uint32_t vm_swap_free_delayed_count
= 0;
1205 vm_swap_free(uint64_t f_offset
)
1207 struct swapfile
*swf
= NULL
;
1208 struct trim_list
*tl
;
1212 lck_mtx_lock(&vm_swap_data_lock
);
1214 swf
= vm_swapfile_for_handle(f_offset
);
1216 if (swf
&& (swf
->swp_flags
& (SWAP_READY
| SWAP_RECLAIM
))) {
1218 if (swf
->swp_trim_supported
== FALSE
|| (swf
->swp_flags
& SWAP_RECLAIM
)) {
1220 * don't delay the free if the underlying disk doesn't support
1221 * trim, or we're in the midst of reclaiming this swap file since
1222 * we don't want to move segments that are technically free
1223 * but not yet handled by the delayed free mechanism
1225 vm_swap_free_now(swf
, f_offset
);
1227 vm_swap_free_now_count
++;
1230 tl
= kalloc(sizeof(struct trim_list
));
1232 tl
->tl_offset
= f_offset
& SWAP_SLOT_MASK
;
1233 tl
->tl_length
= COMPRESSED_SWAP_CHUNK_SIZE
;
1235 tl
->tl_next
= swf
->swp_delayed_trim_list_head
;
1236 swf
->swp_delayed_trim_list_head
= tl
;
1237 swf
->swp_delayed_trim_count
++;
1239 if (VM_SWAP_SHOULD_TRIM(swf
) && !vm_swapfile_mgmt_thread_running
) {
1240 clock_get_system_nanotime(&sec
, &nsec
);
1242 if (sec
> dont_trim_until_ts
)
1243 thread_wakeup((event_t
) &vm_swapfile_mgmt_needed
);
1245 vm_swap_free_delayed_count
++;
1247 lck_mtx_unlock(&vm_swap_data_lock
);
1252 vm_swap_handle_delayed_trims(boolean_t force_now
)
1254 struct swapfile
*swf
= NULL
;
1257 * because swap files are created or reclaimed on the
1258 * same thread that calls this function, it's safe
1259 * to iterate "swf_global_queue" w/o holding
1260 * the lock since those are the only 2 cases that can
1261 * change the items on the "swf_global_queue"
1263 swf
= (struct swapfile
*) queue_first(&swf_global_queue
);
1265 while (queue_end(&swf_global_queue
, (queue_entry_t
)swf
) == FALSE
) {
1267 assert(!(swf
->swp_flags
& SWAP_RECLAIM
));
1269 if ((swf
->swp_flags
& SWAP_READY
) && (force_now
== TRUE
|| VM_SWAP_SHOULD_TRIM(swf
)))
1270 vm_swap_do_delayed_trim(swf
);
1272 swf
= (struct swapfile
*) queue_next(&swf
->swp_queue
);
1278 vm_swap_do_delayed_trim(struct swapfile
*swf
)
1280 struct trim_list
*tl
, *tl_head
;
1282 lck_mtx_lock(&vm_swap_data_lock
);
1284 tl_head
= swf
->swp_delayed_trim_list_head
;
1285 swf
->swp_delayed_trim_list_head
= NULL
;
1286 swf
->swp_delayed_trim_count
= 0;
1288 lck_mtx_unlock(&vm_swap_data_lock
);
1290 vnode_trim_list(swf
->swp_vp
, tl_head
);
1292 while ((tl
= tl_head
) != NULL
) {
1293 unsigned int segidx
= 0;
1294 unsigned int byte_for_segidx
= 0;
1295 unsigned int offset_within_byte
= 0;
1297 lck_mtx_lock(&vm_swap_data_lock
);
1299 segidx
= (unsigned int) (tl
->tl_offset
/ COMPRESSED_SWAP_CHUNK_SIZE
);
1301 byte_for_segidx
= segidx
>> 3;
1302 offset_within_byte
= segidx
% 8;
1304 if ((swf
->swp_bitmap
)[byte_for_segidx
] & (1 << offset_within_byte
)) {
1306 (swf
->swp_bitmap
)[byte_for_segidx
] &= ~(1 << offset_within_byte
);
1308 swf
->swp_csegs
[segidx
] = NULL
;
1310 swf
->swp_nseginuse
--;
1311 vm_swapfile_total_segs_used
--;
1313 if (segidx
< swf
->swp_free_hint
) {
1314 swf
->swp_free_hint
= segidx
;
1317 lck_mtx_unlock(&vm_swap_data_lock
);
1319 tl_head
= tl
->tl_next
;
1321 kfree(tl
, sizeof(struct trim_list
));
1332 int vm_swap_reclaim_yielded
= 0;
1335 vm_swap_reclaim(void)
1337 vm_offset_t addr
= 0;
1338 unsigned int segidx
= 0;
1339 uint64_t f_offset
= 0;
1340 struct swapfile
*swf
= NULL
;
1341 struct swapfile
*smallest_swf
= NULL
;
1342 unsigned int min_nsegs
= 0;
1343 unsigned int byte_for_segidx
= 0;
1344 unsigned int offset_within_byte
= 0;
1345 uint32_t c_size
= 0;
1347 c_segment_t c_seg
= NULL
;
1349 if (kernel_memory_allocate(kernel_map
, (vm_offset_t
*)(&addr
), C_SEG_BUFSIZE
, 0, KMA_KOBJECT
) != KERN_SUCCESS
) {
1350 panic("vm_swap_reclaim: kernel_memory_allocate failed\n");
1353 lck_mtx_lock(&vm_swap_data_lock
);
1355 swf
= (struct swapfile
*) queue_first(&swf_global_queue
);
1356 min_nsegs
= MAX_SWAP_FILE_SIZE
/ COMPRESSED_SWAP_CHUNK_SIZE
;
1357 smallest_swf
= NULL
;
1359 while (queue_end(&swf_global_queue
, (queue_entry_t
)swf
) == FALSE
) {
1361 if ((swf
->swp_flags
& SWAP_READY
) && (swf
->swp_nseginuse
<= min_nsegs
)) {
1364 min_nsegs
= swf
->swp_nseginuse
;
1366 swf
= (struct swapfile
*) queue_next(&swf
->swp_queue
);
1369 if (smallest_swf
== NULL
)
1375 swf
->swp_flags
&= ~SWAP_READY
;
1376 swf
->swp_flags
|= SWAP_RECLAIM
;
1378 if (swf
->swp_delayed_trim_count
) {
1380 lck_mtx_unlock(&vm_swap_data_lock
);
1382 vm_swap_do_delayed_trim(swf
);
1384 lck_mtx_lock(&vm_swap_data_lock
);
1388 while (segidx
< swf
->swp_nsegs
) {
1391 if (compressor_store_stop_compaction
== TRUE
|| (swf
->swp_trim_supported
== FALSE
&& VM_SWAP_BUSY())) {
1392 vm_swap_reclaim_yielded
++;
1396 * Wait for outgoing I/Os.
1398 while (swf
->swp_io_count
) {
1400 swf
->swp_flags
|= SWAP_WANTED
;
1402 assert_wait((event_t
) &swf
->swp_flags
, THREAD_UNINT
);
1403 lck_mtx_unlock(&vm_swap_data_lock
);
1405 thread_block(THREAD_CONTINUE_NULL
);
1407 lck_mtx_lock(&vm_swap_data_lock
);
1410 byte_for_segidx
= segidx
>> 3;
1411 offset_within_byte
= segidx
% 8;
1413 if (((swf
->swp_bitmap
)[byte_for_segidx
] & (1 << offset_within_byte
)) == 0) {
1419 c_seg
= swf
->swp_csegs
[segidx
];
1421 lck_mtx_lock_spin_always(&c_seg
->c_lock
);
1423 assert(c_seg
->c_ondisk
);
1425 if (c_seg
->c_busy
) {
1427 c_seg
->c_wanted
= 1;
1429 assert_wait((event_t
) (c_seg
), THREAD_UNINT
);
1430 lck_mtx_unlock_always(&c_seg
->c_lock
);
1432 lck_mtx_unlock(&vm_swap_data_lock
);
1434 thread_block(THREAD_CONTINUE_NULL
);
1436 lck_mtx_lock(&vm_swap_data_lock
);
1438 goto ReTry_for_cseg
;
1440 (swf
->swp_bitmap
)[byte_for_segidx
] &= ~(1 << offset_within_byte
);
1442 f_offset
= segidx
* COMPRESSED_SWAP_CHUNK_SIZE
;
1444 swf
->swp_csegs
[segidx
] = NULL
;
1445 swf
->swp_nseginuse
--;
1447 vm_swapfile_total_segs_used
--;
1449 lck_mtx_unlock(&vm_swap_data_lock
);
1451 if (c_seg
->c_must_free
) {
1457 c_seg
->c_busy_swapping
= 1;
1458 #if !CHECKSUM_THE_SWAP
1459 c_seg_trim_tail(c_seg
);
1462 #if SANITY_CHECK_SWAP_ROUTINES
1464 c_size
= COMPRESSED_SWAP_CHUNK_SIZE
;
1466 #else /* SANITY_CHECK_SWAP_ROUTINES */
1468 c_size
= round_page_32(C_SEG_OFFSET_TO_BYTES(c_seg
->c_populated_offset
));
1470 assert(c_size
<= C_SEG_BUFSIZE
);
1472 #endif /* SANITY_CHECK_SWAP_ROUTINES */
1474 lck_mtx_unlock_always(&c_seg
->c_lock
);
1476 if (vm_swapfile_io(swf
->swp_vp
, f_offset
, addr
, (int)(c_size
/ PAGE_SIZE_64
), SWAP_READ
)) {
1479 * reading the data back in failed, so convert c_seg
1480 * to a swapped in c_segment that contains no data
1482 c_seg
->c_store
.c_buffer
= (int32_t *)NULL
;
1483 c_seg_swapin_requeue(c_seg
);
1485 goto swap_io_failed
;
1487 VM_STAT_INCR_BY(swapins
, c_size
>> PAGE_SHIFT
);
1489 if (vm_swap_put(addr
, &f_offset
, c_size
, c_seg
)) {
1490 vm_offset_t c_buffer
;
1493 * the put failed, so convert c_seg to a fully swapped in c_segment
1496 if (kernel_memory_allocate(kernel_map
, &c_buffer
, C_SEG_ALLOCSIZE
, 0, KMA_COMPRESSOR
| KMA_VAONLY
) != KERN_SUCCESS
)
1497 panic("vm_swap_reclaim: kernel_memory_allocate failed\n");
1498 kernel_memory_populate(kernel_map
, c_buffer
, c_size
, KMA_COMPRESSOR
);
1500 memcpy((char *)c_buffer
, (char *)addr
, c_size
);
1502 c_seg
->c_store
.c_buffer
= (int32_t *)c_buffer
;
1504 vm_swap_decrypt(c_seg
);
1506 c_seg_swapin_requeue(c_seg
);
1508 OSAddAtomic64(c_seg
->c_bytes_used
, &compressor_bytes_used
);
1510 goto swap_io_failed
;
1512 VM_STAT_INCR_BY(swapouts
, c_size
>> PAGE_SHIFT
);
1514 lck_mtx_lock_spin_always(&c_seg
->c_lock
);
1516 assert(c_seg
->c_ondisk
);
1518 * The c_seg will now know about the new location on disk.
1520 c_seg
->c_store
.c_swap_handle
= f_offset
;
1522 c_seg
->c_busy_swapping
= 0;
1524 if (c_seg
->c_must_free
)
1527 C_SEG_WAKEUP_DONE(c_seg
);
1529 lck_mtx_unlock_always(&c_seg
->c_lock
);
1532 lck_mtx_lock(&vm_swap_data_lock
);
1535 if (swf
->swp_nseginuse
) {
1537 swf
->swp_flags
&= ~SWAP_RECLAIM
;
1538 swf
->swp_flags
|= SWAP_READY
;
1543 * We don't remove this inactive swf from the queue.
1544 * That way, we can re-use it when needed again and
1545 * preserve the namespace.
1547 //queue_remove(&swf_global_queue, swf, struct swapfile*, swp_queue);
1549 vm_num_swap_files
--;
1551 vm_swapfile_total_segs_alloced
-= swf
->swp_nsegs
;
1553 lck_mtx_unlock(&vm_swap_data_lock
);
1555 vm_swapfile_close((uint64_t)(swf
->swp_path
), swf
->swp_vp
);
1557 kfree(swf
->swp_csegs
, swf
->swp_nsegs
* sizeof(c_segment_t
));
1558 kfree(swf
->swp_bitmap
, MAX((swf
->swp_nsegs
>> 3), 1));
1560 lck_mtx_lock(&vm_swap_data_lock
);
1564 swf
->swp_free_hint
= 0;
1566 swf
->swp_flags
= SWAP_REUSE
;
1568 thread_wakeup((event_t
) &swf
->swp_flags
);
1570 lck_mtx_unlock(&vm_swap_data_lock
);
1572 kmem_free(kernel_map
, (vm_offset_t
) addr
, C_SEG_BUFSIZE
);
1577 vm_swap_get_total_space(void)
1579 uint64_t total_space
= 0;
1581 total_space
= (uint64_t)vm_swapfile_total_segs_alloced
* COMPRESSED_SWAP_CHUNK_SIZE
;
1587 vm_swap_get_used_space(void)
1589 uint64_t used_space
= 0;
1591 used_space
= (uint64_t)vm_swapfile_total_segs_used
* COMPRESSED_SWAP_CHUNK_SIZE
;
1597 vm_swap_get_free_space(void)
1599 return (vm_swap_get_total_space() - vm_swap_get_used_space());