1/*
2 * Copyright (c) 2000-2010 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#if CONFIG_FREEZE
30
31#ifndef CONFIG_MEMORYSTATUS
32#error "CONFIG_FREEZE defined without matching CONFIG_MEMORYSTATUS"
33#endif
34
35#include <vm/default_freezer.h>
36
37/*
38 * Indicates that a page has been faulted back in.
39 */
40#define FREEZER_OFFSET_ABSENT ((vm_object_offset_t)(-1))
41
42lck_grp_attr_t	default_freezer_handle_lck_grp_attr;
43lck_grp_t	default_freezer_handle_lck_grp;
44
45void
46default_freezer_init(void)
47{
48	lck_grp_attr_setdefault(&default_freezer_handle_lck_grp_attr);
49	lck_grp_init(&default_freezer_handle_lck_grp, "default_freezer_handle",
50		     &default_freezer_handle_lck_grp_attr);
51
52}
53
54
55/*
56 * Create the mapping table that will
57 * tell us the object/offset pair that
58 * corresponds to the page being sent
59 * out or being brought back in.
60 */
61
62default_freezer_mapping_table_t
63default_freezer_mapping_create(vm_object_t object, vm_offset_t offset)
64{
65	default_freezer_mapping_table_t table;
66
67	table = kalloc(sizeof(struct default_freezer_mapping_table));
68	if (table) {
69		memset(table, 0, sizeof(*table));
70	} else {
71		panic("Could not allocate mapping table\n");
72	}
73
74	table->object = object;
75	table->offset = offset;
76
77	return table;
78}
79
80/*
81 * Table modifications/lookup are done behind
82 * the compact_object lock.
83 */
84
85void
86default_freezer_mapping_free(default_freezer_mapping_table_t *table_p, boolean_t all)
87{
88	default_freezer_mapping_table_t freezer_table = *table_p;
89	assert(freezer_table);
90
91	if (all) {
92		do {
93			default_freezer_mapping_table_t next = freezer_table->next;
94			kfree(freezer_table, sizeof(*freezer_table));
95			freezer_table = next;
96		} while (freezer_table);
97	} else {
98		kfree(freezer_table, sizeof(*freezer_table));
99	}
100}
101
102kern_return_t
103default_freezer_mapping_store(
104		default_freezer_mapping_table_t table,
105		memory_object_offset_t table_offset,
106		memory_object_t memory_object,
107		memory_object_offset_t offset)
108{
109	default_freezer_mapping_table_entry_t entry;
110	uint32_t index;
111
112	assert(table);
113
114	while (table->next) {
115		table = table->next;
116	}
117
118	if (table->index >= MAX_FREEZE_TABLE_ENTRIES) {
119		vm_object_t compact_object = table->object;
120		default_freezer_mapping_table_t next;
121
122		next = default_freezer_mapping_create(compact_object, table_offset);
123		if (!next) {
124			return KERN_FAILURE;
125		}
126		table->next = next;
127	}
128
129	index = (table)->index++;
130	entry = &(table)->entry[index];
131
132	entry->memory_object = memory_object;
133	entry->offset = offset;
134
135	return KERN_SUCCESS;
136}
137
138kern_return_t
139default_freezer_mapping_update(
140		default_freezer_mapping_table_t table,
141		memory_object_t memory_object,
142		memory_object_offset_t offset,
143		memory_object_offset_t *table_offset, /*OUT: contains the offset into the compact object*/
144		boolean_t remove_entry)
145{
146
147	kern_return_t kr = KERN_SUCCESS;
148	vm_object_offset_t compact_offset;
149	default_freezer_mapping_table_entry_t entry;
150	uint32_t index = 0;
151
152	if (table == NULL){
153		return KERN_FAILURE;
154	}
155
156	compact_offset = table->offset;
157
158	while (1) {
159		if (index >= table->index) {
160			if (table->next) {
161				table = table->next;
162				index = 0;
163			} else {
164				/* End of tables and we didn't find our candidate entry */
165				kr = KERN_FAILURE;
166				break;
167			}
168		}
169
170		entry = &table->entry[index];
171
172		if (memory_object == entry->memory_object && offset == entry->offset) {
173			if (remove_entry == TRUE) {
174				/*
175				 * Mark the page absent whilst retaining the object
176				 * for cleanup during thaw.
177				 */
178				entry->offset = FREEZER_OFFSET_ABSENT;
179			}
180			if (table_offset != NULL) {
181				*table_offset = compact_offset;
182			}
183			break;
184		}
185
186		index++;
187		compact_offset += PAGE_SIZE;
188	}
189	return kr;
190}
191
192
193
194/*
195 * Create a freezer memory object for this
196 * vm object. This will be one of the vm
197 * objects that will pack the compact object.
198 */
199void
200default_freezer_memory_object_create(
201			vm_object_t	object,
202			default_freezer_handle_t df_handle)
203{
204
205	default_freezer_memory_object_t fo = NULL;
206
207	fo = kalloc(sizeof(struct default_freezer_memory_object));
208
209	if (fo) {
210		memory_object_control_t control = NULL;
211
212		memset(fo, 0, sizeof(*fo));
213
214		control = memory_object_control_allocate(object);
215		assert (control != MEMORY_OBJECT_CONTROL_NULL);
216
217		df_memory_object_init((memory_object_t)fo, control, 0);
218		fo->fo_df_handle = df_handle;
219
220		default_freezer_handle_reference_locked(fo->fo_df_handle);
221
222		object->pager = (memory_object_t)fo;
223		object->pager_created = TRUE;
224		object->pager_initialized = TRUE;
225		object->pager_ready = TRUE;
226		object->pager_trusted = TRUE;
227		object->pager_control = control;
228	} else {
229		panic(" Could not allocate freezer object\n");
230	}
231}
232
233kern_return_t
234default_freezer_pack(
235	unsigned int	*purgeable_count,
236	unsigned int	*wired_count,
237	unsigned int	*clean_count,
238	unsigned int	*dirty_count,
239	unsigned int	dirty_budget,
240	boolean_t	*shared,
241	vm_object_t	src_object,
242	default_freezer_handle_t df_handle)
243{
244	kern_return_t			kr = KERN_SUCCESS;
245
246	if (df_handle) {
247		default_freezer_handle_lock(df_handle);
248	}
249
250	kr = vm_object_pack(purgeable_count, wired_count, clean_count, dirty_count, dirty_budget, shared, src_object, df_handle);
251
252	if (df_handle) {
253		default_freezer_handle_unlock(df_handle);
254	}
255
256	return kr;
257}
258
259/*
260 * Called with freezer_handle locked.
261 * default_freezer_pack locks the handle, calls
262 * vm_object_pack which, in turn, will call
263 * default_freezer_pack_page().
264 */
265void
266default_freezer_pack_page(
267		vm_page_t p,
268		default_freezer_handle_t df_handle)
269{
270
271	default_freezer_mapping_table_t freeze_table = NULL;
272	memory_object_t 		memory_object = NULL;
273	vm_object_t			compact_object =  VM_OBJECT_NULL;
274
275	assert(df_handle);
276
277	compact_object = df_handle->dfh_compact_object;
278
279	assert(compact_object);
280
281	freeze_table =  df_handle->dfh_table;
282	memory_object = p->object->pager;
283
284	if (memory_object == NULL) {
285		default_freezer_memory_object_create(p->object, df_handle);
286		memory_object = p->object->pager;
287	} else {
288		assert(df_handle == ((default_freezer_memory_object_t)memory_object)->fo_df_handle);
289	}
290
291	vm_object_lock(compact_object);
292	default_freezer_mapping_store(freeze_table, df_handle->dfh_compact_offset, memory_object, p->offset + p->object->paging_offset);
293	vm_page_rename(p, compact_object, df_handle->dfh_compact_offset, FALSE);
294	vm_object_unlock(compact_object);
295
296	df_handle->dfh_compact_offset += PAGE_SIZE;
297}
298
299void
300default_freezer_unpack(
301		 default_freezer_handle_t df_handle)
302{
303
304	vm_page_t 				compact_page = VM_PAGE_NULL, src_page = VM_PAGE_NULL;
305	uint32_t 				index = 0;
306	vm_object_t 				src_object = VM_OBJECT_NULL;
307	vm_object_t				compact_object = VM_OBJECT_NULL;
308	memory_object_t				src_mem_object = MEMORY_OBJECT_NULL;
309	memory_object_offset_t			src_offset = 0;
310	vm_object_offset_t			compact_offset = 0;
311	default_freezer_memory_object_t		fo = NULL;
312	default_freezer_mapping_table_t 	freeze_table = NULL;
313	boolean_t				should_unlock_handle = FALSE;
314
315	assert(df_handle);
316
317	default_freezer_handle_lock(df_handle);
318	should_unlock_handle = TRUE;
319
320	freeze_table = df_handle->dfh_table;
321	compact_object = df_handle->dfh_compact_object;
322
323	assert(compact_object);
324	assert(compact_object->alive);
325	assert(!compact_object->terminating);
326	assert(compact_object->pager_ready);
327
328	/* Bring the pages back in */
329	if (vm_object_pagein(compact_object) != KERN_SUCCESS) {
330		if (should_unlock_handle) {
331			default_freezer_handle_unlock(df_handle);
332		}
333        	return;
334	}
335
336	vm_object_lock(compact_object);
337
338	for (index = 0, compact_offset = 0; ; index++, compact_offset += PAGE_SIZE){
339		if (index >= freeze_table->index) {
340			default_freezer_mapping_table_t table_next;
341
342			table_next = freeze_table->next;
343
344			/* Free the tables as we go along */
345			default_freezer_mapping_free(&freeze_table, FALSE);
346
347			if (table_next == NULL){
348				break;
349			}
350
351			freeze_table = table_next;
352			index = 0;
353		}
354
355		/*
356		 * Skip slots that represent deallocated memory objects.
357		 */
358		src_mem_object = freeze_table->entry[index].memory_object;
359		if (src_mem_object == MEMORY_OBJECT_NULL)
360			continue;
361
362		/*
363		 * Skip slots that represent faulted pages.
364		 */
365		src_offset = freeze_table->entry[index].offset;
366		if (src_offset != FREEZER_OFFSET_ABSENT) {
367
368			compact_page = vm_page_lookup(compact_object, compact_offset);
369			assert(compact_page);
370
371			fo = (default_freezer_memory_object_t)src_mem_object;
372
373			src_object = memory_object_control_to_vm_object(fo->fo_pager_control);
374
375			/* Move back over from the freeze object to the original */
376			vm_object_lock(src_object);
377			src_page = vm_page_lookup(src_object, src_offset - src_object->paging_offset);
378			if (src_page != VM_PAGE_NULL){
379				/*
380				 * We might be racing with a VM fault.
381				 * So handle that gracefully.
382				 */
383				assert(src_page->absent == TRUE);
384				VM_PAGE_FREE(src_page);
385			}
386			vm_page_rename(compact_page, src_object, src_offset - src_object->paging_offset, FALSE);
387			vm_object_unlock(src_object);
388		}
389
390	}
391
392	vm_object_unlock(compact_object);
393
394	vm_object_deallocate(compact_object);
395
396	if (should_unlock_handle) {
397		df_handle->dfh_table = NULL;
398		df_handle->dfh_compact_object = VM_OBJECT_NULL;
399		df_handle->dfh_compact_offset = 0;
400		default_freezer_handle_unlock(df_handle);
401	}
402}
403
404void
405df_memory_object_reference(__unused memory_object_t mem_obj)
406{
407
408	/* No-op */
409}
410
411void
412df_memory_object_deallocate(memory_object_t mem_obj)
413{
414
415	default_freezer_memory_object_t	fo = (default_freezer_memory_object_t)mem_obj;
416
417	assert(fo);
418
419	if (fo->fo_df_handle != NULL) {
420
421		default_freezer_mapping_table_t table = NULL;
422		default_freezer_mapping_table_entry_t entry;
423		boolean_t found = FALSE;
424		uint32_t index = 0;
425		vm_object_t compact_object = VM_OBJECT_NULL;
426
427		default_freezer_handle_lock(fo->fo_df_handle);
428
429		compact_object =  fo->fo_df_handle->dfh_compact_object;
430		table = fo->fo_df_handle->dfh_table;
431
432		if (compact_object == VM_OBJECT_NULL || table == NULL) {
433			/*Nothing to do. A thaw must have cleared it all out.*/
434		} else {
435			vm_object_lock(compact_object);
436
437			/* Remove from table */
438			while (1) {
439				if (index >= table->index) {
440					if (table->next) {
441						table = table->next;
442						index = 0;
443					} else {
444						/* End of tables */
445						break;
446					}
447				}
448
449				entry = &table->entry[index];
450				if (mem_obj == entry->memory_object) {
451					/* It matches, so clear the entry */
452					if (!found) {
453						found = TRUE;
454					}
455					entry->memory_object = MEMORY_OBJECT_NULL;
456					entry->offset = 0;
457				} else if (MEMORY_OBJECT_NULL != entry->memory_object) {
458					/* We have a different valid object; we're done */
459					if (found) {
460						break;
461					}
462				}
463
464				index++;
465			}
466
467			vm_object_unlock(compact_object);
468		}
469
470		if (default_freezer_handle_deallocate_locked(fo->fo_df_handle)) {
471			default_freezer_handle_unlock(fo->fo_df_handle);
472		}
473	}
474
475	kfree(fo, sizeof(*fo));
476}
477
478kern_return_t
479df_memory_object_init(
480		memory_object_t mem_obj,
481		memory_object_control_t control,
482		__unused memory_object_cluster_size_t pager_page_size)
483{
484
485	default_freezer_memory_object_t	fo = (default_freezer_memory_object_t)mem_obj;
486	assert(fo);
487
488	fo->fo_pager_ops = &default_freezer_ops;
489	fo->fo_pager_header.io_bits = IKOT_MEMORY_OBJECT;
490	fo->fo_pager_control = control;
491
492	return KERN_SUCCESS;
493}
494
495kern_return_t
496df_memory_object_terminate(memory_object_t mem_obj)
497{
498
499	default_freezer_memory_object_t	fo = (default_freezer_memory_object_t)mem_obj;
500	assert(fo);
501	memory_object_control_deallocate(fo->fo_pager_control);
502	return KERN_SUCCESS;
503}
504
505
506kern_return_t
507df_memory_object_data_request(
508		memory_object_t mem_obj,
509		memory_object_offset_t offset,
510		memory_object_cluster_size_t length,
511		vm_prot_t protection_required,
512		memory_object_fault_info_t fault_info)
513{
514
515	vm_object_t	src_object = VM_OBJECT_NULL, compact_object = VM_OBJECT_NULL;
516	memory_object_offset_t	compact_offset = 0;
517	memory_object_t pager = NULL;
518	kern_return_t kr = KERN_SUCCESS;
519	boolean_t	drop_object_ref = FALSE;
520
521	default_freezer_memory_object_t fo = (default_freezer_memory_object_t)mem_obj;
522	default_freezer_handle_t	df_handle = NULL;
523
524	df_handle = fo->fo_df_handle;
525
526	if (df_handle == NULL) {
527		kr = KERN_FAILURE;
528	} else {
529		default_freezer_handle_lock(df_handle);
530
531		src_object = memory_object_control_to_vm_object(fo->fo_pager_control);
532		compact_object = fo->fo_df_handle->dfh_compact_object;
533
534		if (compact_object == NULL) {
535			kr = KERN_FAILURE;
536		} else {
537			vm_object_lock(compact_object);
538			vm_object_reference_locked(compact_object);
539			drop_object_ref = TRUE;
540
541			kr = default_freezer_mapping_update(fo->fo_df_handle->dfh_table,
542								mem_obj,
543								offset,
544								&compact_offset,
545								FALSE);
546			vm_object_unlock(compact_object);
547		}
548		default_freezer_handle_unlock(df_handle);
549	}
550
551
552	if (length == 0){
553		/*Caller is just querying to see if we have the page*/
554		if (drop_object_ref) {
555			vm_object_deallocate(compact_object);
556		}
557		return kr;
558	}
559
560	if (kr != KERN_SUCCESS){
561
562		unsigned int request_flags;
563		upl_t        upl;
564		unsigned int page_list_count = 0;
565
566		request_flags = UPL_NO_SYNC | UPL_RET_ONLY_ABSENT | UPL_SET_LITE;
567		/*
568		 * Should we decide to activate USE_PRECIOUS (from default_pager_internal.h)
569		 * here, then the request_flags will need to add these to the ones above:
570		 *
571		 * request_flags |= UPL_PRECIOUS | UPL_CLEAN_IN_PLACE
572		 */
573		request_flags |= UPL_REQUEST_SET_DIRTY;
574
575		memory_object_super_upl_request(fo->fo_pager_control,
576						(memory_object_offset_t)offset,
577						PAGE_SIZE, PAGE_SIZE,
578						&upl, NULL, &page_list_count,
579						request_flags);
580		upl_range_needed(upl, 0, 1);
581
582		upl_abort(upl, UPL_ABORT_UNAVAILABLE);
583		upl_deallocate(upl);
584
585		if (drop_object_ref) {
586			vm_object_deallocate(compact_object);
587		}
588
589		return KERN_SUCCESS;
590	}
591
592	assert(compact_object->alive);
593	assert(!compact_object->terminating);
594	assert(compact_object->pager_ready);
595
596	vm_object_lock(compact_object);
597
598	vm_object_paging_wait(compact_object, THREAD_UNINT);
599	vm_object_paging_begin(compact_object);
600
601	compact_object->blocked_access = TRUE;
602	pager = (memory_object_t)compact_object->pager;
603
604	vm_object_unlock(compact_object);
605
606	((vm_object_fault_info_t) fault_info)->io_sync = TRUE;
607
608	/*
609	 * We have a reference on both the default_freezer
610	 * memory object handle and the compact object.
611	 */
612	kr = dp_memory_object_data_request(pager,
613					compact_offset,
614					length,
615					protection_required,
616					fault_info);
617	if (kr == KERN_SUCCESS){
618
619		vm_page_t compact_page = VM_PAGE_NULL, dst_page = VM_PAGE_NULL;
620
621		vm_object_lock(compact_object);
622
623		compact_object->blocked_access = FALSE;
624		vm_object_paging_end(compact_object);
625
626		vm_object_lock(src_object);
627
628		if ((compact_page = vm_page_lookup(compact_object, compact_offset)) != VM_PAGE_NULL){
629
630			dst_page = vm_page_lookup(src_object, offset - src_object->paging_offset);
631
632			if (!dst_page->absent){
633				/*
634				 * Someone raced us here and unpacked
635				 * the object behind us.
636				 * So cleanup before we return.
637				 */
638				VM_PAGE_FREE(compact_page);
639			} else {
640				VM_PAGE_FREE(dst_page);
641				vm_page_rename(compact_page, src_object, offset - src_object->paging_offset, FALSE);
642
643				if (default_freezer_mapping_update(fo->fo_df_handle->dfh_table,
644								mem_obj,
645								offset,
646								NULL,
647								TRUE) != KERN_SUCCESS) {
648					printf("Page for object: 0x%lx at offset: 0x%lx not found in table\n", (uintptr_t)src_object, (uintptr_t)offset);
649				}
650
651				PAGE_WAKEUP_DONE(compact_page);
652			}
653		} else {
654			printf("%d: default_freezer: compact_object doesn't have the page for object 0x%lx at offset 0x%lx \n", kr, (uintptr_t)compact_object, (uintptr_t)compact_offset);
655			kr = KERN_SUCCESS;
656		}
657		vm_object_unlock(src_object);
658		vm_object_unlock(compact_object);
659		vm_object_deallocate(compact_object);
660	} else {
661		panic("%d: default_freezer TOC pointed us to default_pager incorrectly\n", kr);
662	}
663
664	return kr;
665}
666
667kern_return_t
668df_memory_object_data_return(
669		__unused memory_object_t		mem_obj,
670		__unused memory_object_offset_t	offset,
671		__unused memory_object_cluster_size_t			size,
672		__unused memory_object_offset_t	*resid_offset,
673		__unused int		*io_error,
674		__unused boolean_t	dirty,
675		__unused boolean_t	kernel_copy,
676		__unused int	upl_flags)
677{
678
679	panic(" default_freezer: df_memory_object_data_return should not be called\n");
680	return KERN_SUCCESS;
681}
682
683kern_return_t
684df_memory_object_data_initialize(
685		__unused memory_object_t mem_obj,
686		__unused  memory_object_offset_t offset,
687		__unused memory_object_cluster_size_t size)
688{
689
690	panic(" default_freezer: df_memory_object_data_initialize should not be called\n");
691	return KERN_SUCCESS;
692}
693
694kern_return_t
695df_memory_object_data_unlock(
696		__unused memory_object_t mem_obj,
697		__unused memory_object_offset_t offset,
698		__unused memory_object_size_t length,
699		__unused vm_prot_t prot)
700{
701
702	panic(" default_freezer: df_memory_object_data_unlock should not be called\n");
703	return KERN_FAILURE;
704}
705
706kern_return_t
707df_memory_object_synchronize(
708		__unused memory_object_t mem_obj,
709		__unused memory_object_offset_t offset,
710		__unused memory_object_size_t length,
711		__unused vm_sync_t flags)
712{
713
714	panic(" default_freezer: df_memory_object_synchronize should not be called\n");
715	return KERN_FAILURE;
716}
717
718kern_return_t
719df_memory_object_map(
720		__unused memory_object_t mem_obj,
721		__unused vm_prot_t prot)
722{
723
724	panic(" default_freezer: df_memory_object_map should not be called\n");
725	return KERN_FAILURE;
726}
727
728kern_return_t
729df_memory_object_last_unmap(__unused memory_object_t mem_obj)
730{
731
732	panic(" default_freezer: df_memory_object_last_unmap should not be called\n");
733	return KERN_FAILURE;
734}
735
736
737kern_return_t
738df_memory_object_data_reclaim(
739		__unused memory_object_t mem_obj,
740		__unused boolean_t reclaim_backing_store)
741{
742
743	panic("df_memory_object_data_reclaim\n");
744	return KERN_SUCCESS;
745}
746
747
748/*
749 * The freezer handle is used to make sure that
750 * we don't race against the lookup and termination
751 * of the compact object.
752 */
753
754void
755default_freezer_handle_lock(default_freezer_handle_t df_handle) {
756	lck_rw_lock_exclusive(&df_handle->dfh_lck);
757}
758
759void
760default_freezer_handle_unlock(default_freezer_handle_t df_handle) {
761	lck_rw_done(&df_handle->dfh_lck);
762}
763
764default_freezer_handle_t
765default_freezer_handle_allocate(void)
766{
767
768	default_freezer_handle_t		df_handle = NULL;
769	df_handle = kalloc(sizeof(struct default_freezer_handle));
770
771	if (df_handle) {
772		memset(df_handle, 0, sizeof(struct default_freezer_handle));
773		lck_rw_init(&df_handle->dfh_lck, &default_freezer_handle_lck_grp, NULL);
774		/* No one knows of this handle yet so no need to lock it. */
775		default_freezer_handle_reference_locked(df_handle);
776	} else {
777		panic("Failed to allocated default_freezer_handle structure\n");
778	}
779	return df_handle;
780}
781
782kern_return_t
783default_freezer_handle_init(
784	default_freezer_handle_t df_handle)
785{
786	kern_return_t				kr = KERN_SUCCESS;
787	vm_object_t				compact_object = VM_OBJECT_NULL;
788
789	if (df_handle == NULL || df_handle->dfh_table != NULL) {
790		kr = KERN_FAILURE;
791	} else {
792		/* Create our compact object */
793		compact_object = vm_object_allocate((vm_map_offset_t)(VM_MAX_ADDRESS) - (vm_map_offset_t)(VM_MIN_ADDRESS));
794		if (!compact_object) {
795			kr = KERN_FAILURE;
796		} else {
797			df_handle->dfh_compact_object = compact_object;
798			df_handle->dfh_compact_offset = 0;
799			df_handle->dfh_table = default_freezer_mapping_create(df_handle->dfh_compact_object, df_handle->dfh_compact_offset);
800			if (!df_handle->dfh_table) {
801				kr = KERN_FAILURE;
802			}
803		}
804	}
805
806	return kr;
807}
808
809void
810default_freezer_handle_reference_locked(
811	default_freezer_handle_t df_handle)
812{
813	assert(df_handle);
814	df_handle->dfh_ref_count++;
815}
816
817void
818default_freezer_handle_deallocate(
819	default_freezer_handle_t df_handle)
820{
821	assert(df_handle);
822	default_freezer_handle_lock(df_handle);
823	if (default_freezer_handle_deallocate_locked(df_handle)) {
824		default_freezer_handle_unlock(df_handle);
825	}
826}
827
828boolean_t
829default_freezer_handle_deallocate_locked(
830	default_freezer_handle_t df_handle)
831{
832	boolean_t	should_unlock = TRUE;
833
834	assert(df_handle);
835	df_handle->dfh_ref_count--;
836	if (df_handle->dfh_ref_count == 0) {
837		lck_rw_destroy(&df_handle->dfh_lck, &default_freezer_handle_lck_grp);
838		kfree(df_handle, sizeof(struct default_freezer_handle));
839		should_unlock = FALSE;
840	}
841	return should_unlock;
842}
843
844void
845default_freezer_pageout(
846	default_freezer_handle_t df_handle)
847{
848	assert(df_handle);
849
850	vm_object_pageout(df_handle->dfh_compact_object);
851}
852
853#endif /* CONFIG_FREEZE */
854