]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/kern/decmpfs.c
xnu-6153.121.1.tar.gz
[apple/xnu.git] / bsd / kern / decmpfs.c
index ef8057a4e238330d1fb2896e75602d6e4e2fc46a..fd532f1007667f78707cc61881c593004bd0fa64 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (c) 2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2008-2018 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
- * 
+ *
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
  * unlawful or unlicensed copies of an Apple operating system, or to
  * circumvent, violate, or enable the circumvention or violation of, any
  * terms of an Apple operating system software license agreement.
- * 
+ *
  * Please obtain a copy of the License at
  * http://www.opensource.apple.com/apsl/ and read it before using this file.
- * 
+ *
  * The Original Code and all software distributed under the License are
  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  * Please see the License for the specific language governing rights and
  * limitations under the License.
- * 
+ *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
  */
-#if !HFS_COMPRESSION
-/* we need these symbols even though compression is turned off */
-char register_decmpfs_decompressor;
-char unregister_decmpfs_decompressor;
-#else /* HFS_COMPRESSION */
+#if !FS_COMPRESSION
+
+/* We need these symbols even though compression is turned off */
+
+#define UNUSED_SYMBOL(x)        asm(".global _" #x "\n.set _" #x ", 0\n");
+
+UNUSED_SYMBOL(register_decmpfs_decompressor)
+UNUSED_SYMBOL(unregister_decmpfs_decompressor)
+UNUSED_SYMBOL(decmpfs_init)
+UNUSED_SYMBOL(decmpfs_read_compressed)
+UNUSED_SYMBOL(decmpfs_cnode_cmp_type)
+UNUSED_SYMBOL(decmpfs_cnode_get_vnode_state)
+UNUSED_SYMBOL(decmpfs_cnode_get_vnode_cached_size)
+UNUSED_SYMBOL(decmpfs_cnode_get_vnode_cached_nchildren)
+UNUSED_SYMBOL(decmpfs_cnode_get_vnode_cached_total_size)
+UNUSED_SYMBOL(decmpfs_lock_compressed_data)
+UNUSED_SYMBOL(decmpfs_cnode_free)
+UNUSED_SYMBOL(decmpfs_cnode_alloc)
+UNUSED_SYMBOL(decmpfs_cnode_destroy)
+UNUSED_SYMBOL(decmpfs_decompress_file)
+UNUSED_SYMBOL(decmpfs_unlock_compressed_data)
+UNUSED_SYMBOL(decmpfs_cnode_init)
+UNUSED_SYMBOL(decmpfs_cnode_set_vnode_state)
+UNUSED_SYMBOL(decmpfs_hides_xattr)
+UNUSED_SYMBOL(decmpfs_ctx)
+UNUSED_SYMBOL(decmpfs_file_is_compressed)
+UNUSED_SYMBOL(decmpfs_update_attributes)
+UNUSED_SYMBOL(decmpfs_hides_rsrc)
+UNUSED_SYMBOL(decmpfs_pagein_compressed)
+UNUSED_SYMBOL(decmpfs_validate_compressed_file)
+
+#else /* FS_COMPRESSION */
 #include <sys/kernel.h>
 #include <sys/vnode_internal.h>
 #include <sys/file_internal.h>
@@ -43,6 +70,7 @@ char unregister_decmpfs_decompressor;
 #include <sys/decmpfs.h>
 #include <sys/uio_internal.h>
 #include <libkern/OSByteOrder.h>
+#include <libkern/section_keywords.h>
 
 #pragma mark --- debugging ---
 
@@ -53,29 +81,46 @@ char unregister_decmpfs_decompressor;
 static const char *
 baseName(const char *path)
 {
-    if (!path)
-        return NULL;
-    const char *ret = path;
-    int i;
-    for (i = 0; path[i] != 0; i++) {
-        if (path[i] == '/')
-            ret = &path[i + 1];
-    }
-    return ret;
+       if (!path) {
+               return NULL;
+       }
+       const char *ret = path;
+       int i;
+       for (i = 0; path[i] != 0; i++) {
+               if (path[i] == '/') {
+                       ret = &path[i + 1];
+               }
+       }
+       return ret;
+}
+
+static char*
+vnpath(vnode_t vp, char *path, int len)
+{
+       int origlen = len;
+       path[0] = 0;
+       vn_getpath(vp, path, &len);
+       path[origlen - 1] = 0;
+       return path;
 }
 
 #define ErrorLog(x, args...) printf("%s:%d:%s: " x, baseName(__FILE__), __LINE__, __FUNCTION__, ## args)
+#define ErrorLogWithPath(x, args...) do { char *path; MALLOC(path, char *, PATH_MAX, M_TEMP, M_WAITOK); printf("%s:%d:%s: %s: " x, baseName(__FILE__), __LINE__, __FUNCTION__, vnpath(vp, path, PATH_MAX), ## args); FREE(path, M_TEMP); } while(0)
 
 #if COMPRESSION_DEBUG
 #define DebugLog ErrorLog
+#define DebugLogWithPath ErrorLogWithPath
 #else
 #define DebugLog(x...) do { } while(0)
+#define DebugLogWithPath(x...) do { } while(0)
 #endif
 
 #if COMPRESSION_DEBUG_VERBOSE
 #define VerboseLog ErrorLog
+#define VerboseLogWithPath ErrorLogWithPath
 #else
 #define VerboseLog(x...) do { } while(0)
+#define VerboseLogWithPath(x...) do { } while(0)
 #endif
 
 #if MALLOC_DEBUG
@@ -83,71 +128,71 @@ baseName(const char *path)
 static SInt32 totalAlloc;
 
 typedef struct {
-    uint32_t allocSz;
-    uint32_t magic;
-    const char *file;
-    int line;
+       uint32_t allocSz;
+       uint32_t magic;
+       const char *file;
+       int line;
 } allocated;
 
 static void *
 _malloc(uint32_t sz, __unused int type, __unused int flags, const char *file, int line)
 {
-    uint32_t allocSz = sz + 2 * sizeof(allocated);
-    
-    allocated *alloc = NULL;
-    MALLOC(alloc, allocated *, allocSz, type, flags);
-    if (!alloc) {
-        ErrorLog("malloc failed\n");
-        return NULL;
-    }
-    
-    char *ret = (char*)&alloc[1];
-    allocated *alloc2 = (allocated*)(ret + sz);
-       
-    alloc->allocSz = allocSz;
-    alloc->magic = 0xdadadada;
-    alloc->file = file;
-    alloc->line = line;
-    
-    *alloc2 = *alloc;
-    
-    int s = OSAddAtomic(sz, &totalAlloc);
-    ErrorLog("malloc(%d) -> %p, total allocations %d\n", sz, ret, s + sz);
-    
-    return ret;
+       uint32_t allocSz = sz + 2 * sizeof(allocated);
+
+       allocated *alloc = NULL;
+       MALLOC(alloc, allocated *, allocSz, type, flags);
+       if (!alloc) {
+               ErrorLog("malloc failed\n");
+               return NULL;
+       }
+
+       char *ret = (char*)&alloc[1];
+       allocated *alloc2 = (allocated*)(ret + sz);
+
+       alloc->allocSz = allocSz;
+       alloc->magic = 0xdadadada;
+       alloc->file = file;
+       alloc->line = line;
+
+       *alloc2 = *alloc;
+
+       int s = OSAddAtomic(sz, &totalAlloc);
+       ErrorLog("malloc(%d) -> %p, total allocations %d\n", sz, ret, s + sz);
+
+       return ret;
 }
 
 static void
 _free(char *ret, __unused int type, const char *file, int line)
 {
-    if (!ret) {
-        ErrorLog("freeing null\n");
-        return;
-    }
-    allocated *alloc = (allocated*)ret;
-    alloc--;
-    uint32_t sz = alloc->allocSz - 2 * sizeof(allocated);
-    allocated *alloc2 = (allocated*)(ret + sz);
-    
-    if (alloc->magic != 0xdadadada) {
-        panic("freeing bad pointer");
-    }
-       
-    if (memcmp(alloc, alloc2, sizeof(*alloc)) != 0) {
-        panic("clobbered data");
-    }
-    
-    memset(ret, 0xce, sz);
-    alloc2->file = file;
-    alloc2->line = line;
-    FREE(alloc, type);
-    int s = OSAddAtomic(-sz, &totalAlloc);
-    ErrorLog("free(%p,%d) -> total allocations %d\n", ret, sz, s - sz);
+       if (!ret) {
+               ErrorLog("freeing null\n");
+               return;
+       }
+       allocated *alloc = (allocated*)ret;
+       alloc--;
+       uint32_t sz = alloc->allocSz - 2 * sizeof(allocated);
+       allocated *alloc2 = (allocated*)(ret + sz);
+
+       if (alloc->magic != 0xdadadada) {
+               panic("freeing bad pointer");
+       }
+
+       if (memcmp(alloc, alloc2, sizeof(*alloc)) != 0) {
+               panic("clobbered data");
+       }
+
+       memset(ret, 0xce, sz);
+       alloc2->file = file;
+       alloc2->line = line;
+       FREE(alloc, type);
+       int s = OSAddAtomic(-sz, &totalAlloc);
+       ErrorLog("free(%p,%d) -> total allocations %d\n", ret, sz, s - sz);
 }
 
 #undef MALLOC
 #undef FREE
-#define        MALLOC(space, cast, size, type, flags) (space) = (cast)_malloc(size, type, flags, __FILE__, __LINE__)
+#define MALLOC(space, cast, size, type, flags) (space) = (cast)_malloc(size, type, flags, __FILE__, __LINE__)
 #define FREE(addr, type) _free((void *)addr, type, __FILE__, __LINE__)
 
 #endif /* MALLOC_DEBUG */
@@ -156,7 +201,7 @@ _free(char *ret, __unused int type, const char *file, int line)
 
 static lck_grp_t *decmpfs_lockgrp;
 
-static decmpfs_registration * decompressors[CMP_MAX]; /* the registered compressors */
+SECURITY_READ_ONLY_EARLY(static decmpfs_registration *) decompressors[CMP_MAX]; /* the registered compressors */
 static lck_rw_t * decompressorsLock;
 static int decompress_channel; /* channel used by decompress_file to wake up waiters */
 static lck_mtx_t *decompress_channel_mtx;
@@ -170,26 +215,28 @@ vfs_context_t decmpfs_ctx;
 static void *
 _func_from_offset(uint32_t type, uintptr_t offset)
 {
-    /* get the function at the given offset in the registration for the given type */
-    decmpfs_registration *reg = decompressors[type];
-    char *regChar = (char*)reg;
-    char *func = &regChar[offset];
-    void **funcPtr = (void**)func;
-
-    switch (reg->decmpfs_registration) {
-        case DECMPFS_REGISTRATION_VERSION_V1:
-            if (offset > offsetof_func(free_data))
-                return NULL;
-            break;
-        case DECMPFS_REGISTRATION_VERSION_V3:
-            if (offset > offsetof_func(get_flags))
-                return NULL;
-            break;
-        default:
-            return NULL;
-    }
-
-    return funcPtr[0];
+       /* get the function at the given offset in the registration for the given type */
+       const decmpfs_registration *reg = decompressors[type];
+       const char *regChar = (const char*)reg;
+       const char *func = &regChar[offset];
+       void * const * funcPtr = (void * const *) func;
+
+       switch (reg->decmpfs_registration) {
+       case DECMPFS_REGISTRATION_VERSION_V1:
+               if (offset > offsetof_func(free_data)) {
+                       return NULL;
+               }
+               break;
+       case DECMPFS_REGISTRATION_VERSION_V3:
+               if (offset > offsetof_func(get_flags)) {
+                       return NULL;
+               }
+               break;
+       default:
+               return NULL;
+       }
+
+       return funcPtr[0];
 }
 
 extern void IOServicePublishResource( const char * property, boolean_t value );
@@ -197,97 +244,102 @@ extern boolean_t IOServiceWaitForMatchingResource( const char * property, uint64
 extern boolean_t IOCatalogueMatchingDriversPresent( const char * property );
 
 static void *
-_decmp_get_func(uint32_t type, uintptr_t offset)
+_decmp_get_func(vnode_t vp, uint32_t type, uintptr_t offset)
 {
        /*
-        this function should be called while holding a shared lock to decompressorsLock,
-        and will return with the lock held
+        *  this function should be called while holding a shared lock to decompressorsLock,
+        *  and will return with the lock held
         */
-       
-       if (type >= CMP_MAX)
+
+       if (type >= CMP_MAX) {
                return NULL;
-       
+       }
+
        if (decompressors[type] != NULL) {
                // the compressor has already registered but the function might be null
                return _func_from_offset(type, offset);
        }
-       
-    // does IOKit know about a kext that is supposed to provide this type?
-    char providesName[80];
-    snprintf(providesName, sizeof(providesName), "com.apple.AppleFSCompression.providesType%u", type);
-    if (IOCatalogueMatchingDriversPresent(providesName)) {
-        // there is a kext that says it will register for this type, so let's wait for it
-        char resourceName[80];
-        uint64_t delay = 10000000ULL; // 10 milliseconds.
-        snprintf(resourceName, sizeof(resourceName), "com.apple.AppleFSCompression.Type%u", type);
-        printf("waiting for %s\n", resourceName);
-        while(decompressors[type] == NULL) {
-            lck_rw_unlock_shared(decompressorsLock); // we have to unlock to allow the kext to register
-            if (IOServiceWaitForMatchingResource(resourceName, delay)) {
-                lck_rw_lock_shared(decompressorsLock);
-                break;
-            }
-            if (!IOCatalogueMatchingDriversPresent(providesName)) {
-                // 
-                printf("the kext with %s is no longer present\n", providesName);
-                lck_rw_lock_shared(decompressorsLock);
-                break;
-            }
-            printf("still waiting for %s\n", resourceName);
-            delay *= 2;
-            lck_rw_lock_shared(decompressorsLock);
-        }
-        // IOKit says the kext is loaded, so it should be registered too!
-        if (decompressors[type] == NULL) {
-            ErrorLog("we found %s, but the type still isn't registered\n", providesName);
-            return NULL;
-        }
-        // it's now registered, so let's return the function
-        return _func_from_offset(type, offset);
-    }
-    
+
+       // does IOKit know about a kext that is supposed to provide this type?
+       char providesName[80];
+       snprintf(providesName, sizeof(providesName), "com.apple.AppleFSCompression.providesType%u", type);
+       if (IOCatalogueMatchingDriversPresent(providesName)) {
+               // there is a kext that says it will register for this type, so let's wait for it
+               char resourceName[80];
+               uint64_t delay = 10000000ULL; // 10 milliseconds.
+               snprintf(resourceName, sizeof(resourceName), "com.apple.AppleFSCompression.Type%u", type);
+               ErrorLogWithPath("waiting for %s\n", resourceName);
+               while (decompressors[type] == NULL) {
+                       lck_rw_unlock_shared(decompressorsLock); // we have to unlock to allow the kext to register
+                       if (IOServiceWaitForMatchingResource(resourceName, delay)) {
+                               lck_rw_lock_shared(decompressorsLock);
+                               break;
+                       }
+                       if (!IOCatalogueMatchingDriversPresent(providesName)) {
+                               //
+                               ErrorLogWithPath("the kext with %s is no longer present\n", providesName);
+                               lck_rw_lock_shared(decompressorsLock);
+                               break;
+                       }
+                       ErrorLogWithPath("still waiting for %s\n", resourceName);
+                       delay *= 2;
+                       lck_rw_lock_shared(decompressorsLock);
+               }
+               // IOKit says the kext is loaded, so it should be registered too!
+               if (decompressors[type] == NULL) {
+                       ErrorLogWithPath("we found %s, but the type still isn't registered\n", providesName);
+                       return NULL;
+               }
+               // it's now registered, so let's return the function
+               return _func_from_offset(type, offset);
+       }
+
        // the compressor hasn't registered, so it never will unless someone manually kextloads it
-       ErrorLog("tried to access a compressed file of unregistered type %d\n", type);
+       ErrorLogWithPath("tried to access a compressed file of unregistered type %d\n", type);
        return NULL;
 }
 
-#define decmp_get_func(type, func) ((typeof(((decmpfs_registration*)NULL)->func))_decmp_get_func(type, offsetof_func(func)))
+#define decmp_get_func(vp, type, func) ((typeof(((decmpfs_registration*)NULL)->func))_decmp_get_func(vp, type, offsetof_func(func)))
 
 #pragma mark --- utilities ---
 
 #if COMPRESSION_DEBUG
-static char*
-vnpath(vnode_t vp, char *path, int len)
-{
-    int origlen = len;
-    path[0] = 0;
-    vn_getpath(vp, path, &len);
-    path[origlen - 1] = 0;
-    return path;
-}
-
 static int
 vnsize(vnode_t vp, uint64_t *size)
 {
-    struct vnode_attr va;
-    VATTR_INIT(&va);
-    VATTR_WANTED(&va, va_data_size);
+       struct vnode_attr va;
+       VATTR_INIT(&va);
+       VATTR_WANTED(&va, va_data_size);
        int error = vnode_getattr(vp, &va, decmpfs_ctx);
-    if (error != 0) {
-        ErrorLog("vnode_getattr err %d\n", error);
-        return error;
-    }
-    *size = va.va_data_size;
-    return 0;
+       if (error != 0) {
+               ErrorLogWithPath("vnode_getattr err %d\n", error);
+               return error;
+       }
+       *size = va.va_data_size;
+       return 0;
 }
 #endif /* COMPRESSION_DEBUG */
 
 #pragma mark --- cnode routines ---
 
+decmpfs_cnode *
+decmpfs_cnode_alloc(void)
+{
+       decmpfs_cnode *dp;
+       MALLOC_ZONE(dp, decmpfs_cnode *, sizeof(decmpfs_cnode), M_DECMPFS_CNODE, M_WAITOK);
+       return dp;
+}
+
+void
+decmpfs_cnode_free(decmpfs_cnode *dp)
+{
+       FREE_ZONE(dp, sizeof(*dp), M_DECMPFS_CNODE);
+}
+
 void
 decmpfs_cnode_init(decmpfs_cnode *cp)
 {
-    memset(cp, 0, sizeof(*cp));
+       memset(cp, 0, sizeof(*cp));
        lck_rw_init(&cp->compressed_data_lock, decmpfs_lockgrp, NULL);
 }
 
@@ -297,16 +349,16 @@ decmpfs_cnode_destroy(decmpfs_cnode *cp)
        lck_rw_destroy(&cp->compressed_data_lock, decmpfs_lockgrp);
 }
 
