#define COMPRESSION_DEBUG_VERBOSE 0
#define MALLOC_DEBUG 0
-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 COMPRESSION_DEBUG
static char*
vnpath(vnode_t vp, char *path, int len)
}
#endif
-#define ErrorLog(x, args...) printf("%s:%d:%s: " x, baseName(__FILE__), __LINE__, __FUNCTION__, ## args)
+#define ErrorLog(x, args...) \
+ printf("%s:%d:%s: " x, __FILE_NAME__, __LINE__, __FUNCTION__, ## args)
#if COMPRESSION_DEBUG
-#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)
+#define ErrorLogWithPath(x, args...) do { \
+ char *path = zalloc(ZV_NAMEI); \
+ printf("%s:%d:%s: %s: " x, __FILE_NAME__, __LINE__, __FUNCTION__, \
+ vnpath(vp, path, PATH_MAX), ## args); \
+ zfree(ZV_NAMEI, path); \
+} while(0)
#else
-#define ErrorLogWithPath(x, args...) do { (void*)vp; printf("%s:%d:%s: %s: " x, baseName(__FILE__), __LINE__, __FUNCTION__, "<private>", ## args); } while(0)
+#define ErrorLogWithPath(x, args...) do { \
+ (void*)vp; \
+ printf("%s:%d:%s: %s: " x, __FILE_NAME__, __LINE__, __FUNCTION__, \
+ "<private>", ## args); \
+} while(0)
#endif
#if COMPRESSION_DEBUG
#define VerboseLogWithPath(x...) do { } while(0)
#endif
-#if MALLOC_DEBUG
-
-static SInt32 totalAlloc;
-
-typedef struct {
- 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;
-}
-
-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);
-}
-
-#undef MALLOC
-#undef FREE
-#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 */
-
#pragma mark --- globals ---
-static lck_grp_t *decmpfs_lockgrp;
+static LCK_GRP_DECLARE(decmpfs_lockgrp, "VFSCOMP");
+static LCK_RW_DECLARE(decompressorsLock, &decmpfs_lockgrp);
+static LCK_MTX_DECLARE(decompress_channel_mtx, &decmpfs_lockgrp);
static const 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;
vfs_context_t decmpfs_ctx;
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
+ lck_rw_unlock_shared(&decompressorsLock); // we have to unlock to allow the kext to register
if (IOServiceWaitForMatchingResource(resourceName, delay)) {
- lck_rw_lock_shared(decompressorsLock);
+ 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);
+ lck_rw_lock_shared(&decompressorsLock);
break;
}
ErrorLogWithPath("still waiting for %s\n", resourceName);
delay *= 2;
- lck_rw_lock_shared(decompressorsLock);
+ lck_rw_lock_shared(&decompressorsLock);
}
// IOKit says the kext is loaded, so it should be registered too!
if (decompressors[type] == NULL) {
decmpfs_cnode_init(decmpfs_cnode *cp)
{
memset(cp, 0, sizeof(*cp));
- lck_rw_init(&cp->compressed_data_lock, decmpfs_lockgrp, NULL);
+ lck_rw_init(&cp->compressed_data_lock, &decmpfs_lockgrp, NULL);
}
void
decmpfs_cnode_destroy(decmpfs_cnode *cp)
{
- lck_rw_destroy(&cp->compressed_data_lock, decmpfs_lockgrp);
+ lck_rw_destroy(&cp->compressed_data_lock, &decmpfs_lockgrp);
}
bool
#pragma mark --- decmpfs state routines ---
static int
-decmpfs_fetch_compressed_header(vnode_t vp, decmpfs_cnode *cp, decmpfs_header **hdrOut, int returnInvalid)
+decmpfs_fetch_compressed_header(vnode_t vp, decmpfs_cnode *cp, decmpfs_header **hdrOut, int returnInvalid, size_t *hdr_size)
{
/*
* fetches vp's compression xattr, converting it into a decmpfs_header; returns 0 or errno
size_t read_size = 0;
size_t attr_size = 0;
+ size_t alloc_size = 0;
uio_t attr_uio = NULL;
int err = 0;
char *data = NULL;
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);
+ alloc_size = sizeof(decmpfs_header);
+ data = kheap_alloc(KHEAP_TEMP, alloc_size, Z_WAITOK);
if (!data) {
err = ENOMEM;
goto out;
if (err != 0) {
goto out;
}
+ alloc_size = attr_size + sizeof(hdr->attr_size);
if (attr_size < sizeof(decmpfs_disk_header) || attr_size > MAX_DECMPFS_XATTR_SIZE) {
err = EINVAL;
}
/* 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);
+ data = kheap_alloc(KHEAP_TEMP, alloc_size, Z_WAITOK);
if (!data) {
err = ENOMEM;
goto out;
out:
if (err && (err != ERANGE)) {
DebugLogWithPath("err %d\n", err);
- if (data) {
- FREE(data, M_TEMP);
- }
+ kheap_free(KHEAP_TEMP, data, alloc_size);
*hdrOut = NULL;
} else {
*hdrOut = hdr;
+ *hdr_size = alloc_size;
}
/*
* Trace the following parameters on return with event-id 0x03120004.
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);
+ size_t alloc_size = 0;
+ errno_t err = decmpfs_fetch_compressed_header(vp, cp, &hdr, 0, &alloc_size);
+
if (err) {
/* we couldn't get the header */
if (decmpfs_fast_get_state(cp) == FILE_IS_NOT_COMPRESSED) {
}
if (!decmpfs_type_is_dataless(hdr->compression_type)) {
- lck_rw_lock_shared(decompressorsLock);
+ 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? */
/* no validate registered, so nothing to do */
err = 0;
}
- lck_rw_unlock_shared(decompressorsLock);
+ lck_rw_unlock_shared(&decompressorsLock);
}
out:
- if (hdr) {
- FREE(hdr, M_TEMP);
+ if (hdr != NULL) {
+ kheap_free(KHEAP_TEMP, hdr, alloc_size);
}
#if COMPRESSION_DEBUG
if (err) {
uint32_t cmp_state;
struct vnode_attr va_fetch;
decmpfs_header *hdr = NULL;
+ size_t alloc_size = 0;
mount_t mp = NULL;
int cnode_locked = 0;
int saveInvalid = 0; // save the header data even though the type was out of range
}
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);
+ error = decmpfs_fetch_compressed_header(vp, cp, &hdr, 1, &alloc_size);
if ((hdr != NULL) && (error == ERANGE)) {
saveInvalid = 1;
}
ubc_setsize(vp, hdr->uncompressed_size);
/* update the decompression flags in the decmpfs cnode */
- lck_rw_lock_shared(decompressorsLock);
+ 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);
+ lck_rw_unlock_shared(&decompressorsLock);
decmpfs_cnode_set_decompression_flags(cp, decompression_flags);
}
} else {
decmpfs_unlock_compressed_data(cp, 1);
}
- if (hdr) {
- FREE(hdr, M_TEMP);
+ if (hdr != NULL) {
+ kheap_free(KHEAP_TEMP, hdr, alloc_size);
}
+
/*
* Trace the following parameters on return with event-id 0x03120014.
*
}
decmpfs_header *hdr = NULL;
- error = decmpfs_fetch_compressed_header(vp, NULL, &hdr, 1);
+ size_t alloc_size = 0;
+ error = decmpfs_fetch_compressed_header(vp, NULL, &hdr, 1, &alloc_size);
if (error == 0) {
/*
* Allow the flag to be set since the decmpfs attribute
/* no DECMPFS_XATTR_NAME attribute, so deny the update */
vap->va_flags &= ~UF_COMPRESSED;
}
- if (hdr) {
- FREE(hdr, M_TEMP);
+ if (hdr != NULL) {
+ kheap_free(KHEAP_TEMP, hdr, alloc_size);
}
}
}
wait_for_decompress(decmpfs_cnode *cp)
{
int state;
- lck_mtx_lock(decompress_channel_mtx);
+ 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);
+ lck_mtx_unlock(&decompress_channel_mtx);
return state;
}
- msleep((caddr_t)&decompress_channel, decompress_channel_mtx, PINOD, "wait_for_decompress", NULL);
+ msleep((caddr_t)&decompress_channel, &decompress_channel_mtx, PINOD, "wait_for_decompress", NULL);
} while (1);
}
goto out;
}
- lck_rw_lock_exclusive(decompressorsLock); locked = 1;
+ lck_rw_lock_exclusive(&decompressorsLock); locked = 1;
/* make sure the registration for this type is zero */
if (decompressors[compression_type] != NULL) {
out:
if (locked) {
- lck_rw_unlock_exclusive(decompressorsLock);
+ lck_rw_unlock_exclusive(&decompressorsLock);
}
return ret;
}
goto out;
}
- lck_rw_lock_exclusive(decompressorsLock); locked = 1;
+ lck_rw_lock_exclusive(&decompressorsLock); locked = 1;
if (decompressors[compression_type] != registration) {
ret = EEXIST;
goto out;
out:
if (locked) {
- lck_rw_unlock_exclusive(decompressorsLock);
+ lck_rw_unlock_exclusive(&decompressorsLock);
}
return ret;
}
int ret = 0;
/* every compressor must have at least a fetch function */
- lck_rw_lock_shared(decompressorsLock);
+ lck_rw_lock_shared(&decompressorsLock);
if (decmp_get_func(vp, hdr->compression_type, fetch) != NULL) {
ret = 1;
}
- lck_rw_unlock_shared(decompressorsLock);
+ lck_rw_unlock_shared(&decompressorsLock);
return ret;
}
*/
DECMPFS_EMIT_TRACE_ENTRY(DECMPDBG_FETCH_UNCOMPRESSED_DATA, vp->v_id,
hdr->compression_type, (int)offset, (int)size);
- lck_rw_lock_shared(decompressorsLock);
+ 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);
+ 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) {
}
} else {
err = ENOTSUP;
- lck_rw_unlock_shared(decompressorsLock);
+ lck_rw_unlock_shared(&decompressorsLock);
}
/*
* Trace the following parameters on return with event-id 0x03120008.
size_t verify_block_size = 0;
void *data = NULL;
decmpfs_header *hdr = NULL;
+ size_t alloc_size = 0;
uint64_t cachedSize = 0;
int cmpdata_locked = 0;
bool file_tail_page_valid = false;
DebugLogWithPath("pagein: unknown flags 0x%08x\n", (flags & ~(UPL_IOSYNC | UPL_NOCOMMIT | UPL_NORDAHEAD)));
}
- err = decmpfs_fetch_compressed_header(vp, cp, &hdr, 0);
+ err = decmpfs_fetch_compressed_header(vp, cp, &hdr, 0, &alloc_size);
if (err != 0) {
goto out;
}
if (data) {
ubc_upl_unmap(pl);
}
- if (hdr) {
- FREE(hdr, M_TEMP);
+ if (hdr != NULL) {
+ kheap_free(KHEAP_TEMP, hdr, alloc_size);
}
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);
+ char *path = zalloc(ZV_NAMEI);
panic("%s: decmpfs_pagein_compressed: err %d", vnpath(vp, path, PATH_MAX), err);
- FREE(path, M_TEMP);
+ zfree(ZV_NAMEI, path);
}
#endif /* 0 */
ErrorLogWithPath("err %d\n", err);
upl_t upl = NULL;
upl_page_info_t *pli = NULL;
decmpfs_header *hdr = NULL;
+ size_t alloc_size = 0;
uint64_t cachedSize = 0;
off_t uioPos = 0;
user_ssize_t uioRemaining = 0;
goto out;
}
- err = decmpfs_fetch_compressed_header(vp, cp, &hdr, 0);
+ err = decmpfs_fetch_compressed_header(vp, cp, &hdr, 0, &alloc_size);
if (err != 0) {
goto out;
}
DebugLogWithPath("uplPos %lld uplSize %lld\n", (uint64_t)uplPos, (uint64_t)uplSize);
#endif
- lck_rw_lock_shared(decompressorsLock);
+ 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);
VerboseLogWithPath("adjusted uplPos %lld uplSize %lld\n", (uint64_t)uplPos, (uint64_t)uplSize);
}
- lck_rw_unlock_shared(decompressorsLock);
+ lck_rw_unlock_shared(&decompressorsLock);
/* clip the adjusted size to the size of the file */
if ((uint64_t)uplPos + uplSize > cachedSize) {
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);
+ char *path = zalloc(ZV_NAMEI);
panic("%s: decmpfs_read_compressed: ubc_upl_map error %d", vnpath(vp, path, PATH_MAX), (int)kr);
- FREE(path, M_TEMP);
+ zfree(ZV_NAMEI, path);
#else /* 0 */
ErrorLogWithPath("ubc_upl_map kr=0x%x\n", (int)kr);
#endif /* 0 */
out:
- if (hdr) {
- FREE(hdr, M_TEMP);
+ if (hdr != NULL) {
+ kheap_free(KHEAP_TEMP, hdr, alloc_size);
}
if (cmpdata_locked) {
decmpfs_unlock_compressed_data(cp, 0);
* then delete the file's compression xattr
*/
decmpfs_header *hdr = NULL;
+ size_t alloc_size = 0;
/*
* Trace the following parameters on entry with event-id 0x03120010.
*/
DECMPFS_EMIT_TRACE_ENTRY(DECMPDBG_FREE_COMPRESSED_DATA, vp->v_id);
- int err = decmpfs_fetch_compressed_header(vp, cp, &hdr, 0);
+ int err = decmpfs_fetch_compressed_header(vp, cp, &hdr, 0, &alloc_size);
if (err) {
ErrorLogWithPath("decmpfs_fetch_compressed_header err %d\n", err);
} else {
- lck_rw_lock_shared(decompressorsLock);
+ 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);
/* nothing to do, so no error */
err = 0;
}
- lck_rw_unlock_shared(decompressorsLock);
+ lck_rw_unlock_shared(&decompressorsLock);
if (err != 0) {
ErrorLogWithPath("decompressor err %d\n", err);
/* delete the xattr */
err = vn_removexattr(vp, DECMPFS_XATTR_NAME, 0, decmpfs_ctx);
- if (err != 0) {
- goto out;
- }
-out:
- if (hdr) {
- FREE(hdr, M_TEMP);
+ if (hdr != NULL) {
+ kheap_free(KHEAP_TEMP, hdr, alloc_size);
}
return err;
}
int update_file_state = 0;
size_t allocSize = 0;
decmpfs_header *hdr = NULL;
+ size_t hdr_size = 0;
int cmpdata_locked = 0;
off_t remaining = 0;
uint64_t uncompressed_size = 0;
}
}
- err = decmpfs_fetch_compressed_header(vp, cp, &hdr, 0);
+ err = decmpfs_fetch_compressed_header(vp, cp, &hdr, 0, &hdr_size);
if (err != 0) {
goto out;
}
}
allocSize = MIN(64 * 1024, (size_t)toSize);
- MALLOC(data, char *, allocSize, M_TEMP, M_WAITOK);
+ data = kheap_alloc(KHEAP_TEMP, allocSize, Z_WAITOK);
if (!data) {
err = ENOMEM;
goto out;
#endif
out:
- if (hdr) {
- FREE(hdr, M_TEMP);
- }
- if (data) {
- FREE(data, M_TEMP);
+ if (hdr != NULL) {
+ kheap_free(KHEAP_TEMP, hdr, hdr_size);
}
+ kheap_free(KHEAP_TEMP, data, allocSize);
if (uio_w) {
uio_free(uio_w);
}
}
if (update_file_state) {
- lck_mtx_lock(decompress_channel_mtx);
+ 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);
+ lck_mtx_unlock(&decompress_channel_mtx);
}
if (cmpdata_locked) {
#pragma mark --- decmpfs initialization ---
void
-decmpfs_init()
+decmpfs_init(void)
{
static int done = 0;
if (done) {
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);
- 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;