X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/6d2010ae8f7a6078e10b361c6962983bab233e0f..94ff46dc2849db4d43eaaf144872decc522aafb4:/bsd/sys/decmpfs.h?ds=sidebyside diff --git a/bsd/sys/decmpfs.h b/bsd/sys/decmpfs.h index f8a61d288..51fbdfdd6 100644 --- a/bsd/sys/decmpfs.h +++ b/bsd/sys/decmpfs.h @@ -2,7 +2,7 @@ * Copyright (c) 2008 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 @@ -11,10 +11,10 @@ * 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, @@ -22,82 +22,184 @@ * 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@ */ #ifndef _SYS_DECMPFS_H_ #define _SYS_DECMPFS_H_ 1 +#include +#include +#include +#include + +/* + * Please switch on @DECMPFS_ENABLE_KDEBUG_TRACES to enable tracepoints. + * Tracepoints are compiled out by default to eliminate any overhead due to + * kernel tracing. + * + * #define DECMPFS_ENABLE_KDEBUG_TRACES 1 + */ +#if DECMPFS_ENABLE_KDEBUG_TRACES +#define DECMPFS_EMIT_TRACE_ENTRY(D, ...) \ + KDBG_FILTERED((D) | DBG_FUNC_START, ## __VA_ARGS__) +#define DECMPFS_EMIT_TRACE_RETURN(D, ...) \ + KDBG_FILTERED((D) | DBG_FUNC_END, ##__VA_ARGS__) +#else +#define DECMPFS_EMIT_TRACE_ENTRY(D, ...) do {} while (0) +#define DECMPFS_EMIT_TRACE_RETURN(D, ...) do {} while (0) +#endif /* DECMPFS_ENABLE_KDEBUG_TRACES */ + +/* + * KERNEL_DEBUG related definitions for decmpfs. + * + * Please NOTE: The Class DBG_FSYSTEM = 3, and Subclass DBG_DECMP = 0x12, so + * these debug codes are of the form 0x0312nnnn. + */ +#define DECMPDBG_CODE(code) FSDBG_CODE(DBG_DECMP, code) + +enum { + DECMPDBG_DECOMPRESS_FILE = DECMPDBG_CODE(0),/* 0x03120000 */ + DECMPDBG_FETCH_COMPRESSED_HEADER = DECMPDBG_CODE(1),/* 0x03120004 */ + DECMPDBG_FETCH_UNCOMPRESSED_DATA = DECMPDBG_CODE(2),/* 0x03120008 */ + DECMPDBG_FREE_COMPRESSED_DATA = DECMPDBG_CODE(4),/* 0x03120010 */ + DECMPDBG_FILE_IS_COMPRESSED = DECMPDBG_CODE(5),/* 0x03120014 */ +}; + #define MAX_DECMPFS_XATTR_SIZE 3802 /* - NOTE: decmpfs can only be used by thread-safe filesystems + * NOTE: decmpfs can only be used by thread-safe filesystems */ #define DECMPFS_MAGIC 0x636d7066 /* cmpf */ #define DECMPFS_XATTR_NAME "com.apple.decmpfs" /* extended attribute to use for decmpfs */ +/* + * This single field is to be interpreted differently depending on the + * corresponding item type. + * For regular files: it is a 64bits-encoded logical size + * For directories: it is a 64bits-encoded number of children (ie st_nlink - 2) + * For packages: it is 40bits encoded size and 24bits number of children at root + */ +typedef struct __attribute__((packed)) { + uint64_t value; +} decmpfs_raw_item_size; + +#define DECMPFS_PKG_SIZE_MASK 0x000000ffffffffffULL +#define DECMPFS_PKG_COUNT_MASK 0xffffff +#define DECMPFS_PKG_CHLD_COUNT_SHIFT 40 + +#define DECMPFS_PKG_SIZE(x) ((x).value & DECMPFS_PKG_SIZE_MASK) +#define DECMPFS_PKG_CHLD_COUNT(x) ((uint32_t)(((x).value >> DECMPFS_PKG_CHLD_COUNT_SHIFT) & DECMPFS_PKG_COUNT_MASK)) +#define DECMPFS_PKG_VALUE_FROM_SIZE_COUNT(size, count) \ + (((size) & DECMPFS_PKG_SIZE_MASK) | ((uint64_t)(count) << DECMPFS_PKG_CHLD_COUNT_SHIFT)) + +/* Dataless file or directory */ +#define DATALESS_CMPFS_TYPE 0x80000001 + +/* Dataless package, with number of root children and total size encoded on disk */ +#define DATALESS_PKG_CMPFS_TYPE 0x80000002 + + +static inline bool +decmpfs_type_is_dataless(uint32_t cmp_type) +{ + return cmp_type == DATALESS_CMPFS_TYPE || cmp_type == DATALESS_PKG_CMPFS_TYPE; +} + typedef struct __attribute__((packed)) { - /* this structure represents the xattr on disk; the fields below are little-endian */ - uint32_t compression_magic; - uint32_t compression_type; /* see the enum below */ - uint64_t uncompressed_size; - unsigned char attr_bytes[0]; /* the bytes of the attribute after the header */ + /* this structure represents the xattr on disk; the fields below are little-endian */ + uint32_t compression_magic; + uint32_t compression_type; /* see the enum below */ + union { + uint64_t uncompressed_size; /* compatility accessor */ + decmpfs_raw_item_size _size; + }; + unsigned char attr_bytes[0]; /* the bytes of the attribute after the header */ } decmpfs_disk_header; typedef struct __attribute__((packed)) { - /* this structure represents the xattr in memory; the fields below are host-endian */ - uint32_t attr_size; - uint32_t compression_magic; - uint32_t compression_type; - uint64_t uncompressed_size; - unsigned char attr_bytes[0]; /* the bytes of the attribute after the header */ + /* this structure represents the xattr in memory; the fields below are host-endian */ + uint32_t attr_size; + uint32_t compression_magic; + uint32_t compression_type; + union { + /* + * although uncompressed_size remains available for backward-compatibility reasons + * the uncompressed size and nchildren should be accessed using the inline helpers + * below + */ + uint64_t uncompressed_size; + decmpfs_raw_item_size _size; + }; + unsigned char attr_bytes[0]; /* the bytes of the attribute after the header */ } decmpfs_header; +static inline uint64_t +decmpfs_get_uncompressed_size(const decmpfs_header *hdr) +{ + if (hdr->compression_magic == DECMPFS_MAGIC && hdr->compression_type == DATALESS_PKG_CMPFS_TYPE) { + return DECMPFS_PKG_SIZE(hdr->_size); + } + + return hdr->uncompressed_size; +} + +static inline uint32_t +decmpfs_get_directory_entries(const decmpfs_header *hdr) +{ + if (hdr->compression_magic == DECMPFS_MAGIC && hdr->compression_type == DATALESS_PKG_CMPFS_TYPE) { + return DECMPFS_PKG_CHLD_COUNT(hdr->_size); + } + + return (uint32_t)hdr->uncompressed_size; +} + /* compression_type values */ enum { - CMP_Type1 = 1, /* uncompressed data in xattr */ - - /* additional types defined in AppleFSCompression project */ - - CMP_MAX = 255 + CMP_Type1 = 1,/* uncompressed data in xattr */ + + /* additional types defined in AppleFSCompression project */ + + CMP_MAX = 255/* Highest compression_type supported */ }; typedef struct { - void *buf; - user_ssize_t size; + void *buf; + user_ssize_t size; } decmpfs_vector; -#if KERNEL +#ifdef KERNEL -#include +#ifdef XNU_KERNEL_PRIVATE -#if defined(__i386__) || defined(__x86_64__) -#define DECMPFS_SUPPORTS_SWAP64 1 -/* otherwise, no OSCompareAndSwap64, so use a mutex */ -#endif +#include -typedef struct decmpfs_cnode { +struct decmpfs_cnode { uint8_t cmp_state; - uint8_t cmp_minimal_xattr; /* if non-zero, this file's com.apple.decmpfs xattr contained only the minimal decmpfs_disk_header */ + uint8_t cmp_minimal_xattr; /* if non-zero, this file's com.apple.decmpfs xattr contained only the minimal decmpfs_disk_header */ uint32_t cmp_type; uint32_t lockcount; - void *lockowner; /* cnode's lock owner (if a thread is currently holding an exclusive lock) */ - uint64_t uncompressed_size __attribute__((aligned(8))); - lck_rw_t compressed_data_lock; -#if !DECMPFS_SUPPORTS_SWAP64 - /* we need a lock since we can't atomically fetch/set 64 bits */ - lck_mtx_t uncompressed_size_mtx; -#endif /* !DECMPFS_SUPPORTS_SWAP64 */ -} decmpfs_cnode; + void *lockowner; /* cnode's lock owner (if a thread is currently holding an exclusive lock) */ + uint64_t uncompressed_size __attribute__((aligned(8))); + uint64_t nchildren __attribute__((aligned(8))); /* for dataless directories (incl. packages) */ + uint64_t total_size __attribute__((aligned(8)));/* for dataless directories (incl. packages) */ + uint64_t decompression_flags; + lck_rw_t compressed_data_lock; +}; + +#endif // XNU_KERNEL_PRIVATE + +typedef struct decmpfs_cnode decmpfs_cnode; /* return values from decmpfs_file_is_compressed */ enum { - FILE_TYPE_UNKNOWN = 0, - FILE_IS_NOT_COMPRESSED = 1, - FILE_IS_COMPRESSED = 2, - FILE_IS_CONVERTING = 3 /* file is converting from compressed to decompressed */ + FILE_TYPE_UNKNOWN = 0, + FILE_IS_NOT_COMPRESSED = 1, + FILE_IS_COMPRESSED = 2, + FILE_IS_CONVERTING = 3/* file is converting from compressed to decompressed */ }; /* vfs entrypoints */ @@ -105,19 +207,27 @@ extern vfs_context_t decmpfs_ctx; /* client filesystem entrypoints */ void decmpfs_init(void); +decmpfs_cnode *decmpfs_cnode_alloc(void); +void decmpfs_cnode_free(decmpfs_cnode *dp); void decmpfs_cnode_init(decmpfs_cnode *cp); void decmpfs_cnode_destroy(decmpfs_cnode *cp); int decmpfs_hides_rsrc(vfs_context_t ctx, decmpfs_cnode *cp); int decmpfs_hides_xattr(vfs_context_t ctx, decmpfs_cnode *cp, const char *xattr); -boolean_t decmpfs_trylock_compressed_data(decmpfs_cnode *cp, int exclusive); +bool decmpfs_trylock_compressed_data(decmpfs_cnode *cp, int exclusive); void decmpfs_lock_compressed_data(decmpfs_cnode *cp, int exclusive); void decmpfs_unlock_compressed_data(decmpfs_cnode *cp, int exclusive); uint32_t decmpfs_cnode_get_vnode_state(decmpfs_cnode *cp); void decmpfs_cnode_set_vnode_state(decmpfs_cnode *cp, uint32_t state, int skiplock); uint64_t decmpfs_cnode_get_vnode_cached_size(decmpfs_cnode *cp); +uint64_t decmpfs_cnode_get_vnode_cached_nchildren(decmpfs_cnode *cp); +uint64_t decmpfs_cnode_get_vnode_cached_total_size(decmpfs_cnode *cp); +void decmpfs_cnode_set_vnode_cached_size(decmpfs_cnode *cp, uint64_t size); +void decmpfs_cnode_set_vnode_cached_nchildren(decmpfs_cnode *cp, uint64_t nchildren); +void decmpfs_cnode_set_vnode_cached_total_size(decmpfs_cnode *cp, uint64_t total_sz); +uint32_t decmpfs_cnode_cmp_type(decmpfs_cnode *cp); int decmpfs_file_is_compressed(vnode_t vp, decmpfs_cnode *cp); errno_t decmpfs_validate_compressed_file(vnode_t vp, decmpfs_cnode *cp); @@ -133,18 +243,29 @@ typedef int (*decmpfs_validate_compressed_file_func)(vnode_t vp, vfs_context_t c typedef void (*decmpfs_adjust_fetch_region_func)(vnode_t vp, vfs_context_t ctx, decmpfs_header *hdr, off_t *offset, user_ssize_t *size); typedef int (*decmpfs_fetch_uncompressed_data_func)(vnode_t vp, vfs_context_t ctx, decmpfs_header *hdr, off_t offset, user_ssize_t size, int nvec, decmpfs_vector *vec, uint64_t *bytes_read); typedef int (*decmpfs_free_compressed_data_func)(vnode_t vp, vfs_context_t ctx, decmpfs_header *hdr); +typedef uint64_t (*decmpfs_get_decompression_flags_func)(vnode_t vp, vfs_context_t ctx, decmpfs_header *hdr); // returns flags from the DECMPFS_FLAGS enumeration below + +enum { + DECMPFS_FLAGS_FORCE_FLUSH_ON_DECOMPRESS = 1 << 0, +}; + +/* Versions that are supported for binary compatibility */ +#define DECMPFS_REGISTRATION_VERSION_V1 1 +#define DECMPFS_REGISTRATION_VERSION_V3 3 + +#define DECMPFS_REGISTRATION_VERSION (DECMPFS_REGISTRATION_VERSION_V3) -#define DECMPFS_REGISTRATION_VERSION 1 typedef struct { - int decmpfs_registration; - decmpfs_validate_compressed_file_func validate; - decmpfs_adjust_fetch_region_func adjust_fetch; - decmpfs_fetch_uncompressed_data_func fetch; - decmpfs_free_compressed_data_func free_data; + int decmpfs_registration; + decmpfs_validate_compressed_file_func validate; + decmpfs_adjust_fetch_region_func adjust_fetch; + decmpfs_fetch_uncompressed_data_func fetch; + decmpfs_free_compressed_data_func free_data; + decmpfs_get_decompression_flags_func get_flags; } decmpfs_registration; /* hooks for kexts to call */ -errno_t register_decmpfs_decompressor(uint32_t compression_type, decmpfs_registration *registration); +errno_t register_decmpfs_decompressor(uint32_t compression_type, const decmpfs_registration *registration); errno_t unregister_decmpfs_decompressor(uint32_t compression_type, decmpfs_registration *registration); #endif /* KERNEL */