+
+unsigned int
+vm_compressor_pager_reap_pages(
+ memory_object_t mem_obj,
+ int flags)
+{
+ compressor_pager_t pager;
+ int num_chunks;
+ int failures;
+ int i;
+ compressor_slot_t *chunk;
+ unsigned int num_slots_freed;
+
+ compressor_pager_lookup(mem_obj, pager);
+ if (pager == NULL)
+ return 0;
+
+ compressor_pager_lock(pager);
+
+ /* reap the compressor slots */
+ num_slots_freed = 0;
+
+ num_chunks = (pager->cpgr_num_slots + COMPRESSOR_SLOTS_PER_CHUNK -1) / COMPRESSOR_SLOTS_PER_CHUNK;
+ if (num_chunks > 1) {
+ /* we have an array of chunks */
+ for (i = 0; i < num_chunks; i++) {
+ chunk = pager->cpgr_slots.cpgr_islots[i];
+ if (chunk != NULL) {
+ num_slots_freed +=
+ compressor_pager_slots_chunk_free(
+ chunk,
+ COMPRESSOR_SLOTS_PER_CHUNK,
+ flags,
+ &failures);
+ if (failures == 0) {
+ pager->cpgr_slots.cpgr_islots[i] = NULL;
+ kfree(chunk, COMPRESSOR_SLOTS_CHUNK_SIZE);
+ }
+ }
+ }
+ } else if (pager->cpgr_num_slots > 2) {
+ chunk = pager->cpgr_slots.cpgr_dslots;
+ num_slots_freed +=
+ compressor_pager_slots_chunk_free(
+ chunk,
+ pager->cpgr_num_slots,
+ flags,
+ NULL);
+ } else {
+ chunk = &pager->cpgr_slots.cpgr_eslots[0];
+ num_slots_freed +=
+ compressor_pager_slots_chunk_free(
+ chunk,
+ pager->cpgr_num_slots,
+ flags,
+ NULL);
+ }
+
+ compressor_pager_unlock(pager);
+
+ return num_slots_freed;
+}
+
+void
+vm_compressor_pager_transfer(
+ memory_object_t dst_mem_obj,
+ memory_object_offset_t dst_offset,
+ memory_object_t src_mem_obj,
+ memory_object_offset_t src_offset)
+{
+ compressor_pager_t src_pager, dst_pager;
+ compressor_slot_t *src_slot_p, *dst_slot_p;
+
+ compressor_pager_stats.transfer++;
+
+ /* find the compressor slot for the destination */
+ assert((uint32_t) dst_offset == dst_offset);
+ compressor_pager_lookup(dst_mem_obj, dst_pager);
+ assert(dst_offset / PAGE_SIZE <= dst_pager->cpgr_num_slots);
+ compressor_pager_slot_lookup(dst_pager, TRUE, (uint32_t) dst_offset,
+ &dst_slot_p);
+ assert(dst_slot_p != NULL);
+ assert(*dst_slot_p == 0);
+
+ /* find the compressor slot for the source */
+ assert((uint32_t) src_offset == src_offset);
+ compressor_pager_lookup(src_mem_obj, src_pager);
+ assert(src_offset / PAGE_SIZE <= src_pager->cpgr_num_slots);
+ compressor_pager_slot_lookup(src_pager, FALSE, (uint32_t) src_offset,
+ &src_slot_p);
+ assert(src_slot_p != NULL);
+ assert(*src_slot_p != 0);
+
+ /* transfer the slot from source to destination */
+ vm_compressor_transfer(dst_slot_p, src_slot_p);
+ OSAddAtomic(-1, &src_pager->cpgr_num_slots_occupied);
+ OSAddAtomic(+1, &dst_pager->cpgr_num_slots_occupied);
+}
+
+memory_object_offset_t
+vm_compressor_pager_next_compressed(
+ memory_object_t mem_obj,
+ memory_object_offset_t offset)
+{
+ compressor_pager_t pager;
+ uint32_t num_chunks;
+ uint32_t page_num;
+ uint32_t chunk_idx;
+ uint32_t slot_idx;
+ compressor_slot_t *chunk;
+
+ compressor_pager_lookup(mem_obj, pager);
+
+ page_num = (uint32_t)(offset / PAGE_SIZE);
+ if (page_num != (offset/PAGE_SIZE)) {
+ /* overflow */
+ return (memory_object_offset_t) -1;
+ }
+ if (page_num > pager->cpgr_num_slots) {
+ /* out of range */
+ return (memory_object_offset_t) -1;
+ }
+
+ num_chunks = ((pager->cpgr_num_slots + COMPRESSOR_SLOTS_PER_CHUNK - 1) /
+ COMPRESSOR_SLOTS_PER_CHUNK);
+
+ if (num_chunks == 1) {
+ if (pager->cpgr_num_slots > 2) {
+ chunk = pager->cpgr_slots.cpgr_dslots;
+ } else {
+ chunk = &pager->cpgr_slots.cpgr_eslots[0];
+ }
+ for (slot_idx = page_num;
+ slot_idx < pager->cpgr_num_slots;
+ slot_idx++) {
+ if (chunk[slot_idx] != 0) {
+ /* found a non-NULL slot in this chunk */
+ return (memory_object_offset_t) (slot_idx *
+ PAGE_SIZE);
+ }
+ }
+ return (memory_object_offset_t) -1;
+ }
+
+ /* we have an array of chunks; find the next non-NULL chunk */
+ chunk = NULL;
+ for (chunk_idx = page_num / COMPRESSOR_SLOTS_PER_CHUNK,
+ slot_idx = page_num % COMPRESSOR_SLOTS_PER_CHUNK;
+ chunk_idx < num_chunks;
+ chunk_idx++,
+ slot_idx = 0) {
+ chunk = pager->cpgr_slots.cpgr_islots[chunk_idx];
+ if (chunk == NULL) {
+ /* no chunk here: try the next one */
+ continue;
+ }
+ /* search for an occupied slot in this chunk */
+ for (;
+ slot_idx < COMPRESSOR_SLOTS_PER_CHUNK;
+ slot_idx++) {
+ if (chunk[slot_idx] != 0) {
+ /* found an occupied slot in this chunk */
+ uint32_t next_slot;
+
+ next_slot = ((chunk_idx *
+ COMPRESSOR_SLOTS_PER_CHUNK) +
+ slot_idx);
+ if (next_slot > pager->cpgr_num_slots) {
+ /* went beyond end of object */
+ return (memory_object_offset_t) -1;
+ }
+ return (memory_object_offset_t) (next_slot *
+ PAGE_SIZE);
+ }
+ }
+ }
+ return (memory_object_offset_t) -1;
+}
+
+unsigned int
+vm_compressor_pager_get_count(
+ memory_object_t mem_obj)
+{
+ compressor_pager_t pager;
+
+ compressor_pager_lookup(mem_obj, pager);
+ if (pager == NULL)
+ return 0;
+
+ /*
+ * The caller should have the VM object locked and one
+ * needs that lock to do a page-in or page-out, so no
+ * need to lock the pager here.
+ */
+ assert(pager->cpgr_num_slots_occupied >= 0);
+
+ return pager->cpgr_num_slots_occupied;
+}
+
+void
+vm_compressor_pager_count(
+ memory_object_t mem_obj,
+ int compressed_count_delta,
+ boolean_t shared_lock,
+ vm_object_t object __unused)
+{
+ compressor_pager_t pager;
+
+ if (compressed_count_delta == 0) {
+ return;
+ }
+
+ compressor_pager_lookup(mem_obj, pager);
+ if (pager == NULL)
+ return;
+
+ if (compressed_count_delta < 0) {
+ assert(pager->cpgr_num_slots_occupied >=
+ (unsigned int) -compressed_count_delta);
+ }
+
+ /*
+ * The caller should have the VM object locked,
+ * shared or exclusive.
+ */
+ if (shared_lock) {
+ vm_object_lock_assert_shared(object);
+ OSAddAtomic(compressed_count_delta,
+ &pager->cpgr_num_slots_occupied);
+ } else {
+ vm_object_lock_assert_exclusive(object);
+ pager->cpgr_num_slots_occupied += compressed_count_delta;
+ }
+}
+
+#if CONFIG_FREEZE
+kern_return_t
+vm_compressor_pager_relocate(
+ memory_object_t mem_obj,
+ memory_object_offset_t offset,
+ void **current_chead)
+{
+ /*
+ * Has the page at this offset been compressed?
+ */
+
+ compressor_slot_t *slot_p;
+ compressor_pager_t dst_pager;
+
+ assert(mem_obj);
+
+ compressor_pager_lookup(mem_obj, dst_pager);
+ if (dst_pager == NULL)
+ return KERN_FAILURE;
+
+ compressor_pager_slot_lookup(dst_pager, FALSE, offset, &slot_p);
+ return (vm_compressor_relocate(current_chead, slot_p));
+}
+#endif /* CONFIG_FREEZE */
+