-boolean_t
+bool
 decmpfs_trylock_compressed_data(decmpfs_cnode *cp, int exclusive)
 {
        void *thread = current_thread();
-       boolean_t retval = FALSE;
+       bool retval = false;
 
        if (cp->lockowner == thread) {
                /* this thread is already holding an exclusive lock, so bump the count */
                cp->lockcount++;
-               retval = TRUE;
+               retval = true;
        } else if (exclusive) {
                if ((retval = lck_rw_try_lock_exclusive(&cp->compressed_data_lock))) {
                        cp->lockowner = thread;
@@ -324,7 +376,7 @@ void
 decmpfs_lock_compressed_data(decmpfs_cnode *cp, int exclusive)
 {
        void *thread = current_thread();
-       
+
        if (cp->lockowner == thread) {
                /* this thread is already holding an exclusive lock, so bump the count */
                cp->lockcount++;
@@ -342,7 +394,7 @@ void
 decmpfs_unlock_compressed_data(decmpfs_cnode *cp, __unused int exclusive)
 {
        void *thread = current_thread();
-       
+
        if (cp->lockowner == thread) {
                /* this thread is holding an exclusive lock, so decrement the count */
                if ((--cp->lockcount) > 0) {
@@ -351,80 +403,136 @@ decmpfs_unlock_compressed_data(decmpfs_cnode *cp, __unused int exclusive)
                }
                cp->lockowner = NULL;
        }
-       
+
        lck_rw_done(&cp->compressed_data_lock);
 }
 
 uint32_t
 decmpfs_cnode_get_vnode_state(decmpfs_cnode *cp)
 {
-    return cp->cmp_state;
+       return cp->cmp_state;
 }
 
 void
 decmpfs_cnode_set_vnode_state(decmpfs_cnode *cp, uint32_t state, int skiplock)
 {
-       if (!skiplock) decmpfs_lock_compressed_data(cp, 1);
+       if (!skiplock) {
+               decmpfs_lock_compressed_data(cp, 1);
+       }
        cp->cmp_state = state;
-    if (state == FILE_TYPE_UNKNOWN) {
-        /* clear out the compression type too */
-        cp->cmp_type = 0;
-    }
-       if (!skiplock) decmpfs_unlock_compressed_data(cp, 1);
+       if (state == FILE_TYPE_UNKNOWN) {
+               /* clear out the compression type too */
+               cp->cmp_type = 0;
+       }
+       if (!skiplock) {
+               decmpfs_unlock_compressed_data(cp, 1);
+       }
 }
 
 static void
 decmpfs_cnode_set_vnode_cmp_type(decmpfs_cnode *cp, uint32_t cmp_type, int skiplock)
 {
-    if (!skiplock) decmpfs_lock_compressed_data(cp, 1);
-    cp->cmp_type = cmp_type;
-    if (!skiplock) decmpfs_unlock_compressed_data(cp, 1);
+       if (!skiplock) {
+               decmpfs_lock_compressed_data(cp, 1);
+       }
+       cp->cmp_type = cmp_type;
+       if (!skiplock) {
+               decmpfs_unlock_compressed_data(cp, 1);
+       }
 }
 
 static void
 decmpfs_cnode_set_vnode_minimal_xattr(decmpfs_cnode *cp, int minimal_xattr, int skiplock)
 {
-    if (!skiplock) decmpfs_lock_compressed_data(cp, 1);
-    cp->cmp_minimal_xattr = minimal_xattr;
-    if (!skiplock) decmpfs_unlock_compressed_data(cp, 1);
+       if (!skiplock) {
+               decmpfs_lock_compressed_data(cp, 1);
+       }
+       cp->cmp_minimal_xattr = minimal_xattr;
+       if (!skiplock) {
+               decmpfs_unlock_compressed_data(cp, 1);
+       }
 }
 
 uint64_t
 decmpfs_cnode_get_vnode_cached_size(decmpfs_cnode *cp)
 {
-    return cp->uncompressed_size;
+       return cp->uncompressed_size;
 }
 
-static void
+uint64_t
+decmpfs_cnode_get_vnode_cached_nchildren(decmpfs_cnode *cp)
+{
+       return cp->nchildren;
+}
+
+uint64_t
+decmpfs_cnode_get_vnode_cached_total_size(decmpfs_cnode *cp)
+{
+       return cp->total_size;
+}
+
+void
 decmpfs_cnode_set_vnode_cached_size(decmpfs_cnode *cp, uint64_t size)
 {
-    while(1) {
-        uint64_t old = cp->uncompressed_size;
-        if (OSCompareAndSwap64(old, size, (UInt64*)&cp->uncompressed_size)) {
-            return;
-        } else {
-            /* failed to write our value, so loop */
-        }
-    }
+       while (1) {
+               uint64_t old = cp->uncompressed_size;
+               if (OSCompareAndSwap64(old, size, (UInt64*)&cp->uncompressed_size)) {
+                       return;
+               } else {
+                       /* failed to write our value, so loop */
+               }
+       }
+}
+
+void
+decmpfs_cnode_set_vnode_cached_nchildren(decmpfs_cnode *cp, uint64_t nchildren)
+{
+       while (1) {
+               uint64_t old = cp->nchildren;
+               if (OSCompareAndSwap64(old, nchildren, (UInt64*)&cp->nchildren)) {
+                       return;
+               } else {
+                       /* failed to write our value, so loop */
+               }
+       }
+}
+
+void
+decmpfs_cnode_set_vnode_cached_total_size(decmpfs_cnode *cp, uint64_t total_sz)
+{
+       while (1) {
+               uint64_t old = cp->total_size;
+               if (OSCompareAndSwap64(old, total_sz, (UInt64*)&cp->total_size)) {
+                       return;
+               } else {
+                       /* failed to write our value, so loop */
+               }
+       }
 }
 
 static uint64_t
 decmpfs_cnode_get_decompression_flags(decmpfs_cnode *cp)
 {
-    return cp->decompression_flags;
+       return cp->decompression_flags;
 }
 
 static void
 decmpfs_cnode_set_decompression_flags(decmpfs_cnode *cp, uint64_t flags)
 {
-    while(1) {
-        uint64_t old = cp->decompression_flags;
-        if (OSCompareAndSwap64(old, flags, (UInt64*)&cp->decompression_flags)) {
-            return;
-        } else {
-            /* failed to write our value, so loop */
-        }
-    }
+       while (1) {
+               uint64_t old = cp->decompression_flags;
+               if (OSCompareAndSwap64(old, flags, (UInt64*)&cp->decompression_flags)) {
+                       return;
+               } else {
+                       /* failed to write our value, so loop */
+               }
+       }
+}
+
+uint32_t
+decmpfs_cnode_cmp_type(decmpfs_cnode *cp)
+{
+       return cp->cmp_type;
 }
 
 #pragma mark --- decmpfs state routines ---
@@ -432,377 +540,466 @@ decmpfs_cnode_set_decompression_flags(decmpfs_cnode *cp, uint64_t flags)
 static int
 decmpfs_fetch_compressed_header(vnode_t vp, decmpfs_cnode *cp, decmpfs_header **hdrOut, int returnInvalid)
 {
-    /*
-     fetches vp's compression xattr, converting it into a decmpfs_header; returns 0 or errno
-     if returnInvalid == 1, returns the header even if the type was invalid (out of range),
-     and return ERANGE in that case
-     */
-    
+       /*
+        *  fetches vp's compression xattr, converting it into a decmpfs_header; returns 0 or errno
+        *  if returnInvalid == 1, returns the header even if the type was invalid (out of range),
+        *  and return ERANGE in that case
+        */
+
        size_t read_size             = 0;
        size_t attr_size             = 0;
-    uio_t attr_uio               = NULL;
-    int err                      = 0;
-    char *data                   = NULL;
-    decmpfs_header *hdr = NULL;
-       char uio_buf[ UIO_SIZEOF(1) ];
-    
-    if ((cp != NULL) &&
-        (cp->cmp_type != 0) &&
-        (cp->cmp_minimal_xattr != 0)) {
-        /* this file's xattr didn't have any extra data when we fetched it, so we can synthesize a header from the data in the cnode */
-        
-        MALLOC(data, char *, sizeof(decmpfs_header), M_TEMP, M_WAITOK);
-        if (!data) {
-            err = ENOMEM;
-            goto out;
-        }
-        hdr = (decmpfs_header*)data;
-        hdr->attr_size = sizeof(decmpfs_disk_header);
-        hdr->compression_magic = DECMPFS_MAGIC;
-        hdr->compression_type  = cp->cmp_type;
-        hdr->uncompressed_size = decmpfs_cnode_get_vnode_cached_size(cp);
-    } else {
-        /* figure out how big the xattr is on disk */
-        err = vn_getxattr(vp, DECMPFS_XATTR_NAME, NULL, &attr_size, XATTR_NOSECURITY, decmpfs_ctx);
-        if (err != 0)
-            goto out;
-        
-        if (attr_size < sizeof(decmpfs_disk_header) || attr_size > MAX_DECMPFS_XATTR_SIZE) {
-            err = EINVAL;
-            goto out;
-        }
-        
-        /* allocation includes space for the extra attr_size field of a compressed_header */
-        MALLOC(data, char *, attr_size + sizeof(hdr->attr_size), M_TEMP, M_WAITOK);
-        if (!data) {
-            err = ENOMEM;
-            goto out;
-        }
-        
-        /* read the xattr into our buffer, skipping over the attr_size field at the beginning */
-        attr_uio = uio_createwithbuffer(1, 0, UIO_SYSSPACE, UIO_READ, &uio_buf[0], sizeof(uio_buf));
-        uio_addiov(attr_uio, CAST_USER_ADDR_T(data + sizeof(hdr->attr_size)), attr_size);
-        
-        err = vn_getxattr(vp, DECMPFS_XATTR_NAME, attr_uio, &read_size, XATTR_NOSECURITY, decmpfs_ctx);
-        if (err != 0)
-            goto out;
-        if (read_size != attr_size) {
-            err = EINVAL;
-            goto out;
-        }
-        hdr = (decmpfs_header*)data;
-        hdr->attr_size = attr_size;
-        /* swap the fields to native endian */
-        hdr->compression_magic = OSSwapLittleToHostInt32(hdr->compression_magic);
-        hdr->compression_type  = OSSwapLittleToHostInt32(hdr->compression_type);
-        hdr->uncompressed_size = OSSwapLittleToHostInt64(hdr->uncompressed_size);
-    }
-    
-    if (hdr->compression_magic != DECMPFS_MAGIC) {
-        ErrorLog("invalid compression_magic 0x%08x, should be 0x%08x\n", hdr->compression_magic, DECMPFS_MAGIC);
-        err = EINVAL;
+       uio_t attr_uio               = NULL;
+       int err                      = 0;
+       char *data                   = NULL;
+       const bool no_additional_data = ((cp != NULL)
+           && (cp->cmp_type != 0)
+           && (cp->cmp_minimal_xattr != 0));
+       char uio_buf[UIO_SIZEOF(1)];
+       decmpfs_header *hdr = NULL;
+
+       /*
+        * Trace the following parameters on entry with event-id 0x03120004
+        *
+        * @vp->v_id:       vnode-id for which to fetch compressed header.
+        * @no_additional_data: If set true then xattr didn't have any extra data.
+        * @returnInvalid:  return the header even though the type is out of range.
+        */
+       DECMPFS_EMIT_TRACE_ENTRY(DECMPDBG_FETCH_COMPRESSED_HEADER, vp->v_id,
+           no_additional_data, returnInvalid);
+
+       if (no_additional_data) {
+               /* this file's xattr didn't have any extra data when we fetched it, so we can synthesize a header from the data in the cnode */
+
+               MALLOC(data, char *, sizeof(decmpfs_header), M_TEMP, M_WAITOK);
+               if (!data) {
+                       err = ENOMEM;
+                       goto out;
+               }
+               hdr = (decmpfs_header*)data;
+               hdr->attr_size = sizeof(decmpfs_disk_header);
+               hdr->compression_magic = DECMPFS_MAGIC;
+               hdr->compression_type  = cp->cmp_type;
+               if (hdr->compression_type == DATALESS_PKG_CMPFS_TYPE) {
+                       if (!vnode_isdir(vp)) {
+                               err = EINVAL;
+                               goto out;
+                       }
+                       hdr->_size.value = DECMPFS_PKG_VALUE_FROM_SIZE_COUNT(
+                               decmpfs_cnode_get_vnode_cached_size(cp),
+                               decmpfs_cnode_get_vnode_cached_nchildren(cp));
+               } else if (vnode_isdir(vp)) {
+                       hdr->_size.value = decmpfs_cnode_get_vnode_cached_nchildren(cp);
+               } else {
+                       hdr->_size.value = decmpfs_cnode_get_vnode_cached_size(cp);
+               }
+       } else {
+               /* figure out how big the xattr is on disk */
+               err = vn_getxattr(vp, DECMPFS_XATTR_NAME, NULL, &attr_size, XATTR_NOSECURITY, decmpfs_ctx);
+               if (err != 0) {
+                       goto out;
+               }
+
+               if (attr_size < sizeof(decmpfs_disk_header) || attr_size > MAX_DECMPFS_XATTR_SIZE) {
+                       err = EINVAL;
+                       goto out;
+               }
+
+               /* allocation includes space for the extra attr_size field of a compressed_header */
+               MALLOC(data, char *, attr_size + sizeof(hdr->attr_size), M_TEMP, M_WAITOK);
+               if (!data) {
+                       err = ENOMEM;
+                       goto out;
+               }
+
+               /* read the xattr into our buffer, skipping over the attr_size field at the beginning */
+               attr_uio = uio_createwithbuffer(1, 0, UIO_SYSSPACE, UIO_READ, &uio_buf[0], sizeof(uio_buf));
+               uio_addiov(attr_uio, CAST_USER_ADDR_T(data + sizeof(hdr->attr_size)), attr_size);
+
+               err = vn_getxattr(vp, DECMPFS_XATTR_NAME, attr_uio, &read_size, XATTR_NOSECURITY, decmpfs_ctx);
+               if (err != 0) {
+                       goto out;
+               }
+               if (read_size != attr_size) {
+                       err = EINVAL;
+                       goto out;
+               }
+               hdr = (decmpfs_header*)data;
+               hdr->attr_size = attr_size;
+               /* swap the fields to native endian */
+               hdr->compression_magic = OSSwapLittleToHostInt32(hdr->compression_magic);
+               hdr->compression_type  = OSSwapLittleToHostInt32(hdr->compression_type);
+               hdr->uncompressed_size = OSSwapLittleToHostInt64(hdr->uncompressed_size);
+       }
+
+       if (hdr->compression_magic != DECMPFS_MAGIC) {
+               ErrorLogWithPath("invalid compression_magic 0x%08x, should be 0x%08x\n", hdr->compression_magic, DECMPFS_MAGIC);
+               err = EINVAL;
                goto out;
-    }
-       
-    if (hdr->compression_type >= CMP_MAX) {
-        if (returnInvalid) {
-            /* return the header even though the type is out of range */
-            err = ERANGE;
-        } else {
-            ErrorLog("compression_type %d out of range\n", hdr->compression_type);
-            err = EINVAL;
-        }
+       }
+
+       /*
+        * Special-case the DATALESS compressor here; that is a valid type,
+        * even through there will never be an entry in the decompressor
+        * handler table for it.  If we don't do this, then the cmp_state
+        * for this cnode will end up being marked NOT_COMPRESSED, and
+        * we'll be stuck in limbo.
+        */
+       if (hdr->compression_type >= CMP_MAX && !decmpfs_type_is_dataless(hdr->compression_type)) {
+               if (returnInvalid) {
+                       /* return the header even though the type is out of range */
+                       err = ERANGE;
+               } else {
+                       ErrorLogWithPath("compression_type %d out of range\n", hdr->compression_type);
+                       err = EINVAL;
+               }
                goto out;
-    }
-       
+       }
+
 out:
-    if (err && (err != ERANGE)) {
-        DebugLog("err %d\n", err);
-        if (data) FREE(data, M_TEMP);
-        *hdrOut = NULL;
-    } else {
-        *hdrOut = hdr;
-    }
-    return err;
+       if (err && (err != ERANGE)) {
+               DebugLogWithPath("err %d\n", err);
+               if (data) {
+                       FREE(data, M_TEMP);
+               }
+               *hdrOut = NULL;
+       } else {
+               *hdrOut = hdr;
+       }
+       /*
+        * Trace the following parameters on return with event-id 0x03120004.
+        *
+        * @vp->v_id:       vnode-id for which to fetch compressed header.
+        * @err:            value returned from this function.
+        */
+       DECMPFS_EMIT_TRACE_RETURN(DECMPDBG_FETCH_COMPRESSED_HEADER, vp->v_id, err);
+       return err;
 }
 
 static int
 decmpfs_fast_get_state(decmpfs_cnode *cp)
 {
-    /*
-     return the cached state
-     this should *only* be called when we know that decmpfs_file_is_compressed has already been called,
-     because this implies that the cached state is valid
-     */
-    int cmp_state = decmpfs_cnode_get_vnode_state(cp);
-       
-    switch(cmp_state) {
-        case FILE_IS_NOT_COMPRESSED:
-        case FILE_IS_COMPRESSED:
-        case FILE_IS_CONVERTING:
-            return cmp_state;
-        case FILE_TYPE_UNKNOWN:
-            /*
-             we should only get here if decmpfs_file_is_compressed was not called earlier on this vnode,
-             which should not be possible
-             */
-            ErrorLog("decmpfs_fast_get_state called on unknown file\n");
-            return FILE_IS_NOT_COMPRESSED;
-        default:
-            /* */
-            ErrorLog("unknown cmp_state %d\n", cmp_state);
-            return FILE_IS_NOT_COMPRESSED;
-    }
+       /*
+        *  return the cached state
+        *  this should *only* be called when we know that decmpfs_file_is_compressed has already been called,
+        *  because this implies that the cached state is valid
+        */
+       int cmp_state = decmpfs_cnode_get_vnode_state(cp);
+
+       switch (cmp_state) {
+       case FILE_IS_NOT_COMPRESSED:
+       case FILE_IS_COMPRESSED:
+       case FILE_IS_CONVERTING:
+               return cmp_state;
+       case FILE_TYPE_UNKNOWN:
+               /*
+                *  we should only get here if decmpfs_file_is_compressed was not called earlier on this vnode,
+                *  which should not be possible
+                */
+               ErrorLog("decmpfs_fast_get_state called on unknown file\n");
+               return FILE_IS_NOT_COMPRESSED;
+       default:
+               /* */
+               ErrorLog("unknown cmp_state %d\n", cmp_state);
+               return FILE_IS_NOT_COMPRESSED;
+       }
 }
 
 static int
 decmpfs_fast_file_is_compressed(decmpfs_cnode *cp)
 {
-    int cmp_state = decmpfs_cnode_get_vnode_state(cp);
-       
-    switch(cmp_state) {
-        case FILE_IS_NOT_COMPRESSED:
-                       return 0;
-        case FILE_IS_COMPRESSED:
-        case FILE_IS_CONVERTING:
-            return 1;
-        case FILE_TYPE_UNKNOWN:
-            /*
-             we should only get here if decmpfs_file_is_compressed was not called earlier on this vnode,
-             which should not be possible
-             */
-            ErrorLog("decmpfs_fast_get_state called on unknown file\n");
-            return 0;
-        default:
-            /* */
-            ErrorLog("unknown cmp_state %d\n", cmp_state);
-            return 0;
-    }
+       int cmp_state = decmpfs_cnode_get_vnode_state(cp);
+
+       switch (cmp_state) {
+       case FILE_IS_NOT_COMPRESSED:
+               return 0;
+       case FILE_IS_COMPRESSED:
+       case FILE_IS_CONVERTING:
+               return 1;
+       case FILE_TYPE_UNKNOWN:
+               /*
+                *  we should only get here if decmpfs_file_is_compressed was not called earlier on this vnode,
+                *  which should not be possible
+                */
+               ErrorLog("decmpfs_fast_get_state called on unknown file\n");
+               return 0;
+       default:
+               /* */
+               ErrorLog("unknown cmp_state %d\n", cmp_state);
+               return 0;
+       }
 }
 
 errno_t
 decmpfs_validate_compressed_file(vnode_t vp, decmpfs_cnode *cp)
 {
-    /* give a compressor a chance to indicate that a compressed file is invalid */
-    
-    decmpfs_header *hdr = NULL;
-    errno_t err = decmpfs_fetch_compressed_header(vp, cp, &hdr, 0);
-    if (err) {
-        /* we couldn't get the header */
-        if (decmpfs_fast_get_state(cp) == FILE_IS_NOT_COMPRESSED) {
-            /* the file is no longer compressed, so return success */
-            err = 0;
-        }
-        goto out;
-    }
-    
-    lck_rw_lock_shared(decompressorsLock);
-    decmpfs_validate_compressed_file_func validate = decmp_get_func(hdr->compression_type, validate);
-    if (validate) {    /* make sure this validation function is valid */
-        /* is the data okay? */
-               err = validate(vp, decmpfs_ctx, hdr);
-    } else if (decmp_get_func(hdr->compression_type, fetch) == NULL) {
-        /* the type isn't registered */
-        err = EIO;
-    } else {
-        /* no validate registered, so nothing to do */
-        err = 0;
-    }
-    lck_rw_unlock_shared(decompressorsLock);
+       /* give a compressor a chance to indicate that a compressed file is invalid */
+
+       decmpfs_header *hdr = NULL;
+       errno_t err = decmpfs_fetch_compressed_header(vp, cp, &hdr, 0);
+       if (err) {
+               /* we couldn't get the header */
+               if (decmpfs_fast_get_state(cp) == FILE_IS_NOT_COMPRESSED) {
+                       /* the file is no longer compressed, so return success */
+                       err = 0;
+               }
+               goto out;
+       }
+
+       if (!decmpfs_type_is_dataless(hdr->compression_type)) {
+               lck_rw_lock_shared(decompressorsLock);
+               decmpfs_validate_compressed_file_func validate = decmp_get_func(vp, hdr->compression_type, validate);
+               if (validate) { /* make sure this validation function is valid */
+                       /* is the data okay? */
+                       err = validate(vp, decmpfs_ctx, hdr);
+               } else if (decmp_get_func(vp, hdr->compression_type, fetch) == NULL) {
+                       /* the type isn't registered */
+                       err = EIO;
+               } else {
+                       /* no validate registered, so nothing to do */
+                       err = 0;
+               }
+               lck_rw_unlock_shared(decompressorsLock);
+       }
 out:
-    if (hdr) FREE(hdr, M_TEMP);
+       if (hdr) {
+               FREE(hdr, M_TEMP);
+       }
 #if COMPRESSION_DEBUG
-    if (err) {
-        DebugLog("decmpfs_validate_compressed_file ret %d, vp->v_flag %d\n", err, vp->v_flag);
-    }
+       if (err) {
+               DebugLogWithPath("decmpfs_validate_compressed_file ret %d, vp->v_flag %d\n", err, vp->v_flag);
+       }
 #endif
-    return err;
+       return err;
 }
 
 int
 decmpfs_file_is_compressed(vnode_t vp, decmpfs_cnode *cp)
 {
-    /*
-     determines whether vp points to a compressed file
-        
-     to speed up this operation, we cache the result in the cnode, and do as little as possible
-     in the case where the cnode already has a valid cached state
-     
-     */
-    
-    int ret = 0;
+       /*
+        *  determines whether vp points to a compressed file
+        *
+        *  to speed up this operation, we cache the result in the cnode, and do as little as possible
+        *  in the case where the cnode already has a valid cached state
+        *
+        */
+
+       int ret = 0;
        int error = 0;
        uint32_t cmp_state;
        struct vnode_attr va_fetch;
-    decmpfs_header *hdr = NULL;
-    mount_t mp = NULL;
+       decmpfs_header *hdr = NULL;
+       mount_t mp = NULL;
        int cnode_locked = 0;
-    int saveInvalid = 0; // save the header data even though the type was out of range
-    uint64_t decompression_flags = 0;
-       
-    if (vnode_isnamedstream(vp)) {
-        /*
-         named streams can't be compressed
-         since named streams of the same file share the same cnode,
-         we don't want to get/set the state in the cnode, just return 0
-         */
-        return 0;
-    }
-    
-    /* examine the cached a state in this cnode */    
-    cmp_state = decmpfs_cnode_get_vnode_state(cp);
-    switch(cmp_state) {
-        case FILE_IS_NOT_COMPRESSED:
-                       return 0;
-        case FILE_IS_COMPRESSED:
-                       return 1;
-        case FILE_IS_CONVERTING:
-            /* treat the file as compressed, because this gives us a way to block future reads until decompression is done */
-            return 1;
-        case FILE_TYPE_UNKNOWN:
-            /* the first time we encountered this vnode, so we need to check it out */
-            break;
-        default:
-            /* unknown state, assume file is not compressed */
-            ErrorLog("unknown cmp_state %d\n", cmp_state);
-            return 0;
-    }
-    
-//    if (!vnode_isreg(vp)) {
-//        /* only regular files can be compressed */
-//        ret = FILE_IS_NOT_COMPRESSED;
-//        goto done;
-//    }
-    
-    mp = vnode_mount(vp); 
-    if (mp == NULL) {
-        /*
-         this should only be true before we mount the root filesystem
-         we short-cut this return to avoid the call to getattr below, which
-         will fail before root is mounted
-         */
-        ret = FILE_IS_NOT_COMPRESSED;
-        goto done;
-    }
-    if ((mp->mnt_flag & MNT_LOCAL) == 0) {
-        /* compression only supported on local filesystems */
-        ret = FILE_IS_NOT_COMPRESSED;
-        goto done;
-    }
-    
+       int saveInvalid = 0; // save the header data even though the type was out of range
+       uint64_t decompression_flags = 0;
+       bool is_mounted, is_local_fs;
+
+       if (vnode_isnamedstream(vp)) {
+               /*
+                *  named streams can't be compressed
+                *  since named streams of the same file share the same cnode,
+                *  we don't want to get/set the state in the cnode, just return 0
+                */
+               return 0;
+       }
+
+       /* examine the cached a state in this cnode */
+       cmp_state = decmpfs_cnode_get_vnode_state(cp);
+       switch (cmp_state) {
+       case FILE_IS_NOT_COMPRESSED:
+               return 0;
+       case FILE_IS_COMPRESSED:
+               return 1;
+       case FILE_IS_CONVERTING:
+               /* treat the file as compressed, because this gives us a way to block future reads until decompression is done */
+               return 1;
+       case FILE_TYPE_UNKNOWN:
+               /* the first time we encountered this vnode, so we need to check it out */
+               break;
+       default:
+               /* unknown state, assume file is not compressed */
+               ErrorLogWithPath("unknown cmp_state %d\n", cmp_state);
+               return 0;
+       }
+
+       is_mounted = false;
+       is_local_fs = false;
+       mp = vnode_mount(vp);
+       if (mp) {
+               is_mounted = true;
+       }
+       if (is_mounted) {
+               is_local_fs = ((mp->mnt_flag & MNT_LOCAL));
+       }
+       /*
+        * Trace the following parameters on entry with event-id 0x03120014.
+        *
+        * @vp->v_id:       vnode-id of the file being queried.
+        * @is_mounted:     set to true if @vp belongs to a mounted fs.
+        * @is_local_fs:    set to true if @vp belongs to local fs.
+        */
+       DECMPFS_EMIT_TRACE_ENTRY(DECMPDBG_FILE_IS_COMPRESSED, vp->v_id,
+           is_mounted, is_local_fs);
+
+       if (!is_mounted) {
+               /*
+                *  this should only be true before we mount the root filesystem
+                *  we short-cut this return to avoid the call to getattr below, which
+                *  will fail before root is mounted
+                */
+               ret = FILE_IS_NOT_COMPRESSED;
+               goto done;
+       }
+
+       if (!is_local_fs) {
+               /* compression only supported on local filesystems */
+               ret = FILE_IS_NOT_COMPRESSED;
+               goto done;
+       }
+
        /* lock our cnode data so that another caller doesn't change the state under us */
        decmpfs_lock_compressed_data(cp, 1);
        cnode_locked = 1;
-       
+
        VATTR_INIT(&va_fetch);
        VATTR_WANTED(&va_fetch, va_flags);
        error = vnode_getattr(vp, &va_fetch, decmpfs_ctx);
        if (error) {
-        /* failed to get the bsd flags so the file is not compressed */
-        ret = FILE_IS_NOT_COMPRESSED;
-        goto done;
-    }
+               /* failed to get the bsd flags so the file is not compressed */
+               ret = FILE_IS_NOT_COMPRESSED;
+               goto done;
+       }
        if (va_fetch.va_flags & UF_COMPRESSED) {
                /* UF_COMPRESSED is on, make sure the file has the DECMPFS_XATTR_NAME xattr */
-        error = decmpfs_fetch_compressed_header(vp, cp, &hdr, 1);
-        if ((hdr != NULL) && (error == ERANGE)) {
-            saveInvalid = 1;
-        }
-        if (error) {
-            /* failed to get the xattr so the file is not compressed */
-            ret = FILE_IS_NOT_COMPRESSED;
-            goto done;
-        }
-        /* we got the xattr, so the file is compressed */
-        ret = FILE_IS_COMPRESSED;
-        goto done;
-       }
-    /* UF_COMPRESSED isn't on, so the file isn't compressed */
-    ret = FILE_IS_NOT_COMPRESSED;
-    
+               error = decmpfs_fetch_compressed_header(vp, cp, &hdr, 1);
+               if ((hdr != NULL) && (error == ERANGE)) {
+                       saveInvalid = 1;
+               }
+               if (error) {
+                       /* failed to get the xattr so the file is not compressed */
+                       ret = FILE_IS_NOT_COMPRESSED;
+                       goto done;
+               }
+               /*
+                * We got the xattr, so the file is at least tagged compressed.
+                * For DATALESS, regular files and directories can be "compressed".
+                * For all other types, only files are allowed.
+                */
+               if (!vnode_isreg(vp) &&
+                   !(decmpfs_type_is_dataless(hdr->compression_type) && vnode_isdir(vp))) {
+                       ret = FILE_IS_NOT_COMPRESSED;
+                       goto done;
+               }
+               ret = FILE_IS_COMPRESSED;
+               goto done;
+       }
+       /* UF_COMPRESSED isn't on, so the file isn't compressed */
+       ret = FILE_IS_NOT_COMPRESSED;
+
 done:
-    if (((ret == FILE_IS_COMPRESSED) || saveInvalid) && hdr) {
+       if (((ret == FILE_IS_COMPRESSED) || saveInvalid) && hdr) {
                /*
-                cache the uncompressed size away in the cnode
+                *  cache the uncompressed size away in the cnode
                 */
-               
+
                if (!cnode_locked) {
                        /*
-                        we should never get here since the only place ret is set to FILE_IS_COMPRESSED
-                        is after the call to decmpfs_lock_compressed_data above
+                        *  we should never get here since the only place ret is set to FILE_IS_COMPRESSED
+                        *  is after the call to decmpfs_lock_compressed_data above
                         */
                        decmpfs_lock_compressed_data(cp, 1);
                        cnode_locked = 1;
                }
-               
-        decmpfs_cnode_set_vnode_cached_size(cp, hdr->uncompressed_size);
+
+               if (vnode_isdir(vp)) {
+                       decmpfs_cnode_set_vnode_cached_size(cp, 64);
+                       decmpfs_cnode_set_vnode_cached_nchildren(cp, decmpfs_get_directory_entries(hdr));
+                       if (hdr->compression_type == DATALESS_PKG_CMPFS_TYPE) {
+                               decmpfs_cnode_set_vnode_cached_total_size(cp, DECMPFS_PKG_SIZE(hdr->_size));
+                       }
+               } else {
+                       decmpfs_cnode_set_vnode_cached_size(cp, hdr->uncompressed_size);
+               }
                decmpfs_cnode_set_vnode_state(cp, ret, 1);
-        decmpfs_cnode_set_vnode_cmp_type(cp, hdr->compression_type, 1);
-        /* remember if the xattr's size was equal to the minimal xattr */
-        if (hdr->attr_size == sizeof(decmpfs_disk_header)) {
-            decmpfs_cnode_set_vnode_minimal_xattr(cp, 1, 1);
-        }
-        if (ret == FILE_IS_COMPRESSED) {
-            /* update the ubc's size for this file */
-            ubc_setsize(vp, hdr->uncompressed_size);
-            
-            /* update the decompression flags in the decmpfs cnode */
-            lck_rw_lock_shared(decompressorsLock);
-            decmpfs_get_decompression_flags_func get_flags = decmp_get_func(hdr->compression_type, get_flags);
-            if (get_flags) {
-                decompression_flags = get_flags(vp, decmpfs_ctx, hdr);
-            }
-            lck_rw_unlock_shared(decompressorsLock);
-            decmpfs_cnode_set_decompression_flags(cp, decompression_flags);
-        }
+               decmpfs_cnode_set_vnode_cmp_type(cp, hdr->compression_type, 1);
+               /* remember if the xattr's size was equal to the minimal xattr */
+               if (hdr->attr_size == sizeof(decmpfs_disk_header)) {
+                       decmpfs_cnode_set_vnode_minimal_xattr(cp, 1, 1);
+               }
+               if (ret == FILE_IS_COMPRESSED) {
+                       /* update the ubc's size for this file */
+                       ubc_setsize(vp, hdr->uncompressed_size);
+
+                       /* update the decompression flags in the decmpfs cnode */
+                       lck_rw_lock_shared(decompressorsLock);
+                       decmpfs_get_decompression_flags_func get_flags = decmp_get_func(vp, hdr->compression_type, get_flags);
+                       if (get_flags) {
+                               decompression_flags = get_flags(vp, decmpfs_ctx, hdr);
+                       }
+                       lck_rw_unlock_shared(decompressorsLock);
+                       decmpfs_cnode_set_decompression_flags(cp, decompression_flags);
+               }
        } else {
                /* we might have already taken the lock above; if so, skip taking it again by passing cnode_locked as the skiplock parameter */
                decmpfs_cnode_set_vnode_state(cp, ret, cnode_locked);
        }
-       
-       if (cnode_locked) decmpfs_unlock_compressed_data(cp, 1);
-    
-    if (hdr) FREE(hdr, M_TEMP);
-       
-       switch(ret) {
-        case FILE_IS_NOT_COMPRESSED:
-                       return 0;
-        case FILE_IS_COMPRESSED:
-        case FILE_IS_CONVERTING:
-                       return 1;
-        default:
-            /* unknown state, assume file is not compressed */
-            ErrorLog("unknown ret %d\n", ret);
-            return 0;
-    }
+
+       if (cnode_locked) {
+               decmpfs_unlock_compressed_data(cp, 1);
+       }
+
+       if (hdr) {
+               FREE(hdr, M_TEMP);
+       }
+       /*
+        * Trace the following parameters on return with event-id 0x03120014.
+        *
+        * @vp->v_id:       vnode-id of the file being queried.
+        * @return:         set to 1 is file is compressed.
+        */
+       switch (ret) {
+       case FILE_IS_NOT_COMPRESSED:
+               DECMPFS_EMIT_TRACE_RETURN(DECMPDBG_FILE_IS_COMPRESSED, vp->v_id, 0);
+               return 0;
+       case FILE_IS_COMPRESSED:
+       case FILE_IS_CONVERTING:
+               DECMPFS_EMIT_TRACE_RETURN(DECMPDBG_FILE_IS_COMPRESSED, vp->v_id, 1);
+               return 1;
+       default:
+               /* unknown state, assume file is not compressed */
+               DECMPFS_EMIT_TRACE_RETURN(DECMPDBG_FILE_IS_COMPRESSED, vp->v_id, 0);
+               ErrorLogWithPath("unknown ret %d\n", ret);
+               return 0;
+       }
 }
 
 int
 decmpfs_update_attributes(vnode_t vp, struct vnode_attr *vap)
 {
-    int error = 0;
-    
-    if (VATTR_IS_ACTIVE(vap, va_flags)) {
-        /* the BSD flags are being updated */
-        if (vap->va_flags & UF_COMPRESSED) {
-            /* the compressed bit is being set, did it change? */
-            struct vnode_attr va_fetch;
-            int old_flags = 0;
-            VATTR_INIT(&va_fetch);
-            VATTR_WANTED(&va_fetch, va_flags);
+       int error = 0;
+
+       if (VATTR_IS_ACTIVE(vap, va_flags)) {
+               /* the BSD flags are being updated */
+               if (vap->va_flags & UF_COMPRESSED) {
+                       /* the compressed bit is being set, did it change? */
+                       struct vnode_attr va_fetch;
+                       int old_flags = 0;
+                       VATTR_INIT(&va_fetch);
+                       VATTR_WANTED(&va_fetch, va_flags);
                        error = vnode_getattr(vp, &va_fetch, decmpfs_ctx);
-            if (error)
-                return error;
-            
-            old_flags = va_fetch.va_flags;
-            
-            if (!(old_flags & UF_COMPRESSED)) {
-                /*
-                 * Compression bit was turned on, make sure the file has the DECMPFS_XATTR_NAME attribute.
-                 * This precludes anyone from using the UF_COMPRESSED bit for anything else, and it enforces
-                 * an order of operation -- you must first do the setxattr and then the chflags.
-                 */
-                               
+                       if (error) {
+                               return error;
+                       }
+
+                       old_flags = va_fetch.va_flags;
+
+                       if (!(old_flags & UF_COMPRESSED)) {
+                               /*
+                                * Compression bit was turned on, make sure the file has the DECMPFS_XATTR_NAME attribute.
+                                * This precludes anyone from using the UF_COMPRESSED bit for anything else, and it enforces
+                                * an order of operation -- you must first do the setxattr and then the chflags.
+                                */
+
                                if (VATTR_IS_ACTIVE(vap, va_data_size)) {
                                        /*
                                         * don't allow the caller to set the BSD flag and the size in the same call
@@ -811,44 +1008,54 @@ decmpfs_update_attributes(vnode_t vp, struct vnode_attr *vap)
                                        vap->va_flags &= ~UF_COMPRESSED;
                                        return 0;
                                }
-                               
-                decmpfs_header *hdr = NULL;
-                error = decmpfs_fetch_compressed_header(vp, NULL, &hdr, 1);
-                if (error == 0) {
-                    /*
-                     allow the flag to be set since the decmpfs attribute is present
-                     in that case, we also want to truncate the data fork of the file
-                     */
-                    VATTR_SET_ACTIVE(vap, va_data_size);
-                    vap->va_data_size = 0;
-                } else if (error == ERANGE) {
-                    /* the file had a decmpfs attribute but the type was out of range, so don't muck with the file's data size */
-                } else {
-                    /* no DECMPFS_XATTR_NAME attribute, so deny the update */
+
+                               decmpfs_header *hdr = NULL;
+                               error = decmpfs_fetch_compressed_header(vp, NULL, &hdr, 1);
+                               if (error == 0) {
+                                       /*
+                                        * Allow the flag to be set since the decmpfs attribute
+                                        * is present.
+                                        *
+                                        * If we're creating a dataless file we do not want to
+                                        * truncate it to zero which allows the file resolver to
+                                        * have more control over when truncation should happen.
+                                        * All other types of compressed files are truncated to
+                                        * zero.
+                                        */
+                                       if (!decmpfs_type_is_dataless(hdr->compression_type)) {
+                                               VATTR_SET_ACTIVE(vap, va_data_size);
+                                               vap->va_data_size = 0;
+                                       }
+                               } else if (error == ERANGE) {
+                                       /* the file had a decmpfs attribute but the type was out of range, so don't muck with the file's data size */
+                               } else {
+                                       /* no DECMPFS_XATTR_NAME attribute, so deny the update */
                                        vap->va_flags &= ~UF_COMPRESSED;
-                }
-                if (hdr) FREE(hdr, M_TEMP);
-            }
-        }
-    }
-    
-    return 0;
+                               }
+                               if (hdr) {
+                                       FREE(hdr, M_TEMP);
+                               }
+                       }
+               }
+       }
+
+       return 0;
 }
 
 static int
 wait_for_decompress(decmpfs_cnode *cp)
 {
-    int state;
-    lck_mtx_lock(decompress_channel_mtx);
-    do {
-        state = decmpfs_fast_get_state(cp);
-        if (state != FILE_IS_CONVERTING) {
-            /* file is not decompressing */
-            lck_mtx_unlock(decompress_channel_mtx);
-            return state;
-        }
-        msleep((caddr_t)&decompress_channel, decompress_channel_mtx, PINOD, "wait_for_decompress", NULL);
-    } while(1);
+       int state;
+       lck_mtx_lock(decompress_channel_mtx);
+       do {
+               state = decmpfs_fast_get_state(cp);
+               if (state != FILE_IS_CONVERTING) {
+                       /* file is not decompressing */
+                       lck_mtx_unlock(decompress_channel_mtx);
+                       return state;
+               }
+               msleep((caddr_t)&decompress_channel, decompress_channel_mtx, PINOD, "wait_for_decompress", NULL);
+       } while (1);
 }
 
 #pragma mark --- decmpfs hide query routines ---
@@ -857,19 +1064,21 @@ int
 decmpfs_hides_rsrc(vfs_context_t ctx, decmpfs_cnode *cp)
 {
        /*
-        WARNING!!!
-        callers may (and do) pass NULL for ctx, so we should only use it
-        for this equality comparison
-        
-        This routine should only be called after a file has already been through decmpfs_file_is_compressed
+        *  WARNING!!!
+        *  callers may (and do) pass NULL for ctx, so we should only use it
+        *  for this equality comparison
+        *
+        *  This routine should only be called after a file has already been through decmpfs_file_is_compressed
         */
-       
-       if (ctx == decmpfs_ctx)
+
+       if (ctx == decmpfs_ctx) {
                return 0;
-       
-       if (!decmpfs_fast_file_is_compressed(cp))
+       }
+
+       if (!decmpfs_fast_file_is_compressed(cp)) {
                return 0;
-       
+       }
+
        /* all compressed files hide their resource fork */
        return 1;
 }
@@ -878,106 +1087,115 @@ int
 decmpfs_hides_xattr(vfs_context_t ctx, decmpfs_cnode *cp, const char *xattr)
 {
        /*
-        WARNING!!!
-        callers may (and do) pass NULL for ctx, so we should only use it
-        for this equality comparison
-     
-        This routine should only be called after a file has already been through decmpfs_file_is_compressed
+        *  WARNING!!!
+        *  callers may (and do) pass NULL for ctx, so we should only use it
+        *  for this equality comparison
+        *
+        *  This routine should only be called after a file has already been through decmpfs_file_is_compressed
         */
-       
-       if (ctx == decmpfs_ctx)
+
+       if (ctx == decmpfs_ctx) {
                return 0;
-       if (strncmp(xattr, XATTR_RESOURCEFORK_NAME, 22) == 0)
+       }
+       if (strncmp(xattr, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME) - 1) == 0) {
                return decmpfs_hides_rsrc(ctx, cp);
-       if (!decmpfs_fast_file_is_compressed(cp))
-    /* file is not compressed, so don't hide this xattr */
+       }
+       if (!decmpfs_fast_file_is_compressed(cp)) {
+               /* file is not compressed, so don't hide this xattr */
                return 0;
-       if (strncmp(xattr, DECMPFS_XATTR_NAME, 11) == 0)
-    /* it's our xattr, so hide it */
+       }
+       if (strncmp(xattr, DECMPFS_XATTR_NAME, sizeof(DECMPFS_XATTR_NAME) - 1) == 0) {
+               /* it's our xattr, so hide it */
                return 1;
+       }
        /* don't hide this xattr */
        return 0;
 }
 
 #pragma mark --- registration/validation routines ---
 
-static inline int registration_valid(decmpfs_registration *registration)
+static inline int
+registration_valid(const decmpfs_registration *registration)
 {
-    return registration && ((registration->decmpfs_registration == DECMPFS_REGISTRATION_VERSION_V1) || (registration->decmpfs_registration == DECMPFS_REGISTRATION_VERSION_V3));
+       return registration && ((registration->decmpfs_registration == DECMPFS_REGISTRATION_VERSION_V1) || (registration->decmpfs_registration == DECMPFS_REGISTRATION_VERSION_V3));
 }
 
 errno_t
-register_decmpfs_decompressor(uint32_t compression_type, decmpfs_registration *registration)
+register_decmpfs_decompressor(uint32_t compression_type, const decmpfs_registration *registration)
 {
-    /* called by kexts to register decompressors */
-    
-    errno_t ret = 0;
-    int locked = 0;
-    char resourceName[80];
-    
-    if ((compression_type >= CMP_MAX) || !registration_valid(registration)) {
-        ret = EINVAL;
-        goto out;
-    }
-    
-    lck_rw_lock_exclusive(decompressorsLock); locked = 1;
-       
-    /* make sure the registration for this type is zero */
+       /* called by kexts to register decompressors */
+
+       errno_t ret = 0;
+       int locked = 0;
+       char resourceName[80];
+
+       if ((compression_type >= CMP_MAX) || !registration_valid(registration)) {
+               ret = EINVAL;
+               goto out;
+       }
+
+       lck_rw_lock_exclusive(decompressorsLock); locked = 1;
+
+       /* make sure the registration for this type is zero */
        if (decompressors[compression_type] != NULL) {
                ret = EEXIST;
                goto out;
        }
-    decompressors[compression_type] = registration;
-    snprintf(resourceName, sizeof(resourceName), "com.apple.AppleFSCompression.Type%u", compression_type);
-    IOServicePublishResource(resourceName, TRUE);
-    
+       decompressors[compression_type] = registration;
+       snprintf(resourceName, sizeof(resourceName), "com.apple.AppleFSCompression.Type%u", compression_type);
+       IOServicePublishResource(resourceName, TRUE);
+
 out:
-    if (locked) lck_rw_unlock_exclusive(decompressorsLock);
-    return ret;
+       if (locked) {
+               lck_rw_unlock_exclusive(decompressorsLock);
+       }
+       return ret;
 }
 
 errno_t
 unregister_decmpfs_decompressor(uint32_t compression_type, decmpfs_registration *registration)
 {
-    /* called by kexts to unregister decompressors */
-    
-    errno_t ret = 0;
-    int locked = 0;
-    char resourceName[80];
-
-    if ((compression_type >= CMP_MAX) || !registration_valid(registration)) {
-        ret = EINVAL;
-        goto out;
-    }
-    
-    lck_rw_lock_exclusive(decompressorsLock); locked = 1;
-    if (decompressors[compression_type] != registration) {
-        ret = EEXIST;
-        goto out;
-    }
-    decompressors[compression_type] = NULL;
-    snprintf(resourceName, sizeof(resourceName), "com.apple.AppleFSCompression.Type%u", compression_type);
-    IOServicePublishResource(resourceName, FALSE);
-    
+       /* called by kexts to unregister decompressors */
+
+       errno_t ret = 0;
+       int locked = 0;
+       char resourceName[80];
+
+       if ((compression_type >= CMP_MAX) || !registration_valid(registration)) {
+               ret = EINVAL;
+               goto out;
+       }
+
+       lck_rw_lock_exclusive(decompressorsLock); locked = 1;
+       if (decompressors[compression_type] != registration) {
+               ret = EEXIST;
+               goto out;
+       }
+       decompressors[compression_type] = NULL;
+       snprintf(resourceName, sizeof(resourceName), "com.apple.AppleFSCompression.Type%u", compression_type);
+       IOServicePublishResource(resourceName, FALSE);
+
 out:
-    if (locked) lck_rw_unlock_exclusive(decompressorsLock);
-    return ret;
+       if (locked) {
+               lck_rw_unlock_exclusive(decompressorsLock);
+       }
+       return ret;
 }
 
 static int
-compression_type_valid(decmpfs_header *hdr)
+compression_type_valid(vnode_t vp, decmpfs_header *hdr)
 {
-    /* fast pre-check to determine if the given compressor has checked in */
-    int ret = 0;
-    
-    /* every compressor must have at least a fetch function */
-    lck_rw_lock_shared(decompressorsLock);
-    if (decmp_get_func(hdr->compression_type, fetch) != NULL) {
-        ret = 1;
-    }
-    lck_rw_unlock_shared(decompressorsLock);
-       
-    return ret;
+       /* fast pre-check to determine if the given compressor has checked in */
+       int ret = 0;
+
+       /* every compressor must have at least a fetch function */
+       lck_rw_lock_shared(decompressorsLock);
+       if (decmp_get_func(vp, hdr->compression_type, fetch) != NULL) {
+               ret = 1;
+       }
+       lck_rw_unlock_shared(decompressorsLock);
+
+       return ret;
 }
 
 #pragma mark --- compression/decompression routines ---
@@ -985,473 +1203,567 @@ compression_type_valid(decmpfs_header *hdr)
 static int
 decmpfs_fetch_uncompressed_data(vnode_t vp, decmpfs_cnode *cp, decmpfs_header *hdr, off_t offset, user_ssize_t size, int nvec, decmpfs_vector *vec, uint64_t *bytes_read)
 {
-    /* get the uncompressed bytes for the specified region of vp by calling out to the registered compressor */
-    
-    int err          = 0;
-       
-    *bytes_read = 0;
-    
-    if ((uint64_t)offset >= hdr->uncompressed_size) {
-        /* reading past end of file; nothing to do */
-        err = 0;
-        goto out;
-    }
-    if (offset < 0) {
-        /* tried to read from before start of file */
-        err = EINVAL;
-        goto out;
-    }
-    if ((uint64_t)(offset + size) > hdr->uncompressed_size) {
-        /* adjust size so we don't read past the end of the file */
+       /* get the uncompressed bytes for the specified region of vp by calling out to the registered compressor */
+
+       int err          = 0;
+
+       *bytes_read = 0;
+
+       if ((uint64_t)offset >= hdr->uncompressed_size) {
+               /* reading past end of file; nothing to do */
+               err = 0;
+               goto out;
+       }
+       if (offset < 0) {
+               /* tried to read from before start of file */
+               err = EINVAL;
+               goto out;
+       }
+       if ((uint64_t)(offset + size) > hdr->uncompressed_size) {
+               /* adjust size so we don't read past the end of the file */
                size = hdr->uncompressed_size - offset;
        }
-    if (size == 0) {
-        /* nothing to read */
-        err = 0;
-        goto out;
-    }
-    
-    lck_rw_lock_shared(decompressorsLock);
-    decmpfs_fetch_uncompressed_data_func fetch = decmp_get_func(hdr->compression_type, fetch);
-    if (fetch) {
+       if (size == 0) {
+               /* nothing to read */
+               err = 0;
+               goto out;
+       }
+
+       /*
+        * Trace the following parameters on entry with event-id 0x03120008.
+        *
+        * @vp->v_id:       vnode-id of the file being decompressed.
+        * @hdr->compression_type: compression type.
+        * @offset:         offset from where to fetch uncompressed data.
+        * @size:           amount of uncompressed data to fetch.
+        *
+        * Please NOTE: @offset and @size can overflow in theory but
+        * here it is safe.
+        */
+       DECMPFS_EMIT_TRACE_ENTRY(DECMPDBG_FETCH_UNCOMPRESSED_DATA, vp->v_id,
+           hdr->compression_type, (int)offset, (int)size);
+       lck_rw_lock_shared(decompressorsLock);
+       decmpfs_fetch_uncompressed_data_func fetch = decmp_get_func(vp, hdr->compression_type, fetch);
+       if (fetch) {
                err = fetch(vp, decmpfs_ctx, hdr, offset, size, nvec, vec, bytes_read);
                lck_rw_unlock_shared(decompressorsLock);
-        if (err == 0) {
-            uint64_t decompression_flags = decmpfs_cnode_get_decompression_flags(cp);
-            if (decompression_flags & DECMPFS_FLAGS_FORCE_FLUSH_ON_DECOMPRESS) {
-#if    !defined(__i386__) && !defined(__x86_64__)
-                int i;
-                for (i = 0; i < nvec; i++) {
-                    flush_dcache64((addr64_t)(uintptr_t)vec[i].buf, vec[i].size, FALSE);
-                }
+               if (err == 0) {
+                       uint64_t decompression_flags = decmpfs_cnode_get_decompression_flags(cp);
+                       if (decompression_flags & DECMPFS_FLAGS_FORCE_FLUSH_ON_DECOMPRESS) {
+#if     !defined(__i386__) && !defined(__x86_64__)
+                               int i;
+                               for (i = 0; i < nvec; i++) {
+                                       flush_dcache64((addr64_t)(uintptr_t)vec[i].buf, vec[i].size, FALSE);
+                               }
 #endif
-            }
-        }
-    } else {
-        err = ENOTSUP;
-        lck_rw_unlock_shared(decompressorsLock);
-    }
-    
+                       }
+               }
+       } else {
+               err = ENOTSUP;
+               lck_rw_unlock_shared(decompressorsLock);
+       }
+       /*
+        * Trace the following parameters on return with event-id 0x03120008.
+        *
+        * @vp->v_id:       vnode-id of the file being decompressed.
+        * @bytes_read:     amount of uncompressed bytes fetched in bytes.
+        * @err:            value returned from this function.
+        *
+        * Please NOTE: @bytes_read can overflow in theory but here it is safe.
+        */
+       DECMPFS_EMIT_TRACE_RETURN(DECMPDBG_FETCH_UNCOMPRESSED_DATA, vp->v_id,
+           (int)*bytes_read, err);
 out:
-    return err;
+       return err;
 }
 
 static kern_return_t
 commit_upl(upl_t upl, upl_offset_t pl_offset, size_t uplSize, int flags, int abort)
 {
-    kern_return_t kr = 0;
-    
-    /* commit the upl pages */
-    if (abort) {
-        VerboseLog("aborting upl, flags 0x%08x\n", flags);
+       kern_return_t kr = 0;
+
+#if CONFIG_IOSCHED
+       upl_unmark_decmp(upl);
+#endif /* CONFIG_IOSCHED */
+
+       /* commit the upl pages */
+       if (abort) {
+               VerboseLog("aborting upl, flags 0x%08x\n", flags);
                kr = ubc_upl_abort_range(upl, pl_offset, uplSize, flags);
-        if (kr != KERN_SUCCESS)
-            ErrorLog("ubc_upl_commit_range error %d\n", (int)kr);
-    } else {
-        VerboseLog("committing upl, flags 0x%08x\n", flags | UPL_COMMIT_CLEAR_DIRTY);
-               kr = ubc_upl_commit_range(upl, pl_offset, uplSize, flags | UPL_COMMIT_CLEAR_DIRTY);
-        if (kr != KERN_SUCCESS)
-            ErrorLog("ubc_upl_commit_range error %d\n", (int)kr);
-    }
-    return kr;
+               if (kr != KERN_SUCCESS) {
+                       ErrorLog("ubc_upl_abort_range error %d\n", (int)kr);
+               }
+       } else {
+               VerboseLog("committing upl, flags 0x%08x\n", flags | UPL_COMMIT_CLEAR_DIRTY);
+               kr = ubc_upl_commit_range(upl, pl_offset, uplSize, flags | UPL_COMMIT_CLEAR_DIRTY | UPL_COMMIT_WRITTEN_BY_KERNEL);
+               if (kr != KERN_SUCCESS) {
+                       ErrorLog("ubc_upl_commit_range error %d\n", (int)kr);
+               }
+       }
+       return kr;
 }
 
+
 errno_t
 decmpfs_pagein_compressed(struct vnop_pagein_args *ap, int *is_compressed, decmpfs_cnode *cp)
 {
-    /* handles a page-in request from vfs for a compressed file */
-    
-    int err                      = 0;
-    struct vnode *vp             = ap->a_vp;
-    upl_t pl                     = ap->a_pl;
+       /* handles a page-in request from vfs for a compressed file */
+
+       int err                      = 0;
+       vnode_t vp                   = ap->a_vp;
+       upl_t pl                     = ap->a_pl;
        upl_offset_t pl_offset       = ap->a_pl_offset;
-    off_t f_offset               = ap->a_f_offset;
-    size_t size                  = ap->a_size;
+       off_t f_offset               = ap->a_f_offset;
+       size_t size                  = ap->a_size;
        int flags                    = ap->a_flags;
-    off_t uplPos                 = 0;
-    user_ssize_t uplSize         = 0;
+       off_t uplPos                 = 0;
+       user_ssize_t uplSize         = 0;
        void *data                   = NULL;
-    decmpfs_header *hdr = NULL;
-    int abort_pagein             = 0;
-    uint64_t cachedSize          = 0;
+       decmpfs_header *hdr = NULL;
+       uint64_t cachedSize          = 0;
        int cmpdata_locked           = 0;
-       
-    if(!decmpfs_trylock_compressed_data(cp, 0)) {
-           return EAGAIN;
-    }
-    cmpdata_locked = 1;
-    
-       
+
+       if (!decmpfs_trylock_compressed_data(cp, 0)) {
+               return EAGAIN;
+       }
+       cmpdata_locked = 1;
+
+
        if (flags & ~(UPL_IOSYNC | UPL_NOCOMMIT | UPL_NORDAHEAD)) {
-               DebugLog("pagein: unknown flags 0x%08x\n", (flags & ~(UPL_IOSYNC | UPL_NOCOMMIT | UPL_NORDAHEAD)));
-       }
-    
-    err = decmpfs_fetch_compressed_header(vp, cp, &hdr, 0);
-    if (err != 0) {
-        goto out;
-    }
-       
-    cachedSize = hdr->uncompressed_size;
-    
-    if (!compression_type_valid(hdr)) {
-        /* compressor not registered */
-        err = ENOTSUP;
-        goto out;
-    }
-    
-    /* map the upl so we can fetch into it */
+               DebugLogWithPath("pagein: unknown flags 0x%08x\n", (flags & ~(UPL_IOSYNC | UPL_NOCOMMIT | UPL_NORDAHEAD)));
+       }
+
+       err = decmpfs_fetch_compressed_header(vp, cp, &hdr, 0);
+       if (err != 0) {
+               goto out;
+       }
+
+       cachedSize = hdr->uncompressed_size;
+
+       if (!compression_type_valid(vp, hdr)) {
+               /* compressor not registered */
+               err = ENOTSUP;
+               goto out;
+       }
+
+#if CONFIG_IOSCHED
+       /* Mark the UPL as the requesting UPL for decompression */
+       upl_mark_decmp(pl);
+#endif /* CONFIG_IOSCHED */
+
+       /* map the upl so we can fetch into it */
        kern_return_t kr = ubc_upl_map(pl, (vm_offset_t*)&data);
        if ((kr != KERN_SUCCESS) || (data == NULL)) {
+               err = ENOSPC;
+               data = NULL;
+#if CONFIG_IOSCHED
+               upl_unmark_decmp(pl);
+#endif /* CONFIG_IOSCHED */
                goto out;
        }
-    
-    uplPos = f_offset;
-    uplSize = size;
-       
-    /* clip the size to the size of the file */
-    if ((uint64_t)uplPos + uplSize > cachedSize) {
-        /* truncate the read to the size of the file */
-        uplSize = cachedSize - uplPos;
-    }
-       
-    /* do the fetch */
-    decmpfs_vector vec;
-    
+
+       uplPos = f_offset;
+       uplSize = size;
+
+       /* clip the size to the size of the file */
+       if ((uint64_t)uplPos + uplSize > cachedSize) {
+               /* truncate the read to the size of the file */
+               uplSize = cachedSize - uplPos;
+       }
+
+       /* do the fetch */
+       decmpfs_vector vec;
+
 decompress:
-    /* the mapped data pointer points to the first page of the page list, so we want to start filling in at an offset of pl_offset */
-    vec.buf = (char*)data + pl_offset;
-    vec.size = size;
-    
-    uint64_t did_read = 0;
+       /* the mapped data pointer points to the first page of the page list, so we want to start filling in at an offset of pl_offset */
+       vec.buf = (char*)data + pl_offset;
+       vec.size = size;
+
+       uint64_t did_read = 0;
        if (decmpfs_fast_get_state(cp) == FILE_IS_CONVERTING) {
-               ErrorLog("unexpected pagein during decompress\n");
+               ErrorLogWithPath("unexpected pagein during decompress\n");
                /*
-                if the file is converting, this must be a recursive call to pagein from underneath a call to decmpfs_decompress_file;
-                pretend that it succeeded but don't do anything since we're just going to write over the pages anyway
+                *  if the file is converting, this must be a recursive call to pagein from underneath a call to decmpfs_decompress_file;
+                *  pretend that it succeeded but don't do anything since we're just going to write over the pages anyway
                 */
                err = 0;
                did_read = 0;
        } else {
-        err = decmpfs_fetch_uncompressed_data(vp, cp, hdr, uplPos, uplSize, 1, &vec, &did_read);
-       }
-    if (err) {
-        DebugLog("decmpfs_fetch_uncompressed_data err %d\n", err);
-        int cmp_state = decmpfs_fast_get_state(cp);
-        if (cmp_state == FILE_IS_CONVERTING) {
-            DebugLog("cmp_state == FILE_IS_CONVERTING\n");
-            cmp_state = wait_for_decompress(cp);
-            if (cmp_state == FILE_IS_COMPRESSED) {
-                DebugLog("cmp_state == FILE_IS_COMPRESSED\n");
-                /* a decompress was attempted but it failed, let's try calling fetch again */
-                goto decompress;
-            }
-        }
-        if (cmp_state == FILE_IS_NOT_COMPRESSED) {
-            DebugLog("cmp_state == FILE_IS_NOT_COMPRESSED\n");
-            /* the file was decompressed after we started reading it */
-            abort_pagein = 1;   /* we're not going to commit our data */
-            *is_compressed = 0; /* instruct caller to fall back to its normal path */
-        }
-    }
-    
-    /* zero out whatever we didn't read, and zero out the end of the last page(s) */
-    uint64_t total_size = (size + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
-    if (did_read < total_size) {
-        memset((char*)vec.buf + did_read, 0, total_size - did_read);
-    }
-    
+               err = decmpfs_fetch_uncompressed_data(vp, cp, hdr, uplPos, uplSize, 1, &vec, &did_read);
+       }
+       if (err) {
+               DebugLogWithPath("decmpfs_fetch_uncompressed_data err %d\n", err);
+               int cmp_state = decmpfs_fast_get_state(cp);
+               if (cmp_state == FILE_IS_CONVERTING) {
+                       DebugLogWithPath("cmp_state == FILE_IS_CONVERTING\n");
+                       cmp_state = wait_for_decompress(cp);
+                       if (cmp_state == FILE_IS_COMPRESSED) {
+                               DebugLogWithPath("cmp_state == FILE_IS_COMPRESSED\n");
+                               /* a decompress was attempted but it failed, let's try calling fetch again */
+                               goto decompress;
+                       }
+               }
+               if (cmp_state == FILE_IS_NOT_COMPRESSED) {
+                       DebugLogWithPath("cmp_state == FILE_IS_NOT_COMPRESSED\n");
+                       /* the file was decompressed after we started reading it */
+                       *is_compressed = 0; /* instruct caller to fall back to its normal path */
+               }
+       }
+
+       /* zero out whatever we didn't read, and zero out the end of the last page(s) */
+       uint64_t total_size = (size + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
+       if (did_read < total_size) {
+               memset((char*)vec.buf + did_read, 0, total_size - did_read);
+       }
+
+#if CONFIG_IOSCHED
+       upl_unmark_decmp(pl);
+#endif /* CONFIG_IOSCHED */
+
        kr = ubc_upl_unmap(pl); data = NULL; /* make sure to set data to NULL so we don't try to unmap again below */
-    if (kr != KERN_SUCCESS)
-        ErrorLog("ubc_upl_unmap error %d\n", (int)kr);
-    else {
-        if (!abort_pagein) {
-            /* commit our pages */
+       if (kr != KERN_SUCCESS) {
+               ErrorLogWithPath("ubc_upl_unmap error %d\n", (int)kr);
+       } else {
+               if (!err) {
+                       /* commit our pages */
                        kr = commit_upl(pl, pl_offset, total_size, UPL_COMMIT_FREE_ON_EMPTY, 0);
-        }
-    }
-    
+               }
+       }
+
 out:
-       if (data) ubc_upl_unmap(pl);
-    if (hdr) FREE(hdr, M_TEMP);
-       if (cmpdata_locked) decmpfs_unlock_compressed_data(cp, 0);
-    if (err)
-        ErrorLog("err %d\n", err);
-    
+       if (data) {
+               ubc_upl_unmap(pl);
+       }
+       if (hdr) {
+               FREE(hdr, M_TEMP);
+       }
+       if (cmpdata_locked) {
+               decmpfs_unlock_compressed_data(cp, 0);
+       }
+       if (err) {
+#if 0
+               if (err != ENXIO && err != ENOSPC) {
+                       char *path;
+                       MALLOC(path, char *, PATH_MAX, M_TEMP, M_WAITOK);
+                       panic("%s: decmpfs_pagein_compressed: err %d", vnpath(vp, path, PATH_MAX), err);
+                       FREE(path, M_TEMP);
+               }
+#endif /* 0 */
+               ErrorLogWithPath("err %d\n", err);
+       }
        return err;
 }
 
-errno_t 
+errno_t
 decmpfs_read_compressed(struct vnop_read_args *ap, int *is_compressed, decmpfs_cnode *cp)
 {
-    /* handles a read request from vfs for a compressed file */
-       
-    uio_t uio                    = ap->a_uio;
-    vnode_t vp                   = ap->a_vp;
-    int err                      = 0;
-    int countInt                 = 0;
-    off_t uplPos                 = 0;
-    user_ssize_t uplSize         = 0;
-    user_ssize_t uplRemaining    = 0;
-    off_t curUplPos              = 0;
-    user_ssize_t curUplSize      = 0;
-    kern_return_t kr             = KERN_SUCCESS;
-    int abort_read               = 0;
-    void *data                   = NULL;
-    uint64_t did_read            = 0;
-    upl_t upl                    = NULL;
-    upl_page_info_t *pli         = NULL;
-    decmpfs_header *hdr          = NULL;
-    uint64_t cachedSize          = 0;
-    off_t uioPos                 = 0;
-    user_ssize_t uioRemaining    = 0;
+       /* handles a read request from vfs for a compressed file */
+
+       uio_t uio                    = ap->a_uio;
+       vnode_t vp                   = ap->a_vp;
+       int err                      = 0;
+       int countInt                 = 0;
+       off_t uplPos                 = 0;
+       user_ssize_t uplSize         = 0;
+       user_ssize_t uplRemaining    = 0;
+       off_t curUplPos              = 0;
+       user_ssize_t curUplSize      = 0;
+       kern_return_t kr             = KERN_SUCCESS;
+       int abort_read               = 0;
+       void *data                   = NULL;
+       uint64_t did_read            = 0;
+       upl_t upl                    = NULL;
+       upl_page_info_t *pli         = NULL;
+       decmpfs_header *hdr          = NULL;
+       uint64_t cachedSize          = 0;
+       off_t uioPos                 = 0;
+       user_ssize_t uioRemaining    = 0;
        int cmpdata_locked           = 0;
-       
+
        decmpfs_lock_compressed_data(cp, 0); cmpdata_locked = 1;
-       
-    uplPos = uio_offset(uio);
-    uplSize = uio_resid(uio);
-    VerboseLog("uplPos %lld uplSize %lld\n", uplPos, uplSize);
-       
-    cachedSize = decmpfs_cnode_get_vnode_cached_size(cp);
-    
-    if ((uint64_t)uplPos + uplSize > cachedSize) {
-        /* truncate the read to the size of the file */
-        uplSize = cachedSize - uplPos;
-    }
-    
-    /* give the cluster layer a chance to fill in whatever it already has */
-    countInt = (uplSize > INT_MAX) ? INT_MAX : uplSize;
-    err = cluster_copy_ubc_data(vp, uio, &countInt, 0);
-    if (err != 0)
-        goto out;
-       
-    /* figure out what's left */
-    uioPos = uio_offset(uio);
-    uioRemaining = uio_resid(uio);
-    if ((uint64_t)uioPos + uioRemaining > cachedSize) {
-        /* truncate the read to the size of the file */
-        uioRemaining = cachedSize - uioPos;
-    }
-    
-    if (uioRemaining <= 0) {
-        /* nothing left */
-        goto out;
-    }
-    
-    err = decmpfs_fetch_compressed_header(vp, cp, &hdr, 0);
-    if (err != 0) {
-        goto out;
-    }
-    if (!compression_type_valid(hdr)) {
-        err = ENOTSUP;
-        goto out;
-    }
-    
-    uplPos = uioPos;
-    uplSize = uioRemaining;
+
+       uplPos = uio_offset(uio);
+       uplSize = uio_resid(uio);
+       VerboseLogWithPath("uplPos %lld uplSize %lld\n", uplPos, uplSize);
+
+       cachedSize = decmpfs_cnode_get_vnode_cached_size(cp);
+
+       if ((uint64_t)uplPos + uplSize > cachedSize) {
+               /* truncate the read to the size of the file */
+               uplSize = cachedSize - uplPos;
+       }
+
+       /* give the cluster layer a chance to fill in whatever it already has */
+       countInt = (uplSize > INT_MAX) ? INT_MAX : uplSize;
+       err = cluster_copy_ubc_data(vp, uio, &countInt, 0);
+       if (err != 0) {
+               goto out;
+       }
+
+       /* figure out what's left */
+       uioPos = uio_offset(uio);
+       uioRemaining = uio_resid(uio);
+       if ((uint64_t)uioPos + uioRemaining > cachedSize) {
+               /* truncate the read to the size of the file */
+               uioRemaining = cachedSize - uioPos;
+       }
+
+       if (uioRemaining <= 0) {
+               /* nothing left */
+               goto out;
+       }
+
+       err = decmpfs_fetch_compressed_header(vp, cp, &hdr, 0);
+       if (err != 0) {
+               goto out;
+       }
+       if (!compression_type_valid(vp, hdr)) {
+               err = ENOTSUP;
+               goto out;
+       }
+
+       uplPos = uioPos;
+       uplSize = uioRemaining;
 #if COMPRESSION_DEBUG
-    char path[PATH_MAX];
-    DebugLog("%s: uplPos %lld uplSize %lld\n", vnpath(vp, path, sizeof(path)), (uint64_t)uplPos, (uint64_t)uplSize);
+       DebugLogWithPath("uplPos %lld uplSize %lld\n", (uint64_t)uplPos, (uint64_t)uplSize);
 #endif
-       
-    lck_rw_lock_shared(decompressorsLock);
-    decmpfs_adjust_fetch_region_func adjust_fetch = decmp_get_func(hdr->compression_type, adjust_fetch);
-    if (adjust_fetch) {
-        /* give the compressor a chance to adjust the portion of the file that we read */
+
+       lck_rw_lock_shared(decompressorsLock);
+       decmpfs_adjust_fetch_region_func adjust_fetch = decmp_get_func(vp, hdr->compression_type, adjust_fetch);
+       if (adjust_fetch) {
+               /* give the compressor a chance to adjust the portion of the file that we read */
                adjust_fetch(vp, decmpfs_ctx, hdr, &uplPos, &uplSize);
-        VerboseLog("adjusted uplPos %lld uplSize %lld\n", (uint64_t)uplPos, (uint64_t)uplSize);
-    }
-    lck_rw_unlock_shared(decompressorsLock);
-    
-    /* clip the adjusted size to the size of the file */
-    if ((uint64_t)uplPos + uplSize > cachedSize) {
-        /* truncate the read to the size of the file */
-        uplSize = cachedSize - uplPos;
-    }
-    
-    if (uplSize <= 0) {
-        /* nothing left */
-        goto out;
-    }
-    
-    /*
-     since we're going to create a upl for the given region of the file,
-     make sure we're on page boundaries
-     */
-    
-    if (uplPos & (PAGE_SIZE - 1)) {
-        /* round position down to page boundary */
-        uplSize += (uplPos & (PAGE_SIZE - 1));
-        uplPos &= ~(PAGE_SIZE - 1);
-    }
-    /* round size up to page multiple */
-    uplSize = (uplSize + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
-    
-    VerboseLog("new uplPos %lld uplSize %lld\n", (uint64_t)uplPos, (uint64_t)uplSize);
-    
-    uplRemaining = uplSize;
-    curUplPos = uplPos;
-    curUplSize = 0;
-    
-    while(uplRemaining > 0) {
-        /* start after the last upl */
-        curUplPos += curUplSize;
-        
-        /* clip to max upl size */
-        curUplSize = uplRemaining;
-        if (curUplSize > MAX_UPL_SIZE * PAGE_SIZE) {
-            curUplSize = MAX_UPL_SIZE * PAGE_SIZE;
-        }
-        
-        /* create the upl */
-        kr = ubc_create_upl(vp, curUplPos, curUplSize, &upl, &pli, UPL_SET_LITE);
-        if (kr != KERN_SUCCESS) {
-            ErrorLog("ubc_create_upl error %d\n", (int)kr);
-            err = EINVAL;
-            goto out;
-        }
-        VerboseLog("curUplPos %lld curUplSize %lld\n", (uint64_t)curUplPos, (uint64_t)curUplSize);
-               
-        /* map the upl */
-        kr = ubc_upl_map(upl, (vm_offset_t*)&data);
-        if (kr != KERN_SUCCESS) {
-            ErrorLog("ubc_upl_map error %d\n", (int)kr);
-            err = EINVAL;
-            goto out;
-        }
-        
-        /* make sure the map succeeded */
-        if (!data) {
-            ErrorLog("ubc_upl_map mapped null\n");
-            err = EINVAL;
-            goto out;
-        }
-        
-        /* fetch uncompressed data into the mapped upl */
-        decmpfs_vector vec;
-    decompress:
-        vec = (decmpfs_vector){ .buf = data, .size = curUplSize };
-        err = decmpfs_fetch_uncompressed_data(vp, cp, hdr, curUplPos, curUplSize, 1, &vec, &did_read);
-        if (err) {
-            ErrorLog("decmpfs_fetch_uncompressed_data err %d\n", err);
-            
-            /* maybe the file is converting to decompressed */
-            int cmp_state = decmpfs_fast_get_state(cp);
-            if (cmp_state == FILE_IS_CONVERTING) {
-                ErrorLog("cmp_state == FILE_IS_CONVERTING\n");
-                cmp_state = wait_for_decompress(cp);
-                if (cmp_state == FILE_IS_COMPRESSED) {
-                    ErrorLog("cmp_state == FILE_IS_COMPRESSED\n");
-                    /* a decompress was attempted but it failed, let's try fetching again */
-                    goto decompress;
-                }
-            }
-            if (cmp_state == FILE_IS_NOT_COMPRESSED) {
-                ErrorLog("cmp_state == FILE_IS_NOT_COMPRESSED\n");
-                /* the file was decompressed after we started reading it */
-                abort_read = 1;     /* we're not going to commit our data */
-                *is_compressed = 0; /* instruct caller to fall back to its normal path */
-            }
-            kr = KERN_FAILURE;
-            did_read = 0;
-        }
-        /* zero out the remainder of the last page */
-        memset((char*)data + did_read, 0, curUplSize - did_read);
-        kr = ubc_upl_unmap(upl);
-        if (kr == KERN_SUCCESS) {
-            if (abort_read) {
+               VerboseLogWithPath("adjusted uplPos %lld uplSize %lld\n", (uint64_t)uplPos, (uint64_t)uplSize);
+       }
+       lck_rw_unlock_shared(decompressorsLock);
+
+       /* clip the adjusted size to the size of the file */
+       if ((uint64_t)uplPos + uplSize > cachedSize) {
+               /* truncate the read to the size of the file */
+               uplSize = cachedSize - uplPos;
+       }
+
+       if (uplSize <= 0) {
+               /* nothing left */
+               goto out;
+       }
+
+       /*
+        *  since we're going to create a upl for the given region of the file,
+        *  make sure we're on page boundaries
+        */
+
+       if (uplPos & (PAGE_SIZE - 1)) {
+               /* round position down to page boundary */
+               uplSize += (uplPos & (PAGE_SIZE - 1));
+               uplPos &= ~(PAGE_SIZE - 1);
+       }
+       /* round size up to page multiple */
+       uplSize = (uplSize + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
+
+       VerboseLogWithPath("new uplPos %lld uplSize %lld\n", (uint64_t)uplPos, (uint64_t)uplSize);
+
+       uplRemaining = uplSize;
+       curUplPos = uplPos;
+       curUplSize = 0;
+
+       while (uplRemaining > 0) {
+               /* start after the last upl */
+               curUplPos += curUplSize;
+
+               /* clip to max upl size */
+               curUplSize = uplRemaining;
+               if (curUplSize > MAX_UPL_SIZE_BYTES) {
+                       curUplSize = MAX_UPL_SIZE_BYTES;
+               }
+
+               /* create the upl */
+               kr = ubc_create_upl_kernel(vp, curUplPos, curUplSize, &upl, &pli, UPL_SET_LITE, VM_KERN_MEMORY_FILE);
+               if (kr != KERN_SUCCESS) {
+                       ErrorLogWithPath("ubc_create_upl error %d\n", (int)kr);
+                       err = EINVAL;
+                       goto out;
+               }
+               VerboseLogWithPath("curUplPos %lld curUplSize %lld\n", (uint64_t)curUplPos, (uint64_t)curUplSize);
+
+#if CONFIG_IOSCHED
+               /* Mark the UPL as the requesting UPL for decompression */
+               upl_mark_decmp(upl);
+#endif /* CONFIG_IOSCHED */
+
+               /* map the upl */
+               kr = ubc_upl_map(upl, (vm_offset_t*)&data);
+               if (kr != KERN_SUCCESS) {
+                       commit_upl(upl, 0, curUplSize, UPL_ABORT_FREE_ON_EMPTY, 1);
+#if 0
+                       char *path;
+                       MALLOC(path, char *, PATH_MAX, M_TEMP, M_WAITOK);
+                       panic("%s: decmpfs_read_compressed: ubc_upl_map error %d", vnpath(vp, path, PATH_MAX), (int)kr);
+                       FREE(path, M_TEMP);
+#else /* 0 */
+                       ErrorLogWithPath("ubc_upl_map kr=0x%x\n", (int)kr);
+#endif /* 0 */
+                       err = EINVAL;
+                       goto out;
+               }
+
+               /* make sure the map succeeded */
+               if (!data) {
+                       commit_upl(upl, 0, curUplSize, UPL_ABORT_FREE_ON_EMPTY, 1);
+
+                       ErrorLogWithPath("ubc_upl_map mapped null\n");
+                       err = EINVAL;
+                       goto out;
+               }
+
+               /* fetch uncompressed data into the mapped upl */
+               decmpfs_vector vec;
+decompress:
+               vec = (decmpfs_vector){ .buf = data, .size = curUplSize };
+               err = decmpfs_fetch_uncompressed_data(vp, cp, hdr, curUplPos, curUplSize, 1, &vec, &did_read);
+               if (err) {
+                       ErrorLogWithPath("decmpfs_fetch_uncompressed_data err %d\n", err);
+
+                       /* maybe the file is converting to decompressed */
+                       int cmp_state = decmpfs_fast_get_state(cp);
+                       if (cmp_state == FILE_IS_CONVERTING) {
+                               ErrorLogWithPath("cmp_state == FILE_IS_CONVERTING\n");
+                               cmp_state = wait_for_decompress(cp);
+                               if (cmp_state == FILE_IS_COMPRESSED) {
+                                       ErrorLogWithPath("cmp_state == FILE_IS_COMPRESSED\n");
+                                       /* a decompress was attempted but it failed, let's try fetching again */
+                                       goto decompress;
+                               }
+                       }
+                       if (cmp_state == FILE_IS_NOT_COMPRESSED) {
+                               ErrorLogWithPath("cmp_state == FILE_IS_NOT_COMPRESSED\n");
+                               /* the file was decompressed after we started reading it */
+                               abort_read = 1; /* we're not going to commit our data */
+                               *is_compressed = 0; /* instruct caller to fall back to its normal path */
+                       }
+                       kr = KERN_FAILURE;
+                       did_read = 0;
+               }
+               /* zero out the remainder of the last page */
+               memset((char*)data + did_read, 0, curUplSize - did_read);
+               kr = ubc_upl_unmap(upl);
+               if (kr == KERN_SUCCESS) {
+                       if (abort_read) {
                                kr = commit_upl(upl, 0, curUplSize, UPL_ABORT_FREE_ON_EMPTY, 1);
-            } else {
-                VerboseLog("uioPos %lld uioRemaining %lld\n", (uint64_t)uioPos, (uint64_t)uioRemaining);
-                if (uioRemaining) {
-                    off_t uplOff = uioPos - curUplPos;
-                    if (uplOff < 0) {
-                        ErrorLog("uplOff %lld should never be negative\n", (int64_t)uplOff);
-                        err = EINVAL;
-                    } else {
-                        off_t count = curUplPos + curUplSize - uioPos;
-                        if (count < 0) {
-                            /* this upl is entirely before the uio */
-                        } else {
-                            if (count > uioRemaining)
-                                count = uioRemaining;
-                            int io_resid = count;
-                            err = cluster_copy_upl_data(uio, upl, uplOff, &io_resid);
-                            int copied = count - io_resid;
-                            VerboseLog("uplOff %lld count %lld copied %lld\n", (uint64_t)uplOff, (uint64_t)count, (uint64_t)copied);
-                            if (err) {
-                                ErrorLog("cluster_copy_upl_data err %d\n", err);
-                            }
-                            uioPos += copied;
-                            uioRemaining -= copied;
-                        }
-                    }
-                }
+                       } else {
+                               VerboseLogWithPath("uioPos %lld uioRemaining %lld\n", (uint64_t)uioPos, (uint64_t)uioRemaining);
+                               if (uioRemaining) {
+                                       off_t uplOff = uioPos - curUplPos;
+                                       if (uplOff < 0) {
+                                               ErrorLogWithPath("uplOff %lld should never be negative\n", (int64_t)uplOff);
+                                               err = EINVAL;
+                                       } else {
+                                               off_t count = curUplPos + curUplSize - uioPos;
+                                               if (count < 0) {
+                                                       /* this upl is entirely before the uio */
+                                               } else {
+                                                       if (count > uioRemaining) {
+                                                               count = uioRemaining;
+                                                       }
+                                                       int io_resid = count;
+                                                       err = cluster_copy_upl_data(uio, upl, uplOff, &io_resid);
+                                                       int copied = count - io_resid;
+                                                       VerboseLogWithPath("uplOff %lld count %lld copied %lld\n", (uint64_t)uplOff, (uint64_t)count, (uint64_t)copied);
+                                                       if (err) {
+                                                               ErrorLogWithPath("cluster_copy_upl_data err %d\n", err);
+                                                       }
+                                                       uioPos += copied;
+                                                       uioRemaining -= copied;
+                                               }
+                                       }
+                               }
                                kr = commit_upl(upl, 0, curUplSize, UPL_COMMIT_FREE_ON_EMPTY | UPL_COMMIT_INACTIVATE, 0);
-                if (err) {
-                    goto out;
-                }
-            }
-        } else {
-            ErrorLog("ubc_upl_unmap error %d\n", (int)kr);
-        }
-        
-        uplRemaining -= curUplSize;
-    }
-    
+                               if (err) {
+                                       goto out;
+                               }
+                       }
+               } else {
+                       ErrorLogWithPath("ubc_upl_unmap error %d\n", (int)kr);
+               }
+
+               uplRemaining -= curUplSize;
+       }
+
 out:
-    if (hdr) FREE(hdr, M_TEMP);
-       if (cmpdata_locked) decmpfs_unlock_compressed_data(cp, 0);
-    if (err) {/* something went wrong */
-        ErrorLog("err %d\n", err);
-        return err;
-    }
-       
+
+       if (hdr) {
+               FREE(hdr, M_TEMP);
+       }
+       if (cmpdata_locked) {
+               decmpfs_unlock_compressed_data(cp, 0);
+       }
+       if (err) {/* something went wrong */
+               ErrorLogWithPath("err %d\n", err);
+               return err;
+       }
+
 #if COMPRESSION_DEBUG
-    uplSize = uio_resid(uio);
-    if (uplSize)
-        VerboseLog("still %lld bytes to copy\n", uplSize);
+       uplSize = uio_resid(uio);
+       if (uplSize) {
+               VerboseLogWithPath("still %lld bytes to copy\n", uplSize);
+       }
 #endif
-    return 0;
+       return 0;
 }
 
 int
 decmpfs_free_compressed_data(vnode_t vp, decmpfs_cnode *cp)
 {
-    /*
-     call out to the decompressor to free remove any data associated with this compressed file
-     then delete the file's compression xattr
-     */
-    
-    decmpfs_header *hdr = NULL;
-    int err = decmpfs_fetch_compressed_header(vp, cp, &hdr, 0);
-    if (err) {
-        ErrorLog("decmpfs_fetch_compressed_header err %d\n", err);
-    } else {
-        lck_rw_lock_shared(decompressorsLock);
-        decmpfs_free_compressed_data_func free_data = decmp_get_func(hdr->compression_type, free_data);
-        if (free_data) {
+       /*
+        *  call out to the decompressor to free remove any data associated with this compressed file
+        *  then delete the file's compression xattr
+        */
+       decmpfs_header *hdr = NULL;
+
+       /*
+        * Trace the following parameters on entry with event-id 0x03120010.
+        *
+        * @vp->v_id:       vnode-id of the file for which to free compressed data.
+        */
+       DECMPFS_EMIT_TRACE_ENTRY(DECMPDBG_FREE_COMPRESSED_DATA, vp->v_id);
+
+       int err = decmpfs_fetch_compressed_header(vp, cp, &hdr, 0);
+       if (err) {
+               ErrorLogWithPath("decmpfs_fetch_compressed_header err %d\n", err);
+       } else {
+               lck_rw_lock_shared(decompressorsLock);
+               decmpfs_free_compressed_data_func free_data = decmp_get_func(vp, hdr->compression_type, free_data);
+               if (free_data) {
                        err = free_data(vp, decmpfs_ctx, hdr);
-        } else {
-            /* nothing to do, so no error */
-            err = 0;
-        }
-        lck_rw_unlock_shared(decompressorsLock);
-        
-        if (err != 0) {
-            ErrorLog("decompressor err %d\n", err);
-        }
-    }
-    
-    /* delete the xattr */
+               } else {
+                       /* nothing to do, so no error */
+                       err = 0;
+               }
+               lck_rw_unlock_shared(decompressorsLock);
+
+               if (err != 0) {
+                       ErrorLogWithPath("decompressor err %d\n", err);
+               }
+       }
+       /*
+        * Trace the following parameters on return with event-id 0x03120010.
+        *
+        * @vp->v_id:       vnode-id of the file for which to free compressed data.
+        * @err:            value returned from this function.
+        */
+       DECMPFS_EMIT_TRACE_RETURN(DECMPDBG_FREE_COMPRESSED_DATA, vp->v_id, err);
+
+       /* delete the xattr */
        err = vn_removexattr(vp, DECMPFS_XATTR_NAME, 0, decmpfs_ctx);
-    if (err != 0) {
-        goto out;
-    }
-    
+       if (err != 0) {
+               goto out;
+       }
+
 out:
-    if (hdr) FREE(hdr, M_TEMP);
-    return err;
+       if (hdr) {
+               FREE(hdr, M_TEMP);
+       }
+       return err;
 }
 
 #pragma mark --- file conversion routines ---
@@ -1459,34 +1771,34 @@ out:
 static int
 unset_compressed_flag(vnode_t vp)
 {
-    int err = 0;
-    struct vnode_attr va;
-    int new_bsdflags = 0;
-    
-    VATTR_INIT(&va);
-    VATTR_WANTED(&va, va_flags);
+       int err = 0;
+       struct vnode_attr va;
+       int new_bsdflags = 0;
+
+       VATTR_INIT(&va);
+       VATTR_WANTED(&va, va_flags);
        err = vnode_getattr(vp, &va, decmpfs_ctx);
-    
-    if (err != 0) {
-        ErrorLog("vnode_getattr err %d\n", err);
-    } else {
-        new_bsdflags = va.va_flags & ~UF_COMPRESSED;
-        
-        VATTR_INIT(&va);
-        VATTR_SET(&va, va_flags, new_bsdflags);
+
+       if (err != 0) {
+               ErrorLogWithPath("vnode_getattr err %d\n", err);
+       } else {
+               new_bsdflags = va.va_flags & ~UF_COMPRESSED;
+
+               VATTR_INIT(&va);
+               VATTR_SET(&va, va_flags, new_bsdflags);
                err = vnode_setattr(vp, &va, decmpfs_ctx);
-        if (err != 0) {
-            ErrorLog("vnode_setattr err %d\n", err);
-        }
-    }
-    return err;
+               if (err != 0) {
+                       ErrorLogWithPath("vnode_setattr err %d\n", err);
+               }
+       }
+       return err;
 }
 
 int
 decmpfs_decompress_file(vnode_t vp, decmpfs_cnode *cp, off_t toSize, int truncate_okay, int skiplock)
 {
        /* convert a compressed file to an uncompressed file */
-       
+
        int err                      = 0;
        char *data                   = NULL;
        uio_t uio_w                  = 0;
@@ -1495,62 +1807,76 @@ decmpfs_decompress_file(vnode_t vp, decmpfs_cnode *cp, off_t toSize, int truncat
        uint32_t new_state           = 0;
        int update_file_state        = 0;
        int allocSize                = 0;
-       decmpfs_header *hdr = NULL;
+       decmpfs_header *hdr          = NULL;
        int cmpdata_locked           = 0;
        off_t remaining              = 0;
        uint64_t uncompressed_size   = 0;
-       
+
+       /*
+        * Trace the following parameters on entry with event-id 0x03120000.
+        *
+        * @vp->v_id:           vnode-id of the file being decompressed.
+        * @toSize:             uncompress given bytes of the file.
+        * @truncate_okay:      on error it is OK to truncate.
+        * @skiplock:           compressed data is locked, skip locking again.
+        *
+        * Please NOTE: @toSize can overflow in theory but here it is safe.
+        */
+       DECMPFS_EMIT_TRACE_ENTRY(DECMPDBG_DECOMPRESS_FILE, vp->v_id,
+           (int)toSize, truncate_okay, skiplock);
+
        if (!skiplock) {
                decmpfs_lock_compressed_data(cp, 1); cmpdata_locked = 1;
        }
-       
+
 decompress:
        old_state = decmpfs_fast_get_state(cp);
-       
-       switch(old_state) {
-               case FILE_IS_NOT_COMPRESSED:
-               {
-                       /* someone else decompressed the file */
-                       err = 0;
-                       goto out;
-               }
-                       
-               case FILE_TYPE_UNKNOWN:
-               {
-                       /* the file is in an unknown state, so update the state and retry */
-                       (void)decmpfs_file_is_compressed(vp, cp);
-                       
-                       /* try again */
-                       goto decompress;
-               }
-                       
-               case FILE_IS_COMPRESSED:
-               {
-                       /* the file is compressed, so decompress it */
-                       break;
-               }
-                       
-               default:
-               {
-                       /*
-                        this shouldn't happen since multiple calls to decmpfs_decompress_file lock each other out,
-                        and when decmpfs_decompress_file returns, the state should be always be set back to
-                        FILE_IS_NOT_COMPRESSED or FILE_IS_UNKNOWN
-                        */
-                       err = EINVAL;
-                       goto out;
-               }
+
+       switch (old_state) {
+       case FILE_IS_NOT_COMPRESSED:
+       {
+               /* someone else decompressed the file */
+               err = 0;
+               goto out;
+       }
+
+       case FILE_TYPE_UNKNOWN:
+       {
+               /* the file is in an unknown state, so update the state and retry */
+               (void)decmpfs_file_is_compressed(vp, cp);
+
+               /* try again */
+               goto decompress;
+       }
+
+       case FILE_IS_COMPRESSED:
+       {
+               /* the file is compressed, so decompress it */
+               break;
        }
-       
-    err = decmpfs_fetch_compressed_header(vp, cp, &hdr, 0);
+
+       default:
+       {
+               /*
+                *  this shouldn't happen since multiple calls to decmpfs_decompress_file lock each other out,
+                *  and when decmpfs_decompress_file returns, the state should be always be set back to
+                *  FILE_IS_NOT_COMPRESSED or FILE_IS_UNKNOWN
+                */
+               err = EINVAL;
+               goto out;
+       }
+       }
+
+       err = decmpfs_fetch_compressed_header(vp, cp, &hdr, 0);
        if (err != 0) {
                goto out;
        }
-       
+
        uncompressed_size = hdr->uncompressed_size;
-       if (toSize == -1)
+       if (toSize == -1) {
                toSize = hdr->uncompressed_size;
-       
+       }
+
        if (toSize == 0) {
                /* special case truncating the file to zero bytes */
                goto nodecmp;
@@ -1558,126 +1884,132 @@ decompress:
                /* the caller is trying to grow the file, so we should decompress all the data */
                toSize = hdr->uncompressed_size;
        }
-       
-       allocSize = MIN(64*1024, toSize);
+
+       allocSize = MIN(64 * 1024, toSize);
        MALLOC(data, char *, allocSize, M_TEMP, M_WAITOK);
        if (!data) {
                err = ENOMEM;
                goto out;
        }
-       
+
        uio_w = uio_create(1, 0LL, UIO_SYSSPACE, UIO_WRITE);
        if (!uio_w) {
                err = ENOMEM;
                goto out;
        }
        uio_w->uio_flags |= UIO_FLAGS_IS_COMPRESSED_FILE;
-       
+
        remaining = toSize;
-       
+
        /* tell the buffer cache that this is an empty file */
        ubc_setsize(vp, 0);
-       
+
        /* if we got here, we need to decompress the file */
        decmpfs_cnode_set_vnode_state(cp, FILE_IS_CONVERTING, 1);
-       
-       while(remaining > 0) {
+
+       while (remaining > 0) {
                /* loop decompressing data from the file and writing it into the data fork */
-               
+
                uint64_t bytes_read = 0;
                decmpfs_vector vec = { .buf = data, .size = MIN(allocSize, remaining) };
                err = decmpfs_fetch_uncompressed_data(vp, cp, hdr, offset, vec.size, 1, &vec, &bytes_read);
                if (err != 0) {
-                       ErrorLog("decmpfs_fetch_uncompressed_data err %d\n", err);
+                       ErrorLogWithPath("decmpfs_fetch_uncompressed_data err %d\n", err);
                        goto out;
                }
-               
+
                if (bytes_read == 0) {
                        /* we're done reading data */
                        break;
                }
-               
+
                uio_reset(uio_w, offset, UIO_SYSSPACE, UIO_WRITE);
                err = uio_addiov(uio_w, CAST_USER_ADDR_T(data), bytes_read);
                if (err != 0) {
-                       ErrorLog("uio_addiov err %d\n", err);
+                       ErrorLogWithPath("uio_addiov err %d\n", err);
                        err = ENOMEM;
                        goto out;
                }
-               
+
                err = VNOP_WRITE(vp, uio_w, 0, decmpfs_ctx);
                if (err != 0) {
                        /* if the write failed, truncate the file to zero bytes */
-                       ErrorLog("VNOP_WRITE err %d\n", err);
+                       ErrorLogWithPath("VNOP_WRITE err %d\n", err);
                        break;
                }
                offset += bytes_read;
                remaining -= bytes_read;
        }
-       
+
        if (err == 0) {
                if (offset != toSize) {
-                       ErrorLog("file decompressed to %lld instead of %lld\n", offset, toSize);
+                       ErrorLogWithPath("file decompressed to %lld instead of %lld\n", offset, toSize);
                        err = EINVAL;
                        goto out;
                }
        }
-       
+
        if (err == 0) {
                /* sync the data and metadata */
                err = VNOP_FSYNC(vp, MNT_WAIT, decmpfs_ctx);
                if (err != 0) {
-                       ErrorLog("VNOP_FSYNC err %d\n", err);
+                       ErrorLogWithPath("VNOP_FSYNC err %d\n", err);
                        goto out;
                }
        }
-       
+
        if (err != 0) {
                /* write, setattr, or fsync failed */
-               ErrorLog("aborting decompress, err %d\n", err);
+               ErrorLogWithPath("aborting decompress, err %d\n", err);
                if (truncate_okay) {
                        /* truncate anything we might have written */
                        int error = vnode_setsize(vp, 0, 0, decmpfs_ctx);
-                       ErrorLog("vnode_setsize err %d\n", error);
+                       ErrorLogWithPath("vnode_setsize err %d\n", error);
                }
                goto out;
        }
-       
+
 nodecmp:
        /* if we're truncating the file to zero bytes, we'll skip ahead to here */
-       
+
        /* unset the compressed flag */
        unset_compressed_flag(vp);
-       
+
        /* free the compressed data associated with this file */
        err = decmpfs_free_compressed_data(vp, cp);
        if (err != 0) {
-               ErrorLog("decmpfs_free_compressed_data err %d\n", err);
+               ErrorLogWithPath("decmpfs_free_compressed_data err %d\n", err);
        }
-       
+
        /*
-        even if free_compressed_data or vnode_getattr/vnode_setattr failed, return success
-        since we succeeded in writing all of the file data to the data fork
+        *  even if free_compressed_data or vnode_getattr/vnode_setattr failed, return success
+        *  since we succeeded in writing all of the file data to the data fork
         */
        err = 0;
-       
+
        /* if we got this far, the file was successfully decompressed */
        update_file_state = 1;
        new_state = FILE_IS_NOT_COMPRESSED;
-       
+
 #if COMPRESSION_DEBUG
        {
                uint64_t filesize = 0;
                vnsize(vp, &filesize);
-               DebugLog("new file size %lld\n", filesize);
+               DebugLogWithPath("new file size %lld\n", filesize);
        }
 #endif
-       
+
 out:
-       if (hdr) FREE(hdr, M_TEMP);
-       if (data) FREE(data, M_TEMP);
-       if (uio_w) uio_free(uio_w);
-       
+       if (hdr) {
+               FREE(hdr, M_TEMP);
+       }
+       if (data) {
+               FREE(data, M_TEMP);
+       }
+       if (uio_w) {
+               uio_free(uio_w);
+       }
+
        if (err != 0) {
                /* if there was a failure, reset compression flags to unknown and clear the buffer cache data */
                update_file_state = 1;
@@ -1685,101 +2017,114 @@ out:
                if (uncompressed_size) {
                        ubc_setsize(vp, 0);
                        ubc_setsize(vp, uncompressed_size);
-        }
+               }
        }
-       
+
        if (update_file_state) {
                lck_mtx_lock(decompress_channel_mtx);
                decmpfs_cnode_set_vnode_state(cp, new_state, 1);
                wakeup((caddr_t)&decompress_channel); /* wake up anyone who might have been waiting for decompression */
                lck_mtx_unlock(decompress_channel_mtx);
        }
-       
-       if (cmpdata_locked) decmpfs_unlock_compressed_data(cp, 1);
-       
+
+       if (cmpdata_locked) {
+               decmpfs_unlock_compressed_data(cp, 1);
+       }
+       /*
+        * Trace the following parameters on return with event-id 0x03120000.
+        *
+        * @vp->v_id:   vnode-id of the file being decompressed.
+        * @err:        value returned from this function.
+        */
+       DECMPFS_EMIT_TRACE_RETURN(DECMPDBG_DECOMPRESS_FILE, vp->v_id, err);
        return err;
 }
 
 #pragma mark --- Type1 compressor ---
 
 /*
- The "Type1" compressor stores the data fork directly in the compression xattr
*  The "Type1" compressor stores the data fork directly in the compression xattr
  */
 
 static int
 decmpfs_validate_compressed_file_Type1(__unused vnode_t vp, __unused vfs_context_t ctx, decmpfs_header *hdr)
 {
-    int err          = 0;
-    
-    if (hdr->uncompressed_size + sizeof(decmpfs_disk_header) != (uint64_t)hdr->attr_size) {
-        err = EINVAL;
-        goto out;
-    }
+       int err          = 0;
+
+       if (hdr->uncompressed_size + sizeof(decmpfs_disk_header) != (uint64_t)hdr->attr_size) {
+               err = EINVAL;
+               goto out;
+       }
 out:
-    return err;    
+       return err;
 }
 
 static int
 decmpfs_fetch_uncompressed_data_Type1(__unused vnode_t vp, __unused vfs_context_t ctx, decmpfs_header *hdr, off_t offset, user_ssize_t size, int nvec, decmpfs_vector *vec, uint64_t *bytes_read)
 {
-    int err          = 0;
-    int i;
-    user_ssize_t remaining;
-    
-    if (hdr->uncompressed_size + sizeof(decmpfs_disk_header) != (uint64_t)hdr->attr_size) {
-        err = EINVAL;
-        goto out;
-    }
-    
+       int err          = 0;
+       int i;
+       user_ssize_t remaining;
+
+       if (hdr->uncompressed_size + sizeof(decmpfs_disk_header) != (uint64_t)hdr->attr_size) {
+               err = EINVAL;
+               goto out;
+       }
+
 #if COMPRESSION_DEBUG
-    static int dummy = 0; // prevent syslog from coalescing printfs
-    char path[PATH_MAX];
-    DebugLog("%s: %d memcpy %lld at %lld\n", vnpath(vp, path, sizeof(path)), dummy++, size, (uint64_t)offset);
+       static int dummy = 0; // prevent syslog from coalescing printfs
+       DebugLogWithPath("%d memcpy %lld at %lld\n", dummy++, size, (uint64_t)offset);
 #endif
-    
-    remaining = size;
-    for (i = 0; (i < nvec) && (remaining > 0); i++) {
-        user_ssize_t curCopy = vec[i].size;
-        if (curCopy > remaining)
-            curCopy = remaining;
-        memcpy(vec[i].buf, hdr->attr_bytes + offset, curCopy);
-        offset += curCopy;
-        remaining -= curCopy;
-    }
-    
-    if ((bytes_read) && (err == 0))
-        *bytes_read = (size - remaining);
-    
+
+       remaining = size;
+       for (i = 0; (i < nvec) && (remaining > 0); i++) {
+               user_ssize_t curCopy = vec[i].size;
+               if (curCopy > remaining) {
+                       curCopy = remaining;
+               }
+               memcpy(vec[i].buf, hdr->attr_bytes + offset, curCopy);
+               offset += curCopy;
+               remaining -= curCopy;
+       }
+
+       if ((bytes_read) && (err == 0)) {
+               *bytes_read = (size - remaining);
+       }
+
 out:
-    return err;
+       return err;
 }
 
-static decmpfs_registration Type1Reg =
+SECURITY_READ_ONLY_EARLY(static decmpfs_registration) Type1Reg =
 {
-    .decmpfs_registration = DECMPFS_REGISTRATION_VERSION,
-    .validate          = decmpfs_validate_compressed_file_Type1,
-    .adjust_fetch      = NULL, /* no adjust necessary */
-    .fetch             = decmpfs_fetch_uncompressed_data_Type1,
-    .free_data         = NULL, /* no free necessary */
-    .get_flags         = NULL  /* no flags */
+       .decmpfs_registration = DECMPFS_REGISTRATION_VERSION,
+       .validate          = decmpfs_validate_compressed_file_Type1,
+       .adjust_fetch      = NULL,/* no adjust necessary */
+       .fetch             = decmpfs_fetch_uncompressed_data_Type1,
+       .free_data         = NULL,/* no free necessary */
+       .get_flags         = NULL/* no flags */
 };
 
 #pragma mark --- decmpfs initialization ---
 
-void decmpfs_init()
+void
+decmpfs_init()
 {
-    static int done = 0;
-    if (done) return;
-    
+       static int done = 0;
+       if (done) {
+               return;
+       }
+
        decmpfs_ctx = vfs_context_create(vfs_context_kernel());
-       
-    lck_grp_attr_t *attr = lck_grp_attr_alloc_init();
-    decmpfs_lockgrp = lck_grp_alloc_init("VFSCOMP",  attr);
-    decompressorsLock = lck_rw_alloc_init(decmpfs_lockgrp, NULL);
-    decompress_channel_mtx = lck_mtx_alloc_init(decmpfs_lockgrp, NULL);
-    
-    register_decmpfs_decompressor(CMP_Type1, &Type1Reg);
-    
-    done = 1;
+
+       lck_grp_attr_t *attr = lck_grp_attr_alloc_init();
+       decmpfs_lockgrp = lck_grp_alloc_init("VFSCOMP", attr);
+       lck_grp_attr_free(attr);
+       decompressorsLock = lck_rw_alloc_init(decmpfs_lockgrp, NULL);
+       decompress_channel_mtx = lck_mtx_alloc_init(decmpfs_lockgrp, NULL);
+
+       register_decmpfs_decompressor(CMP_Type1, &Type1Reg);
+
+       done = 1;
 }
-#endif /* HFS_COMPRESSION */
+#endif /* FS_COMPRESSION */