#define offsetof_func(func) ((uintptr_t)(&(((decmpfs_registration*)NULL)->func)))
static void *
-_func_from_offset(uint32_t type, int offset)
+_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 = ®Char[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];
}
extern boolean_t IOCatalogueMatchingDriversPresent( const char * property );
static void *
-_decmp_get_func(uint32_t type, int offset)
+_decmp_get_func(uint32_t type, uintptr_t offset)
{
/*
this function should be called while holding a shared lock to decompressorsLock,
snprintf(resourceName, sizeof(resourceName), "com.apple.AppleFSCompression.Type%u", type);
printf("waiting for %s\n", resourceName);
while(decompressors[type] == NULL) {
- lck_rw_done(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);
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);
{
memset(cp, 0, sizeof(*cp));
lck_rw_init(&cp->compressed_data_lock, decmpfs_lockgrp, NULL);
-#if !DECMPFS_SUPPORTS_SWAP64
- lck_mtx_init(&cp->uncompressed_size_mtx, decmpfs_lockgrp, NULL);
-#endif
}
void
decmpfs_cnode_destroy(decmpfs_cnode *cp)
{
lck_rw_destroy(&cp->compressed_data_lock, decmpfs_lockgrp);
-#if !DECMPFS_SUPPORTS_SWAP64
- lck_mtx_destroy(&cp->uncompressed_size_mtx, decmpfs_lockgrp);
-#endif
}
boolean_t
uint64_t
decmpfs_cnode_get_vnode_cached_size(decmpfs_cnode *cp)
{
-#if DECMPFS_SUPPORTS_SWAP64
return cp->uncompressed_size;
-#else
- /*
- since this is a 64-bit field, we may not be able to access it atomically
- so lock access
- */
-
- lck_mtx_lock(&(cp->uncompressed_size_mtx));
- uint64_t ret = cp->uncompressed_size;
- lck_mtx_unlock(&(cp->uncompressed_size_mtx));
- return ret;
-#endif
}
static void
decmpfs_cnode_set_vnode_cached_size(decmpfs_cnode *cp, uint64_t size)
{
-#if DECMPFS_SUPPORTS_SWAP64
while(1) {
uint64_t old = cp->uncompressed_size;
if (OSCompareAndSwap64(old, size, (UInt64*)&cp->uncompressed_size)) {
/* failed to write our value, so loop */
}
}
-#else
- /*
- since this is a 64-bit field, we may not be able to access it atomically
- so lock access
- */
-
- lck_mtx_lock(&(cp->uncompressed_size_mtx));
- cp->uncompressed_size = size;
- lck_mtx_unlock(&(cp->uncompressed_size_mtx));
-#endif
+}
+
+static uint64_t
+decmpfs_cnode_get_decompression_flags(decmpfs_cnode *cp)
+{
+ 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 */
+ }
+ }
}
#pragma mark --- decmpfs state routines ---
/* no validate registered, so nothing to do */
err = 0;
}
- lck_rw_done(decompressorsLock);
+ lck_rw_unlock_shared(decompressorsLock);
out:
if (hdr) FREE(hdr, M_TEMP);
#if COMPRESSION_DEBUG
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)) {
/*
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);
}
} else {
/* we might have already taken the lock above; if so, skip taking it again by passing cnode_locked as the skiplock parameter */
#pragma mark --- registration/validation routines ---
+static inline int registration_valid(decmpfs_registration *registration)
+{
+ 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)
{
int locked = 0;
char resourceName[80];
- if ((compression_type >= CMP_MAX) ||
- (!registration) ||
- (registration->decmpfs_registration != DECMPFS_REGISTRATION_VERSION)) {
+ if ((compression_type >= CMP_MAX) || !registration_valid(registration)) {
ret = EINVAL;
goto out;
}
decompressors[compression_type] = registration;
snprintf(resourceName, sizeof(resourceName), "com.apple.AppleFSCompression.Type%u", compression_type);
IOServicePublishResource(resourceName, TRUE);
- wakeup((caddr_t)&decompressors);
out:
- if (locked) lck_rw_done(decompressorsLock);
+ if (locked) lck_rw_unlock_exclusive(decompressorsLock);
return ret;
}
int locked = 0;
char resourceName[80];
- if ((compression_type >= CMP_MAX) ||
- (!registration) ||
- (registration->decmpfs_registration != DECMPFS_REGISTRATION_VERSION)) {
+ if ((compression_type >= CMP_MAX) || !registration_valid(registration)) {
ret = EINVAL;
goto out;
}
decompressors[compression_type] = NULL;
snprintf(resourceName, sizeof(resourceName), "com.apple.AppleFSCompression.Type%u", compression_type);
IOServicePublishResource(resourceName, FALSE);
- wakeup((caddr_t)&decompressors);
out:
- if (locked) lck_rw_done(decompressorsLock);
+ if (locked) lck_rw_unlock_exclusive(decompressorsLock);
return ret;
}
if (decmp_get_func(hdr->compression_type, fetch) != NULL) {
ret = 1;
}
- lck_rw_done(decompressorsLock);
+ lck_rw_unlock_shared(decompressorsLock);
return ret;
}
#pragma mark --- compression/decompression routines ---
static int
-decmpfs_fetch_uncompressed_data(vnode_t vp, decmpfs_header *hdr, off_t offset, user_ssize_t size, int nvec, decmpfs_vector *vec, uint64_t *bytes_read)
+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 */
decmpfs_fetch_uncompressed_data_func fetch = decmp_get_func(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);
+ }
+#endif
+ }
+ }
} else {
err = ENOTSUP;
+ lck_rw_unlock_shared(decompressorsLock);
}
- lck_rw_done(decompressorsLock);
out:
return err;
err = 0;
did_read = 0;
} else {
- err = decmpfs_fetch_uncompressed_data(vp, hdr, uplPos, uplSize, 1, &vec, &did_read);
+ 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);
adjust_fetch(vp, decmpfs_ctx, hdr, &uplPos, &uplSize);
VerboseLog("adjusted uplPos %lld uplSize %lld\n", (uint64_t)uplPos, (uint64_t)uplSize);
}
- lck_rw_done(decompressorsLock);
+ lck_rw_unlock_shared(decompressorsLock);
/* clip the adjusted size to the size of the file */
if ((uint64_t)uplPos + uplSize > cachedSize) {
decmpfs_vector vec;
decompress:
vec = (decmpfs_vector){ .buf = data, .size = curUplSize };
- err = decmpfs_fetch_uncompressed_data(vp, hdr, curUplPos, curUplSize, 1, &vec, &did_read);
+ 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);
/* nothing to do, so no error */
err = 0;
}
- lck_rw_done(decompressorsLock);
+ lck_rw_unlock_shared(decompressorsLock);
if (err != 0) {
ErrorLog("decompressor err %d\n", err);
uint64_t bytes_read = 0;
decmpfs_vector vec = { .buf = data, .size = MIN(allocSize, remaining) };
- err = decmpfs_fetch_uncompressed_data(vp, hdr, offset, vec.size, 1, &vec, &bytes_read);
+ 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);
goto out;
.validate = decmpfs_validate_compressed_file_Type1,
.adjust_fetch = NULL, /* no adjust necessary */
.fetch = decmpfs_fetch_uncompressed_data_Type1,
- .free_data = NULL /* no free necessary */
+ .free_data = NULL, /* no free necessary */
+ .get_flags = NULL /* no flags */
};
#pragma mark --- decmpfs initialization ---