1 /* 2 * Copyright (c) 2008-2018 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 #if !FS_COMPRESSION 29 30 /* We need these symbols even though compression is turned off */ 31 32 #define UNUSED_SYMBOL(x) asm(".global _" #x "\n.set _" #x ", 0\n"); 33 34 UNUSED_SYMBOL(register_decmpfs_decompressor) 35 UNUSED_SYMBOL(unregister_decmpfs_decompressor) 36 UNUSED_SYMBOL(decmpfs_init) 37 UNUSED_SYMBOL(decmpfs_read_compressed) 38 UNUSED_SYMBOL(decmpfs_cnode_cmp_type) 39 UNUSED_SYMBOL(decmpfs_cnode_get_vnode_state) 40 UNUSED_SYMBOL(decmpfs_cnode_get_vnode_cached_size) 41 UNUSED_SYMBOL(decmpfs_cnode_get_vnode_cached_nchildren) 42 UNUSED_SYMBOL(decmpfs_cnode_get_vnode_cached_total_size) 43 UNUSED_SYMBOL(decmpfs_lock_compressed_data) 44 UNUSED_SYMBOL(decmpfs_cnode_free) 45 UNUSED_SYMBOL(decmpfs_cnode_alloc) 46 UNUSED_SYMBOL(decmpfs_cnode_destroy) 47 UNUSED_SYMBOL(decmpfs_decompress_file) 48 UNUSED_SYMBOL(decmpfs_unlock_compressed_data) 49 UNUSED_SYMBOL(decmpfs_cnode_init) 50 UNUSED_SYMBOL(decmpfs_cnode_set_vnode_state) 51 UNUSED_SYMBOL(decmpfs_hides_xattr) 52 UNUSED_SYMBOL(decmpfs_ctx) 53 UNUSED_SYMBOL(decmpfs_file_is_compressed) 54 UNUSED_SYMBOL(decmpfs_update_attributes) 55 UNUSED_SYMBOL(decmpfs_hides_rsrc) 56 UNUSED_SYMBOL(decmpfs_pagein_compressed) 57 UNUSED_SYMBOL(decmpfs_validate_compressed_file) 58 59 #else /* FS_COMPRESSION */ 60 #include <sys/kernel.h> 61 #include <sys/vnode_internal.h> 62 #include <sys/file_internal.h> 63 #include <sys/stat.h> 64 #include <sys/fcntl.h> 65 #include <sys/xattr.h> 66 #include <sys/namei.h> 67 #include <sys/user.h> 68 #include <sys/mount_internal.h> 69 #include <sys/ubc.h> 70 #include <sys/decmpfs.h> 71 #include <sys/uio_internal.h> 72 #include <libkern/OSByteOrder.h> 73 #include <libkern/section_keywords.h> 74 #include <sys/fsctl.h> 75 76 #include <sys/kdebug_triage.h> 77 78 #include <ptrauth.h> 79 80 #pragma mark --- debugging --- 81 82 #define COMPRESSION_DEBUG 0 83 #define COMPRESSION_DEBUG_VERBOSE 0 84 #define MALLOC_DEBUG 0 85 86 #if COMPRESSION_DEBUG 87 static char* 88 vnpath(vnode_t vp, char *path, int len) 89 { 90 int origlen = len; 91 path[0] = 0; 92 vn_getpath(vp, path, &len); 93 path[origlen - 1] = 0; 94 return path; 95 } 96 #endif 97 98 #define ErrorLog(x, args...) \ 99 printf("%s:%d:%s: " x, __FILE_NAME__, __LINE__, __FUNCTION__, ## args) 100 #if COMPRESSION_DEBUG 101 #define ErrorLogWithPath(x, args...) do { \ 102 char *path = zalloc(ZV_NAMEI); \ 103 printf("%s:%d:%s: %s: " x, __FILE_NAME__, __LINE__, __FUNCTION__, \ 104 vnpath(vp, path, PATH_MAX), ## args); \ 105 zfree(ZV_NAMEI, path); \ 106 } while(0) 107 #else 108 #define ErrorLogWithPath(x, args...) do { \ 109 (void*)vp; \ 110 printf("%s:%d:%s: %s: " x, __FILE_NAME__, __LINE__, __FUNCTION__, \ 111 "<private>", ## args); \ 112 } while(0) 113 #endif 114 115 #if COMPRESSION_DEBUG 116 #define DebugLog ErrorLog 117 #define DebugLogWithPath ErrorLogWithPath 118 #else 119 #define DebugLog(x...) do { } while(0) 120 #define DebugLogWithPath(x...) do { } while(0) 121 #endif 122 123 #if COMPRESSION_DEBUG_VERBOSE 124 #define VerboseLog ErrorLog 125 #define VerboseLogWithPath ErrorLogWithPath 126 #else 127 #define VerboseLog(x...) do { } while(0) 128 #define VerboseLogWithPath(x...) do { } while(0) 129 #endif 130 131 #define decmpfs_ktriage_record(code, arg) ktriage_record(thread_tid(current_thread()), KDBG_TRIAGE_EVENTID(KDBG_TRIAGE_SUBSYS_DECMPFS, KDBG_TRIAGE_RESERVED, code), arg); 132 133 enum ktriage_decmpfs_error_codes { 134 KTRIAGE_DECMPFS_PREFIX = 0, 135 KTRIAGE_DECMPFS_IVALID_OFFSET, 136 KTRIAGE_DECMPFS_COMPRESSOR_NOT_REGISTERED, 137 KTRIAGE_DECMPFS_FETCH_CALLBACK_FAILED, 138 KTRIAGE_DECMPFS_FETCH_HEADER_FAILED, 139 KTRIAGE_DECMPFS_UBC_UPL_MAP_FAILED, 140 KTRIAGE_DECMPFS_FETCH_UNCOMPRESSED_DATA_FAILED, 141 142 KTRIAGE_DECMPFS_MAX 143 }; 144 145 const char *ktriage_decmpfs_strings[] = { 146 [KTRIAGE_DECMPFS_PREFIX] = "decmpfs - ", 147 [KTRIAGE_DECMPFS_IVALID_OFFSET] = "pagein offset is invalid\n", 148 [KTRIAGE_DECMPFS_COMPRESSOR_NOT_REGISTERED] = "compressor is not registered\n", 149 [KTRIAGE_DECMPFS_FETCH_CALLBACK_FAILED] = "fetch callback failed\n", 150 [KTRIAGE_DECMPFS_FETCH_HEADER_FAILED] = "fetch decmpfs xattr failed\n", 151 [KTRIAGE_DECMPFS_UBC_UPL_MAP_FAILED] = "failed to map a UBC UPL\n", 152 [KTRIAGE_DECMPFS_FETCH_UNCOMPRESSED_DATA_FAILED] = "failed to fetch uncompressed data\n", 153 }; 154 155 ktriage_strings_t ktriage_decmpfs_subsystem_strings = {KTRIAGE_DECMPFS_MAX, ktriage_decmpfs_strings}; 156 157 #pragma mark --- globals --- 158 159 static LCK_GRP_DECLARE(decmpfs_lockgrp, "VFSCOMP"); 160 static LCK_RW_DECLARE(decompressorsLock, &decmpfs_lockgrp); 161 static LCK_MTX_DECLARE(decompress_channel_mtx, &decmpfs_lockgrp); 162 163 static const decmpfs_registration *decompressors[CMP_MAX]; /* the registered compressors */ 164 static int decompress_channel; /* channel used by decompress_file to wake up waiters */ 165 166 vfs_context_t decmpfs_ctx; 167 168 #pragma mark --- decmp_get_func --- 169 170 #define offsetof_func(func) ((uintptr_t)offsetof(decmpfs_registration, func)) 171 172 static void * 173 _func_from_offset(uint32_t type, uintptr_t offset, uint32_t discriminator) 174 { 175 /* get the function at the given offset in the registration for the given type */ 176 const decmpfs_registration *reg = decompressors[type]; 177 178 switch (reg->decmpfs_registration) { 179 case DECMPFS_REGISTRATION_VERSION_V1: 180 if (offset > offsetof_func(free_data)) { 181 return NULL; 182 } 183 break; 184 case DECMPFS_REGISTRATION_VERSION_V3: 185 if (offset > offsetof_func(get_flags)) { 186 return NULL; 187 } 188 break; 189 default: 190 return NULL; 191 } 192 193 void *ptr = *(void * const *)((uintptr_t)reg + offset); 194 if (ptr != NULL) { 195 /* Resign as a function-in-void* */ 196 ptr = ptrauth_auth_and_resign(ptr, ptrauth_key_asia, discriminator, ptrauth_key_asia, 0); 197 } 198 return ptr; 199 } 200 201 extern void IOServicePublishResource( const char * property, boolean_t value ); 202 extern boolean_t IOServiceWaitForMatchingResource( const char * property, uint64_t timeout ); 203 extern boolean_t IOCatalogueMatchingDriversPresent( const char * property ); 204 205 static void * 206 _decmp_get_func(vnode_t vp, uint32_t type, uintptr_t offset, uint32_t discriminator) 207 { 208 /* 209 * this function should be called while holding a shared lock to decompressorsLock, 210 * and will return with the lock held 211 */ 212 213 if (type >= CMP_MAX) { 214 return NULL; 215 } 216 217 if (decompressors[type] != NULL) { 218 // the compressor has already registered but the function might be null 219 return _func_from_offset(type, offset, discriminator); 220 } 221 222 // does IOKit know about a kext that is supposed to provide this type? 223 char providesName[80]; 224 snprintf(providesName, sizeof(providesName), "com.apple.AppleFSCompression.providesType%u", type); 225 if (IOCatalogueMatchingDriversPresent(providesName)) { 226 // there is a kext that says it will register for this type, so let's wait for it 227 char resourceName[80]; 228 uint64_t delay = 10000000ULL; // 10 milliseconds. 229 snprintf(resourceName, sizeof(resourceName), "com.apple.AppleFSCompression.Type%u", type); 230 ErrorLogWithPath("waiting for %s\n", resourceName); 231 while (decompressors[type] == NULL) { 232 lck_rw_unlock_shared(&decompressorsLock); // we have to unlock to allow the kext to register 233 if (IOServiceWaitForMatchingResource(resourceName, delay)) { 234 lck_rw_lock_shared(&decompressorsLock); 235 break; 236 } 237 if (!IOCatalogueMatchingDriversPresent(providesName)) { 238 // 239 ErrorLogWithPath("the kext with %s is no longer present\n", providesName); 240 lck_rw_lock_shared(&decompressorsLock); 241 break; 242 } 243 ErrorLogWithPath("still waiting for %s\n", resourceName); 244 delay *= 2; 245 lck_rw_lock_shared(&decompressorsLock); 246 } 247 // IOKit says the kext is loaded, so it should be registered too! 248 if (decompressors[type] == NULL) { 249 ErrorLogWithPath("we found %s, but the type still isn't registered\n", providesName); 250 return NULL; 251 } 252 // it's now registered, so let's return the function 253 return _func_from_offset(type, offset, discriminator); 254 } 255 256 // the compressor hasn't registered, so it never will unless someone manually kextloads it 257 ErrorLogWithPath("tried to access a compressed file of unregistered type %d\n", type); 258 return NULL; 259 } 260 261 #define decmp_get_func(vp, type, func) (typeof(decompressors[0]->func))_decmp_get_func(vp, type, offsetof_func(func), ptrauth_function_pointer_type_discriminator(typeof(decompressors[0]->func))) 262 263 #pragma mark --- utilities --- 264 265 #if COMPRESSION_DEBUG 266 static int 267 vnsize(vnode_t vp, uint64_t *size) 268 { 269 struct vnode_attr va; 270 VATTR_INIT(&va); 271 VATTR_WANTED(&va, va_data_size); 272 int error = vnode_getattr(vp, &va, decmpfs_ctx); 273 if (error != 0) { 274 ErrorLogWithPath("vnode_getattr err %d\n", error); 275 return error; 276 } 277 *size = va.va_data_size; 278 return 0; 279 } 280 #endif /* COMPRESSION_DEBUG */ 281 282 #pragma mark --- cnode routines --- 283 284 ZONE_DEFINE(decmpfs_cnode_zone, "decmpfs_cnode", 285 sizeof(struct decmpfs_cnode), ZC_NONE); 286 287 decmpfs_cnode * 288 decmpfs_cnode_alloc(void) 289 { 290 return zalloc(decmpfs_cnode_zone); 291 } 292 293 void 294 decmpfs_cnode_free(decmpfs_cnode *dp) 295 { 296 zfree(decmpfs_cnode_zone, dp); 297 } 298 299 void 300 decmpfs_cnode_init(decmpfs_cnode *cp) 301 { 302 memset(cp, 0, sizeof(*cp)); 303 lck_rw_init(&cp->compressed_data_lock, &decmpfs_lockgrp, NULL); 304 } 305 306 void 307 decmpfs_cnode_destroy(decmpfs_cnode *cp) 308 { 309 lck_rw_destroy(&cp->compressed_data_lock, &decmpfs_lockgrp); 310 } 311 312 bool 313 decmpfs_trylock_compressed_data(decmpfs_cnode *cp, int exclusive) 314 { 315 void *thread = current_thread(); 316 bool retval = false; 317 318 if (cp->lockowner == thread) { 319 /* this thread is already holding an exclusive lock, so bump the count */ 320 cp->lockcount++; 321 retval = true; 322 } else if (exclusive) { 323 if ((retval = lck_rw_try_lock_exclusive(&cp->compressed_data_lock))) { 324 cp->lockowner = thread; 325 cp->lockcount = 1; 326 } 327 } else { 328 if ((retval = lck_rw_try_lock_shared(&cp->compressed_data_lock))) { 329 cp->lockowner = (void *)-1; 330 } 331 } 332 return retval; 333 } 334 335 void 336 decmpfs_lock_compressed_data(decmpfs_cnode *cp, int exclusive) 337 { 338 void *thread = current_thread(); 339 340 if (cp->lockowner == thread) { 341 /* this thread is already holding an exclusive lock, so bump the count */ 342 cp->lockcount++; 343 } else if (exclusive) { 344 lck_rw_lock_exclusive(&cp->compressed_data_lock); 345 cp->lockowner = thread; 346 cp->lockcount = 1; 347 } else { 348 lck_rw_lock_shared(&cp->compressed_data_lock); 349 cp->lockowner = (void *)-1; 350 } 351 } 352 353 void 354 decmpfs_unlock_compressed_data(decmpfs_cnode *cp, __unused int exclusive) 355 { 356 void *thread = current_thread(); 357 358 if (cp->lockowner == thread) { 359 /* this thread is holding an exclusive lock, so decrement the count */ 360 if ((--cp->lockcount) > 0) { 361 /* the caller still has outstanding locks, so we're done */ 362 return; 363 } 364 cp->lockowner = NULL; 365 } 366 367 lck_rw_done(&cp->compressed_data_lock); 368 } 369 370 uint32_t 371 decmpfs_cnode_get_vnode_state(decmpfs_cnode *cp) 372 { 373 return cp->cmp_state; 374 } 375 376 void 377 decmpfs_cnode_set_vnode_state(decmpfs_cnode *cp, uint32_t state, int skiplock) 378 { 379 if (!skiplock) { 380 decmpfs_lock_compressed_data(cp, 1); 381 } 382 cp->cmp_state = (uint8_t)state; 383 if (state == FILE_TYPE_UNKNOWN) { 384 /* clear out the compression type too */ 385 cp->cmp_type = 0; 386 } 387 if (!skiplock) { 388 decmpfs_unlock_compressed_data(cp, 1); 389 } 390 } 391 392 static void 393 decmpfs_cnode_set_vnode_cmp_type(decmpfs_cnode *cp, uint32_t cmp_type, int skiplock) 394 { 395 if (!skiplock) { 396 decmpfs_lock_compressed_data(cp, 1); 397 } 398 cp->cmp_type = cmp_type; 399 if (!skiplock) { 400 decmpfs_unlock_compressed_data(cp, 1); 401 } 402 } 403 404 static void 405 decmpfs_cnode_set_vnode_minimal_xattr(decmpfs_cnode *cp, int minimal_xattr, int skiplock) 406 { 407 if (!skiplock) { 408 decmpfs_lock_compressed_data(cp, 1); 409 } 410 cp->cmp_minimal_xattr = !!minimal_xattr; 411 if (!skiplock) { 412 decmpfs_unlock_compressed_data(cp, 1); 413 } 414 } 415 416 uint64_t 417 decmpfs_cnode_get_vnode_cached_size(decmpfs_cnode *cp) 418 { 419 return cp->uncompressed_size; 420 } 421 422 uint64_t 423 decmpfs_cnode_get_vnode_cached_nchildren(decmpfs_cnode *cp) 424 { 425 return cp->nchildren; 426 } 427 428 uint64_t 429 decmpfs_cnode_get_vnode_cached_total_size(decmpfs_cnode *cp) 430 { 431 return cp->total_size; 432 } 433 434 void 435 decmpfs_cnode_set_vnode_cached_size(decmpfs_cnode *cp, uint64_t size) 436 { 437 while (1) { 438 uint64_t old = cp->uncompressed_size; 439 if (OSCompareAndSwap64(old, size, (UInt64*)&cp->uncompressed_size)) { 440 return; 441 } else { 442 /* failed to write our value, so loop */ 443 } 444 } 445 } 446 447 void 448 decmpfs_cnode_set_vnode_cached_nchildren(decmpfs_cnode *cp, uint64_t nchildren) 449 { 450 while (1) { 451 uint64_t old = cp->nchildren; 452 if (OSCompareAndSwap64(old, nchildren, (UInt64*)&cp->nchildren)) { 453 return; 454 } else { 455 /* failed to write our value, so loop */ 456 } 457 } 458 } 459 460 void 461 decmpfs_cnode_set_vnode_cached_total_size(decmpfs_cnode *cp, uint64_t total_sz) 462 { 463 while (1) { 464 uint64_t old = cp->total_size; 465 if (OSCompareAndSwap64(old, total_sz, (UInt64*)&cp->total_size)) { 466 return; 467 } else { 468 /* failed to write our value, so loop */ 469 } 470 } 471 } 472 473 static uint64_t 474 decmpfs_cnode_get_decompression_flags(decmpfs_cnode *cp) 475 { 476 return cp->decompression_flags; 477 } 478 479 static void 480 decmpfs_cnode_set_decompression_flags(decmpfs_cnode *cp, uint64_t flags) 481 { 482 while (1) { 483 uint64_t old = cp->decompression_flags; 484 if (OSCompareAndSwap64(old, flags, (UInt64*)&cp->decompression_flags)) { 485 return; 486 } else { 487 /* failed to write our value, so loop */ 488 } 489 } 490 } 491 492 uint32_t 493 decmpfs_cnode_cmp_type(decmpfs_cnode *cp) 494 { 495 return cp->cmp_type; 496 } 497 498 #pragma mark --- decmpfs state routines --- 499 500 static int 501 decmpfs_fetch_compressed_header(vnode_t vp, decmpfs_cnode *cp, decmpfs_header **hdrOut, int returnInvalid, size_t *hdr_size) 502 { 503 /* 504 * fetches vp's compression xattr, converting it into a decmpfs_header; returns 0 or errno 505 * if returnInvalid == 1, returns the header even if the type was invalid (out of range), 506 * and return ERANGE in that case 507 */ 508 509 size_t read_size = 0; 510 size_t attr_size = 0; 511 size_t alloc_size = 0; 512 uio_t attr_uio = NULL; 513 int err = 0; 514 char *data = NULL; 515 const bool no_additional_data = ((cp != NULL) 516 && (cp->cmp_type != 0) 517 && (cp->cmp_minimal_xattr != 0)); 518 UIO_STACKBUF(uio_buf, 1); 519 decmpfs_header *hdr = NULL; 520 521 /* 522 * Trace the following parameters on entry with event-id 0x03120004 523 * 524 * @vp->v_id: vnode-id for which to fetch compressed header. 525 * @no_additional_data: If set true then xattr didn't have any extra data. 526 * @returnInvalid: return the header even though the type is out of range. 527 */ 528 DECMPFS_EMIT_TRACE_ENTRY(DECMPDBG_FETCH_COMPRESSED_HEADER, vp->v_id, 529 no_additional_data, returnInvalid); 530 531 if (no_additional_data) { 532 /* 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 */ 533 534 alloc_size = sizeof(decmpfs_header); 535 data = kalloc_data(sizeof(decmpfs_header), Z_WAITOK | Z_NOFAIL); 536 hdr = (decmpfs_header*)data; 537 hdr->attr_size = sizeof(decmpfs_disk_header); 538 hdr->compression_magic = DECMPFS_MAGIC; 539 hdr->compression_type = cp->cmp_type; 540 if (hdr->compression_type == DATALESS_PKG_CMPFS_TYPE) { 541 if (!vnode_isdir(vp)) { 542 err = EINVAL; 543 goto out; 544 } 545 hdr->_size.value = DECMPFS_PKG_VALUE_FROM_SIZE_COUNT( 546 decmpfs_cnode_get_vnode_cached_size(cp), 547 decmpfs_cnode_get_vnode_cached_nchildren(cp)); 548 } else if (vnode_isdir(vp)) { 549 hdr->_size.value = decmpfs_cnode_get_vnode_cached_nchildren(cp); 550 } else { 551 hdr->_size.value = decmpfs_cnode_get_vnode_cached_size(cp); 552 } 553 } else { 554 /* figure out how big the xattr is on disk */ 555 err = vn_getxattr(vp, DECMPFS_XATTR_NAME, NULL, &attr_size, XATTR_NOSECURITY, decmpfs_ctx); 556 if (err != 0) { 557 goto out; 558 } 559 alloc_size = attr_size + sizeof(hdr->attr_size); 560 561 if (attr_size < sizeof(decmpfs_disk_header) || attr_size > MAX_DECMPFS_XATTR_SIZE) { 562 err = EINVAL; 563 goto out; 564 } 565 566 /* allocation includes space for the extra attr_size field of a compressed_header */ 567 data = (char *)kalloc_data(alloc_size, Z_WAITOK); 568 /* 569 * we know the decmpfs sizes tend to be "small", and 570 * vm_page_alloc_list() will actually wait for memory 571 * for asks of less than 1/4th of the physical memory. 572 * 573 * This is important because decmpfs failures result 574 * in pageins failing spuriously and eventually SIGBUS 575 * errors for example when faulting in TEXT. 576 */ 577 assert(data); 578 579 /* read the xattr into our buffer, skipping over the attr_size field at the beginning */ 580 attr_uio = uio_createwithbuffer(1, 0, UIO_SYSSPACE, UIO_READ, &uio_buf[0], sizeof(uio_buf)); 581 uio_addiov(attr_uio, CAST_USER_ADDR_T(data + sizeof(hdr->attr_size)), attr_size); 582 583 err = vn_getxattr(vp, DECMPFS_XATTR_NAME, attr_uio, &read_size, XATTR_NOSECURITY, decmpfs_ctx); 584 if (err != 0) { 585 goto out; 586 } 587 if (read_size != attr_size) { 588 err = EINVAL; 589 goto out; 590 } 591 hdr = (decmpfs_header*)data; 592 hdr->attr_size = (uint32_t)attr_size; 593 /* swap the fields to native endian */ 594 hdr->compression_magic = OSSwapLittleToHostInt32(hdr->compression_magic); 595 hdr->compression_type = OSSwapLittleToHostInt32(hdr->compression_type); 596 hdr->uncompressed_size = OSSwapLittleToHostInt64(hdr->uncompressed_size); 597 } 598 599 if (hdr->compression_magic != DECMPFS_MAGIC) { 600 ErrorLogWithPath("invalid compression_magic 0x%08x, should be 0x%08x\n", hdr->compression_magic, DECMPFS_MAGIC); 601 err = EINVAL; 602 goto out; 603 } 604 605 /* 606 * Special-case the DATALESS compressor here; that is a valid type, 607 * even through there will never be an entry in the decompressor 608 * handler table for it. If we don't do this, then the cmp_state 609 * for this cnode will end up being marked NOT_COMPRESSED, and 610 * we'll be stuck in limbo. 611 */ 612 if (hdr->compression_type >= CMP_MAX && !decmpfs_type_is_dataless(hdr->compression_type)) { 613 if (returnInvalid) { 614 /* return the header even though the type is out of range */ 615 err = ERANGE; 616 } else { 617 ErrorLogWithPath("compression_type %d out of range\n", hdr->compression_type); 618 err = EINVAL; 619 } 620 goto out; 621 } 622 623 out: 624 if (err && (err != ERANGE)) { 625 DebugLogWithPath("err %d\n", err); 626 kfree_data(data, alloc_size); 627 *hdrOut = NULL; 628 } else { 629 *hdrOut = hdr; 630 *hdr_size = alloc_size; 631 } 632 /* 633 * Trace the following parameters on return with event-id 0x03120004. 634 * 635 * @vp->v_id: vnode-id for which to fetch compressed header. 636 * @err: value returned from this function. 637 */ 638 DECMPFS_EMIT_TRACE_RETURN(DECMPDBG_FETCH_COMPRESSED_HEADER, vp->v_id, err); 639 return err; 640 } 641 642 static int 643 decmpfs_fast_get_state(decmpfs_cnode *cp) 644 { 645 /* 646 * return the cached state 647 * this should *only* be called when we know that decmpfs_file_is_compressed has already been called, 648 * because this implies that the cached state is valid 649 */ 650 int cmp_state = decmpfs_cnode_get_vnode_state(cp); 651 652 switch (cmp_state) { 653 case FILE_IS_NOT_COMPRESSED: 654 case FILE_IS_COMPRESSED: 655 case FILE_IS_CONVERTING: 656 return cmp_state; 657 case FILE_TYPE_UNKNOWN: 658 /* 659 * we should only get here if decmpfs_file_is_compressed was not called earlier on this vnode, 660 * which should not be possible 661 */ 662 ErrorLog("decmpfs_fast_get_state called on unknown file\n"); 663 return FILE_IS_NOT_COMPRESSED; 664 default: 665 /* */ 666 ErrorLog("unknown cmp_state %d\n", cmp_state); 667 return FILE_IS_NOT_COMPRESSED; 668 } 669 } 670 671 static int 672 decmpfs_fast_file_is_compressed(decmpfs_cnode *cp) 673 { 674 int cmp_state = decmpfs_cnode_get_vnode_state(cp); 675 676 switch (cmp_state) { 677 case FILE_IS_NOT_COMPRESSED: 678 return 0; 679 case FILE_IS_COMPRESSED: 680 case FILE_IS_CONVERTING: 681 return 1; 682 case FILE_TYPE_UNKNOWN: 683 /* 684 * we should only get here if decmpfs_file_is_compressed was not called earlier on this vnode, 685 * which should not be possible 686 */ 687 ErrorLog("decmpfs_fast_get_state called on unknown file\n"); 688 return 0; 689 default: 690 /* */ 691 ErrorLog("unknown cmp_state %d\n", cmp_state); 692 return 0; 693 } 694 } 695 696 errno_t 697 decmpfs_validate_compressed_file(vnode_t vp, decmpfs_cnode *cp) 698 { 699 /* give a compressor a chance to indicate that a compressed file is invalid */ 700 decmpfs_header *hdr = NULL; 701 size_t alloc_size = 0; 702 errno_t err = decmpfs_fetch_compressed_header(vp, cp, &hdr, 0, &alloc_size); 703 704 if (err) { 705 /* we couldn't get the header */ 706 if (decmpfs_fast_get_state(cp) == FILE_IS_NOT_COMPRESSED) { 707 /* the file is no longer compressed, so return success */ 708 err = 0; 709 } 710 goto out; 711 } 712 713 if (!decmpfs_type_is_dataless(hdr->compression_type)) { 714 lck_rw_lock_shared(&decompressorsLock); 715 decmpfs_validate_compressed_file_func validate = decmp_get_func(vp, hdr->compression_type, validate); 716 if (validate) { /* make sure this validation function is valid */ 717 /* is the data okay? */ 718 err = validate(vp, decmpfs_ctx, hdr); 719 } else if (decmp_get_func(vp, hdr->compression_type, fetch) == NULL) { 720 /* the type isn't registered */ 721 err = EIO; 722 } else { 723 /* no validate registered, so nothing to do */ 724 err = 0; 725 } 726 lck_rw_unlock_shared(&decompressorsLock); 727 } 728 out: 729 if (hdr != NULL) { 730 kfree_data(hdr, alloc_size); 731 } 732 #if COMPRESSION_DEBUG 733 if (err) { 734 DebugLogWithPath("decmpfs_validate_compressed_file ret %d, vp->v_flag %d\n", err, vp->v_flag); 735 } 736 #endif 737 return err; 738 } 739 740 int 741 decmpfs_file_is_compressed(vnode_t vp, decmpfs_cnode *cp) 742 { 743 /* 744 * determines whether vp points to a compressed file 745 * 746 * to speed up this operation, we cache the result in the cnode, and do as little as possible 747 * in the case where the cnode already has a valid cached state 748 * 749 */ 750 751 int ret = 0; 752 int error = 0; 753 uint32_t cmp_state; 754 struct vnode_attr va_fetch; 755 decmpfs_header *hdr = NULL; 756 size_t alloc_size = 0; 757 mount_t mp = NULL; 758 int cnode_locked = 0; 759 int saveInvalid = 0; // save the header data even though the type was out of range 760 uint64_t decompression_flags = 0; 761 bool is_mounted, is_local_fs; 762 763 if (vnode_isnamedstream(vp)) { 764 /* 765 * named streams can't be compressed 766 * since named streams of the same file share the same cnode, 767 * we don't want to get/set the state in the cnode, just return 0 768 */ 769 return 0; 770 } 771 772 /* examine the cached a state in this cnode */ 773 cmp_state = decmpfs_cnode_get_vnode_state(cp); 774 switch (cmp_state) { 775 case FILE_IS_NOT_COMPRESSED: 776 return 0; 777 case FILE_IS_COMPRESSED: 778 return 1; 779 case FILE_IS_CONVERTING: 780 /* treat the file as compressed, because this gives us a way to block future reads until decompression is done */ 781 return 1; 782 case FILE_TYPE_UNKNOWN: 783 /* the first time we encountered this vnode, so we need to check it out */ 784 break; 785 default: 786 /* unknown state, assume file is not compressed */ 787 ErrorLogWithPath("unknown cmp_state %d\n", cmp_state); 788 return 0; 789 } 790 791 is_mounted = false; 792 is_local_fs = false; 793 mp = vnode_mount(vp); 794 if (mp) { 795 is_mounted = true; 796 } 797 if (is_mounted) { 798 is_local_fs = ((mp->mnt_flag & MNT_LOCAL)); 799 } 800 /* 801 * Trace the following parameters on entry with event-id 0x03120014. 802 * 803 * @vp->v_id: vnode-id of the file being queried. 804 * @is_mounted: set to true if @vp belongs to a mounted fs. 805 * @is_local_fs: set to true if @vp belongs to local fs. 806 */ 807 DECMPFS_EMIT_TRACE_ENTRY(DECMPDBG_FILE_IS_COMPRESSED, vp->v_id, 808 is_mounted, is_local_fs); 809 810 if (!is_mounted) { 811 /* 812 * this should only be true before we mount the root filesystem 813 * we short-cut this return to avoid the call to getattr below, which 814 * will fail before root is mounted 815 */ 816 ret = FILE_IS_NOT_COMPRESSED; 817 goto done; 818 } 819 820 if (!is_local_fs) { 821 /* compression only supported on local filesystems */ 822 ret = FILE_IS_NOT_COMPRESSED; 823 goto done; 824 } 825 826 /* lock our cnode data so that another caller doesn't change the state under us */ 827 decmpfs_lock_compressed_data(cp, 1); 828 cnode_locked = 1; 829 830 VATTR_INIT(&va_fetch); 831 VATTR_WANTED(&va_fetch, va_flags); 832 error = vnode_getattr(vp, &va_fetch, decmpfs_ctx); 833 if (error) { 834 /* failed to get the bsd flags so the file is not compressed */ 835 ret = FILE_IS_NOT_COMPRESSED; 836 goto done; 837 } 838 if (va_fetch.va_flags & UF_COMPRESSED) { 839 /* UF_COMPRESSED is on, make sure the file has the DECMPFS_XATTR_NAME xattr */ 840 error = decmpfs_fetch_compressed_header(vp, cp, &hdr, 1, &alloc_size); 841 if ((hdr != NULL) && (error == ERANGE)) { 842 saveInvalid = 1; 843 } 844 if (error) { 845 /* failed to get the xattr so the file is not compressed */ 846 ret = FILE_IS_NOT_COMPRESSED; 847 goto done; 848 } 849 /* 850 * We got the xattr, so the file is at least tagged compressed. 851 * For DATALESS, regular files and directories can be "compressed". 852 * For all other types, only files are allowed. 853 */ 854 if (!vnode_isreg(vp) && 855 !(decmpfs_type_is_dataless(hdr->compression_type) && vnode_isdir(vp))) { 856 ret = FILE_IS_NOT_COMPRESSED; 857 goto done; 858 } 859 ret = FILE_IS_COMPRESSED; 860 goto done; 861 } 862 /* UF_COMPRESSED isn't on, so the file isn't compressed */ 863 ret = FILE_IS_NOT_COMPRESSED; 864 865 done: 866 if (((ret == FILE_IS_COMPRESSED) || saveInvalid) && hdr) { 867 /* 868 * cache the uncompressed size away in the cnode 869 */ 870 871 if (!cnode_locked) { 872 /* 873 * we should never get here since the only place ret is set to FILE_IS_COMPRESSED 874 * is after the call to decmpfs_lock_compressed_data above 875 */ 876 decmpfs_lock_compressed_data(cp, 1); 877 cnode_locked = 1; 878 } 879 880 if (vnode_isdir(vp)) { 881 decmpfs_cnode_set_vnode_cached_size(cp, 64); 882 decmpfs_cnode_set_vnode_cached_nchildren(cp, decmpfs_get_directory_entries(hdr)); 883 if (hdr->compression_type == DATALESS_PKG_CMPFS_TYPE) { 884 decmpfs_cnode_set_vnode_cached_total_size(cp, DECMPFS_PKG_SIZE(hdr->_size)); 885 } 886 } else { 887 decmpfs_cnode_set_vnode_cached_size(cp, hdr->uncompressed_size); 888 } 889 decmpfs_cnode_set_vnode_state(cp, ret, 1); 890 decmpfs_cnode_set_vnode_cmp_type(cp, hdr->compression_type, 1); 891 /* remember if the xattr's size was equal to the minimal xattr */ 892 if (hdr->attr_size == sizeof(decmpfs_disk_header)) { 893 decmpfs_cnode_set_vnode_minimal_xattr(cp, 1, 1); 894 } 895 if (ret == FILE_IS_COMPRESSED) { 896 /* update the ubc's size for this file */ 897 ubc_setsize(vp, hdr->uncompressed_size); 898 899 /* update the decompression flags in the decmpfs cnode */ 900 lck_rw_lock_shared(&decompressorsLock); 901 decmpfs_get_decompression_flags_func get_flags = decmp_get_func(vp, hdr->compression_type, get_flags); 902 if (get_flags) { 903 decompression_flags = get_flags(vp, decmpfs_ctx, hdr); 904 } 905 lck_rw_unlock_shared(&decompressorsLock); 906 decmpfs_cnode_set_decompression_flags(cp, decompression_flags); 907 } 908 } else { 909 /* we might have already taken the lock above; if so, skip taking it again by passing cnode_locked as the skiplock parameter */ 910 decmpfs_cnode_set_vnode_state(cp, ret, cnode_locked); 911 } 912 913 if (cnode_locked) { 914 decmpfs_unlock_compressed_data(cp, 1); 915 } 916 917 if (hdr != NULL) { 918 kfree_data(hdr, alloc_size); 919 } 920 921 /* 922 * Trace the following parameters on return with event-id 0x03120014. 923 * 924 * @vp->v_id: vnode-id of the file being queried. 925 * @return: set to 1 is file is compressed. 926 */ 927 switch (ret) { 928 case FILE_IS_NOT_COMPRESSED: 929 DECMPFS_EMIT_TRACE_RETURN(DECMPDBG_FILE_IS_COMPRESSED, vp->v_id, 0); 930 return 0; 931 case FILE_IS_COMPRESSED: 932 case FILE_IS_CONVERTING: 933 DECMPFS_EMIT_TRACE_RETURN(DECMPDBG_FILE_IS_COMPRESSED, vp->v_id, 1); 934 return 1; 935 default: 936 /* unknown state, assume file is not compressed */ 937 DECMPFS_EMIT_TRACE_RETURN(DECMPDBG_FILE_IS_COMPRESSED, vp->v_id, 0); 938 ErrorLogWithPath("unknown ret %d\n", ret); 939 return 0; 940 } 941 } 942 943 int 944 decmpfs_update_attributes(vnode_t vp, struct vnode_attr *vap) 945 { 946 int error = 0; 947 948 if (VATTR_IS_ACTIVE(vap, va_flags)) { 949 /* the BSD flags are being updated */ 950 if (vap->va_flags & UF_COMPRESSED) { 951 /* the compressed bit is being set, did it change? */ 952 struct vnode_attr va_fetch; 953 int old_flags = 0; 954 VATTR_INIT(&va_fetch); 955 VATTR_WANTED(&va_fetch, va_flags); 956 error = vnode_getattr(vp, &va_fetch, decmpfs_ctx); 957 if (error) { 958 return error; 959 } 960 961 old_flags = va_fetch.va_flags; 962 963 if (!(old_flags & UF_COMPRESSED)) { 964 /* 965 * Compression bit was turned on, make sure the file has the DECMPFS_XATTR_NAME attribute. 966 * This precludes anyone from using the UF_COMPRESSED bit for anything else, and it enforces 967 * an order of operation -- you must first do the setxattr and then the chflags. 968 */ 969 970 if (VATTR_IS_ACTIVE(vap, va_data_size)) { 971 /* 972 * don't allow the caller to set the BSD flag and the size in the same call 973 * since this doesn't really make sense 974 */ 975 vap->va_flags &= ~UF_COMPRESSED; 976 return 0; 977 } 978 979 decmpfs_header *hdr = NULL; 980 size_t alloc_size = 0; 981 error = decmpfs_fetch_compressed_header(vp, NULL, &hdr, 1, &alloc_size); 982 if (error == 0) { 983 /* 984 * Allow the flag to be set since the decmpfs attribute 985 * is present. 986 * 987 * If we're creating a dataless file we do not want to 988 * truncate it to zero which allows the file resolver to 989 * have more control over when truncation should happen. 990 * All other types of compressed files are truncated to 991 * zero. 992 */ 993 if (!decmpfs_type_is_dataless(hdr->compression_type)) { 994 VATTR_SET_ACTIVE(vap, va_data_size); 995 vap->va_data_size = 0; 996 } 997 } else if (error == ERANGE) { 998 /* the file had a decmpfs attribute but the type was out of range, so don't muck with the file's data size */ 999 } else { 1000 /* no DECMPFS_XATTR_NAME attribute, so deny the update */ 1001 vap->va_flags &= ~UF_COMPRESSED; 1002 } 1003 if (hdr != NULL) { 1004 kfree_data(hdr, alloc_size); 1005 } 1006 } 1007 } 1008 } 1009 1010 return 0; 1011 } 1012 1013 static int 1014 wait_for_decompress(decmpfs_cnode *cp) 1015 { 1016 int state; 1017 lck_mtx_lock(&decompress_channel_mtx); 1018 do { 1019 state = decmpfs_fast_get_state(cp); 1020 if (state != FILE_IS_CONVERTING) { 1021 /* file is not decompressing */ 1022 lck_mtx_unlock(&decompress_channel_mtx); 1023 return state; 1024 } 1025 msleep((caddr_t)&decompress_channel, &decompress_channel_mtx, PINOD, "wait_for_decompress", NULL); 1026 } while (1); 1027 } 1028 1029 #pragma mark --- decmpfs hide query routines --- 1030 1031 int 1032 decmpfs_hides_rsrc(vfs_context_t ctx, decmpfs_cnode *cp) 1033 { 1034 /* 1035 * WARNING!!! 1036 * callers may (and do) pass NULL for ctx, so we should only use it 1037 * for this equality comparison 1038 * 1039 * This routine should only be called after a file has already been through decmpfs_file_is_compressed 1040 */ 1041 1042 if (ctx == decmpfs_ctx) { 1043 return 0; 1044 } 1045 1046 if (!decmpfs_fast_file_is_compressed(cp)) { 1047 return 0; 1048 } 1049 1050 /* all compressed files hide their resource fork */ 1051 return 1; 1052 } 1053 1054 int 1055 decmpfs_hides_xattr(vfs_context_t ctx, decmpfs_cnode *cp, const char *xattr) 1056 { 1057 /* 1058 * WARNING!!! 1059 * callers may (and do) pass NULL for ctx, so we should only use it 1060 * for this equality comparison 1061 * 1062 * This routine should only be called after a file has already been through decmpfs_file_is_compressed 1063 */ 1064 1065 if (ctx == decmpfs_ctx) { 1066 return 0; 1067 } 1068 if (strncmp(xattr, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME) - 1) == 0) { 1069 return decmpfs_hides_rsrc(ctx, cp); 1070 } 1071 if (!decmpfs_fast_file_is_compressed(cp)) { 1072 /* file is not compressed, so don't hide this xattr */ 1073 return 0; 1074 } 1075 if (strncmp(xattr, DECMPFS_XATTR_NAME, sizeof(DECMPFS_XATTR_NAME) - 1) == 0) { 1076 /* it's our xattr, so hide it */ 1077 return 1; 1078 } 1079 /* don't hide this xattr */ 1080 return 0; 1081 } 1082 1083 #pragma mark --- registration/validation routines --- 1084 1085 static inline int 1086 registration_valid(const decmpfs_registration *registration) 1087 { 1088 return registration && ((registration->decmpfs_registration == DECMPFS_REGISTRATION_VERSION_V1) || (registration->decmpfs_registration == DECMPFS_REGISTRATION_VERSION_V3)); 1089 } 1090 1091 errno_t 1092 register_decmpfs_decompressor(uint32_t compression_type, const decmpfs_registration *registration) 1093 { 1094 /* called by kexts to register decompressors */ 1095 1096 errno_t ret = 0; 1097 int locked = 0; 1098 char resourceName[80]; 1099 1100 if ((compression_type >= CMP_MAX) || !registration_valid(registration)) { 1101 ret = EINVAL; 1102 goto out; 1103 } 1104 1105 lck_rw_lock_exclusive(&decompressorsLock); locked = 1; 1106 1107 /* make sure the registration for this type is zero */ 1108 if (decompressors[compression_type] != NULL) { 1109 ret = EEXIST; 1110 goto out; 1111 } 1112 decompressors[compression_type] = registration; 1113 snprintf(resourceName, sizeof(resourceName), "com.apple.AppleFSCompression.Type%u", compression_type); 1114 IOServicePublishResource(resourceName, TRUE); 1115 1116 out: 1117 if (locked) { 1118 lck_rw_unlock_exclusive(&decompressorsLock); 1119 } 1120 return ret; 1121 } 1122 1123 errno_t 1124 unregister_decmpfs_decompressor(uint32_t compression_type, decmpfs_registration *registration) 1125 { 1126 /* called by kexts to unregister decompressors */ 1127 1128 errno_t ret = 0; 1129 int locked = 0; 1130 char resourceName[80]; 1131 1132 if ((compression_type >= CMP_MAX) || !registration_valid(registration)) { 1133 ret = EINVAL; 1134 goto out; 1135 } 1136 1137 lck_rw_lock_exclusive(&decompressorsLock); locked = 1; 1138 if (decompressors[compression_type] != registration) { 1139 ret = EEXIST; 1140 goto out; 1141 } 1142 decompressors[compression_type] = NULL; 1143 snprintf(resourceName, sizeof(resourceName), "com.apple.AppleFSCompression.Type%u", compression_type); 1144 IOServicePublishResource(resourceName, FALSE); 1145 1146 out: 1147 if (locked) { 1148 lck_rw_unlock_exclusive(&decompressorsLock); 1149 } 1150 return ret; 1151 } 1152 1153 static int 1154 compression_type_valid(vnode_t vp, decmpfs_header *hdr) 1155 { 1156 /* fast pre-check to determine if the given compressor has checked in */ 1157 int ret = 0; 1158 1159 /* every compressor must have at least a fetch function */ 1160 lck_rw_lock_shared(&decompressorsLock); 1161 if (decmp_get_func(vp, hdr->compression_type, fetch) != NULL) { 1162 ret = 1; 1163 } 1164 lck_rw_unlock_shared(&decompressorsLock); 1165 1166 return ret; 1167 } 1168 1169 #pragma mark --- compression/decompression routines --- 1170 1171 static int 1172 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) 1173 { 1174 /* get the uncompressed bytes for the specified region of vp by calling out to the registered compressor */ 1175 1176 int err = 0; 1177 1178 *bytes_read = 0; 1179 1180 if (offset >= (off_t)hdr->uncompressed_size) { 1181 /* reading past end of file; nothing to do */ 1182 err = 0; 1183 goto out; 1184 } 1185 if (offset < 0) { 1186 /* tried to read from before start of file */ 1187 err = EINVAL; 1188 goto out; 1189 } 1190 if (hdr->uncompressed_size - offset < size) { 1191 /* adjust size so we don't read past the end of the file */ 1192 size = (user_ssize_t)(hdr->uncompressed_size - offset); 1193 } 1194 if (size == 0) { 1195 /* nothing to read */ 1196 err = 0; 1197 goto out; 1198 } 1199 1200 /* 1201 * Trace the following parameters on entry with event-id 0x03120008. 1202 * 1203 * @vp->v_id: vnode-id of the file being decompressed. 1204 * @hdr->compression_type: compression type. 1205 * @offset: offset from where to fetch uncompressed data. 1206 * @size: amount of uncompressed data to fetch. 1207 * 1208 * Please NOTE: @offset and @size can overflow in theory but 1209 * here it is safe. 1210 */ 1211 DECMPFS_EMIT_TRACE_ENTRY(DECMPDBG_FETCH_UNCOMPRESSED_DATA, vp->v_id, 1212 hdr->compression_type, (int)offset, (int)size); 1213 lck_rw_lock_shared(&decompressorsLock); 1214 decmpfs_fetch_uncompressed_data_func fetch = decmp_get_func(vp, hdr->compression_type, fetch); 1215 if (fetch) { 1216 err = fetch(vp, decmpfs_ctx, hdr, offset, size, nvec, vec, bytes_read); 1217 lck_rw_unlock_shared(&decompressorsLock); 1218 if (err == 0) { 1219 uint64_t decompression_flags = decmpfs_cnode_get_decompression_flags(cp); 1220 if (decompression_flags & DECMPFS_FLAGS_FORCE_FLUSH_ON_DECOMPRESS) { 1221 #if !defined(__i386__) && !defined(__x86_64__) 1222 int i; 1223 for (i = 0; i < nvec; i++) { 1224 assert(vec[i].size >= 0 && vec[i].size <= UINT_MAX); 1225 flush_dcache64((addr64_t)(uintptr_t)vec[i].buf, (unsigned int)vec[i].size, FALSE); 1226 } 1227 #endif 1228 } 1229 } else { 1230 decmpfs_ktriage_record(KTRIAGE_DECMPFS_FETCH_CALLBACK_FAILED, err); 1231 } 1232 } else { 1233 decmpfs_ktriage_record(KTRIAGE_DECMPFS_COMPRESSOR_NOT_REGISTERED, hdr->compression_type); 1234 err = ENOTSUP; 1235 lck_rw_unlock_shared(&decompressorsLock); 1236 } 1237 /* 1238 * Trace the following parameters on return with event-id 0x03120008. 1239 * 1240 * @vp->v_id: vnode-id of the file being decompressed. 1241 * @bytes_read: amount of uncompressed bytes fetched in bytes. 1242 * @err: value returned from this function. 1243 * 1244 * Please NOTE: @bytes_read can overflow in theory but here it is safe. 1245 */ 1246 DECMPFS_EMIT_TRACE_RETURN(DECMPDBG_FETCH_UNCOMPRESSED_DATA, vp->v_id, 1247 (int)*bytes_read, err); 1248 out: 1249 return err; 1250 } 1251 1252 static kern_return_t 1253 commit_upl(upl_t upl, upl_offset_t pl_offset, size_t uplSize, int flags, int abort) 1254 { 1255 kern_return_t kr = 0; 1256 1257 #if CONFIG_IOSCHED 1258 upl_unmark_decmp(upl); 1259 #endif /* CONFIG_IOSCHED */ 1260 1261 /* commit the upl pages */ 1262 if (abort) { 1263 VerboseLog("aborting upl, flags 0x%08x\n", flags); 1264 kr = ubc_upl_abort_range(upl, pl_offset, (upl_size_t)uplSize, flags); 1265 if (kr != KERN_SUCCESS) { 1266 ErrorLog("ubc_upl_abort_range error %d\n", (int)kr); 1267 } 1268 } else { 1269 VerboseLog("committing upl, flags 0x%08x\n", flags | UPL_COMMIT_CLEAR_DIRTY); 1270 kr = ubc_upl_commit_range(upl, pl_offset, (upl_size_t)uplSize, flags | UPL_COMMIT_CLEAR_DIRTY | UPL_COMMIT_WRITTEN_BY_KERNEL); 1271 if (kr != KERN_SUCCESS) { 1272 ErrorLog("ubc_upl_commit_range error %d\n", (int)kr); 1273 } 1274 } 1275 return kr; 1276 } 1277 1278 1279 errno_t 1280 decmpfs_pagein_compressed(struct vnop_pagein_args *ap, int *is_compressed, decmpfs_cnode *cp) 1281 { 1282 /* handles a page-in request from vfs for a compressed file */ 1283 1284 int err = 0; 1285 vnode_t vp = ap->a_vp; 1286 upl_t pl = ap->a_pl; 1287 upl_offset_t pl_offset = ap->a_pl_offset; 1288 off_t f_offset = ap->a_f_offset; 1289 size_t size = ap->a_size; 1290 int flags = ap->a_flags; 1291 off_t uplPos = 0; 1292 user_ssize_t uplSize = 0; 1293 user_ssize_t rounded_uplSize = 0; 1294 size_t verify_block_size = 0; 1295 void *data = NULL; 1296 decmpfs_header *hdr = NULL; 1297 size_t alloc_size = 0; 1298 uint64_t cachedSize = 0; 1299 uint32_t fs_bsize = 0; 1300 int cmpdata_locked = 0; 1301 int num_valid_pages = 0; 1302 int num_invalid_pages = 0; 1303 bool file_tail_page_valid = false; 1304 1305 if (!decmpfs_trylock_compressed_data(cp, 0)) { 1306 return EAGAIN; 1307 } 1308 cmpdata_locked = 1; 1309 1310 1311 if (flags & ~(UPL_IOSYNC | UPL_NOCOMMIT | UPL_NORDAHEAD)) { 1312 DebugLogWithPath("pagein: unknown flags 0x%08x\n", (flags & ~(UPL_IOSYNC | UPL_NOCOMMIT | UPL_NORDAHEAD))); 1313 } 1314 1315 err = decmpfs_fetch_compressed_header(vp, cp, &hdr, 0, &alloc_size); 1316 if (err != 0) { 1317 decmpfs_ktriage_record(KTRIAGE_DECMPFS_FETCH_HEADER_FAILED, err); 1318 goto out; 1319 } 1320 1321 cachedSize = hdr->uncompressed_size; 1322 1323 if (!compression_type_valid(vp, hdr)) { 1324 /* compressor not registered */ 1325 decmpfs_ktriage_record(KTRIAGE_DECMPFS_COMPRESSOR_NOT_REGISTERED, hdr->compression_type); 1326 err = ENOTSUP; 1327 goto out; 1328 } 1329 1330 /* 1331 * can't page-in from a negative offset 1332 * or if we're starting beyond the EOF 1333 * or if the file offset isn't page aligned 1334 * or the size requested isn't a multiple of PAGE_SIZE 1335 */ 1336 if (f_offset < 0 || f_offset >= cachedSize || 1337 (f_offset & PAGE_MASK_64) || (size & PAGE_MASK) || (pl_offset & PAGE_MASK)) { 1338 decmpfs_ktriage_record(KTRIAGE_DECMPFS_IVALID_OFFSET, 0); 1339 err = EINVAL; 1340 goto out; 1341 } 1342 1343 /* 1344 * If the verify block size is larger than the page size, the UPL needs 1345 * to be aligned to it, Since the UPL has been created by the filesystem, 1346 * we will only check if the passed in UPL length conforms to the 1347 * alignment requirements. 1348 */ 1349 err = VNOP_VERIFY(vp, f_offset, NULL, 0, &verify_block_size, NULL, 1350 VNODE_VERIFY_DEFAULT, NULL); 1351 if (err) { 1352 ErrorLogWithPath("VNOP_VERIFY returned error = %d\n", err); 1353 goto out; 1354 } else if (verify_block_size) { 1355 if (vp->v_mount->mnt_vfsstat.f_bsize > PAGE_SIZE) { 1356 fs_bsize = vp->v_mount->mnt_vfsstat.f_bsize; 1357 } 1358 if (verify_block_size & (verify_block_size - 1)) { 1359 ErrorLogWithPath("verify block size (%zu) is not power of 2, no verification will be done\n", verify_block_size); 1360 err = EINVAL; 1361 } else if (size % verify_block_size) { 1362 ErrorLogWithPath("upl size (%zu) is not a multiple of verify block size (%zu)\n", (size_t)size, verify_block_size); 1363 err = EINVAL; 1364 } else if (fs_bsize) { 1365 /* 1366 * Filesystems requesting verification have to provide 1367 * values for block sizes which are powers of 2. 1368 */ 1369 if (fs_bsize & (fs_bsize - 1)) { 1370 ErrorLogWithPath("FS block size (%u) is greater than PAGE_SIZE (%d) and is not power of 2, no verification will be done\n", 1371 fs_bsize, PAGE_SIZE); 1372 err = EINVAL; 1373 } else if (fs_bsize > verify_block_size) { 1374 ErrorLogWithPath("FS block size (%u) is greater than verify block size (%zu), no verification will be done\n", 1375 fs_bsize, verify_block_size); 1376 err = EINVAL; 1377 } 1378 } 1379 if (err) { 1380 goto out; 1381 } 1382 } 1383 1384 #if CONFIG_IOSCHED 1385 /* Mark the UPL as the requesting UPL for decompression */ 1386 upl_mark_decmp(pl); 1387 #endif /* CONFIG_IOSCHED */ 1388 1389 /* map the upl so we can fetch into it */ 1390 kern_return_t kr = ubc_upl_map(pl, (vm_offset_t*)&data); 1391 if ((kr != KERN_SUCCESS) || (data == NULL)) { 1392 decmpfs_ktriage_record(KTRIAGE_DECMPFS_UBC_UPL_MAP_FAILED, kr); 1393 err = ENOSPC; 1394 data = NULL; 1395 #if CONFIG_IOSCHED 1396 upl_unmark_decmp(pl); 1397 #endif /* CONFIG_IOSCHED */ 1398 goto out; 1399 } 1400 1401 uplPos = f_offset; 1402 off_t max_size = cachedSize - f_offset; 1403 1404 if (size < max_size) { 1405 rounded_uplSize = uplSize = size; 1406 file_tail_page_valid = true; 1407 } else { 1408 uplSize = (user_ssize_t)max_size; 1409 if (fs_bsize) { 1410 /* First round up to fs_bsize */ 1411 rounded_uplSize = (uplSize + (fs_bsize - 1)) & ~(fs_bsize - 1); 1412 /* then to PAGE_SIZE */ 1413 rounded_uplSize = MIN(size, round_page((vm_offset_t)rounded_uplSize)); 1414 } else { 1415 rounded_uplSize = round_page((vm_offset_t)uplSize); 1416 } 1417 } 1418 1419 /* do the fetch */ 1420 decmpfs_vector vec; 1421 1422 decompress: 1423 /* 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 */ 1424 vec = (decmpfs_vector) { 1425 .buf = (char*)data + pl_offset, 1426 .size = size, 1427 }; 1428 1429 uint64_t did_read = 0; 1430 if (decmpfs_fast_get_state(cp) == FILE_IS_CONVERTING) { 1431 ErrorLogWithPath("unexpected pagein during decompress\n"); 1432 /* 1433 * if the file is converting, this must be a recursive call to pagein from underneath a call to decmpfs_decompress_file; 1434 * pretend that it succeeded but don't do anything since we're just going to write over the pages anyway 1435 */ 1436 err = 0; 1437 } else { 1438 if (verify_block_size <= PAGE_SIZE) { 1439 err = decmpfs_fetch_uncompressed_data(vp, cp, hdr, uplPos, uplSize, 1, &vec, &did_read); 1440 /* zero out whatever wasn't read */ 1441 if (did_read < rounded_uplSize) { 1442 memset((char*)vec.buf + did_read, 0, (size_t)(rounded_uplSize - did_read)); 1443 } 1444 } else { 1445 off_t l_uplPos = uplPos; 1446 off_t l_pl_offset = pl_offset; 1447 user_ssize_t l_uplSize = uplSize; 1448 upl_page_info_t *pl_info = ubc_upl_pageinfo(pl); 1449 1450 err = 0; 1451 /* 1452 * When the system page size is less than the "verify block size", 1453 * the UPL passed may not consist solely of absent pages. 1454 * We have to detect the "absent" pages and only decompress 1455 * into those absent/invalid page ranges. 1456 * 1457 * Things that will change in each iteration of the loop : 1458 * 1459 * l_pl_offset = where we are inside the UPL [0, caller_upl_created_size) 1460 * l_uplPos = the file offset the l_pl_offset corresponds to. 1461 * l_uplSize = the size of the upl still unprocessed; 1462 * 1463 * In this picture, we have to do the transfer on 2 ranges 1464 * (One 2 page range and one 3 page range) and the loop 1465 * below will skip the first two pages and then identify 1466 * the next two as invalid and fill those in and 1467 * then skip the next one and then do the last pages. 1468 * 1469 * uplPos(file_offset) 1470 * | uplSize 1471 * 0 V<--------------> file_size 1472 * |---------------------------------------------------> 1473 * | | |V|V|I|I|V|I|I|I| 1474 * ^ 1475 * | upl 1476 * <-------------------> 1477 * | 1478 * pl_offset 1479 * 1480 * uplSize will be clipped in case the UPL range exceeds 1481 * the file size. 1482 * 1483 */ 1484 while (l_uplSize) { 1485 uint64_t l_did_read = 0; 1486 int pl_offset_pg = (int)(l_pl_offset / PAGE_SIZE); 1487 int pages_left_in_upl; 1488 int start_pg; 1489 int last_pg; 1490 1491 /* 1492 * l_uplSize may start off less than the size of the upl, 1493 * we have to round it up to PAGE_SIZE to calculate 1494 * how many more pages are left. 1495 */ 1496 pages_left_in_upl = (int)(round_page((vm_offset_t)l_uplSize) / PAGE_SIZE); 1497 1498 /* 1499 * scan from the beginning of the upl looking for the first 1500 * non-valid page.... this will become the first page in 1501 * the request we're going to make to 1502 * 'decmpfs_fetch_uncompressed_data'... if all 1503 * of the pages are valid, we won't call through 1504 * to 'decmpfs_fetch_uncompressed_data' 1505 */ 1506 for (start_pg = 0; start_pg < pages_left_in_upl; start_pg++) { 1507 if (!upl_valid_page(pl_info, pl_offset_pg + start_pg)) { 1508 break; 1509 } 1510 } 1511 1512 num_valid_pages += start_pg; 1513 1514 /* 1515 * scan from the starting invalid page looking for 1516 * a valid page before the end of the upl is 1517 * reached, if we find one, then it will be the 1518 * last page of the request to 'decmpfs_fetch_uncompressed_data' 1519 */ 1520 for (last_pg = start_pg; last_pg < pages_left_in_upl; last_pg++) { 1521 if (upl_valid_page(pl_info, pl_offset_pg + last_pg)) { 1522 break; 1523 } 1524 } 1525 1526 if (start_pg < last_pg) { 1527 off_t inval_offset = start_pg * PAGE_SIZE; 1528 int inval_pages = last_pg - start_pg; 1529 int inval_size = inval_pages * PAGE_SIZE; 1530 decmpfs_vector l_vec; 1531 1532 num_invalid_pages += inval_pages; 1533 if (inval_offset) { 1534 did_read += inval_offset; 1535 l_pl_offset += inval_offset; 1536 l_uplPos += inval_offset; 1537 l_uplSize -= inval_offset; 1538 } 1539 1540 l_vec = (decmpfs_vector) { 1541 .buf = (char*)data + l_pl_offset, 1542 .size = inval_size, 1543 }; 1544 1545 err = decmpfs_fetch_uncompressed_data(vp, cp, hdr, l_uplPos, 1546 MIN(l_uplSize, inval_size), 1, &l_vec, &l_did_read); 1547 1548 if (!err && (l_did_read != inval_size) && (l_uplSize > inval_size)) { 1549 ErrorLogWithPath("Unexpected size fetch of decompressed data, l_uplSize = %d, l_did_read = %d, inval_size = %d\n", 1550 (int)l_uplSize, (int)l_did_read, (int)inval_size); 1551 err = EINVAL; 1552 } 1553 } else { 1554 /* no invalid pages left */ 1555 l_did_read = l_uplSize; 1556 if (!file_tail_page_valid) { 1557 file_tail_page_valid = true; 1558 } 1559 } 1560 1561 if (err) { 1562 break; 1563 } 1564 1565 did_read += l_did_read; 1566 l_pl_offset += l_did_read; 1567 l_uplPos += l_did_read; 1568 l_uplSize -= l_did_read; 1569 } 1570 1571 /* Zero out the region after EOF in the last page (if needed) */ 1572 if (!err && !file_tail_page_valid && (uplSize < rounded_uplSize)) { 1573 memset((char*)vec.buf + uplSize, 0, (size_t)(rounded_uplSize - uplSize)); 1574 } 1575 } 1576 } 1577 if (err) { 1578 decmpfs_ktriage_record(KTRIAGE_DECMPFS_FETCH_UNCOMPRESSED_DATA_FAILED, err) 1579 DebugLogWithPath("decmpfs_fetch_uncompressed_data err %d\n", err); 1580 int cmp_state = decmpfs_fast_get_state(cp); 1581 if (cmp_state == FILE_IS_CONVERTING) { 1582 DebugLogWithPath("cmp_state == FILE_IS_CONVERTING\n"); 1583 cmp_state = wait_for_decompress(cp); 1584 if (cmp_state == FILE_IS_COMPRESSED) { 1585 DebugLogWithPath("cmp_state == FILE_IS_COMPRESSED\n"); 1586 /* a decompress was attempted but it failed, let's try calling fetch again */ 1587 goto decompress; 1588 } 1589 } 1590 if (cmp_state == FILE_IS_NOT_COMPRESSED) { 1591 DebugLogWithPath("cmp_state == FILE_IS_NOT_COMPRESSED\n"); 1592 /* the file was decompressed after we started reading it */ 1593 *is_compressed = 0; /* instruct caller to fall back to its normal path */ 1594 } 1595 } 1596 1597 if (!err && verify_block_size) { 1598 size_t cur_verify_block_size = verify_block_size; 1599 1600 if ((err = VNOP_VERIFY(vp, uplPos, vec.buf, rounded_uplSize, &cur_verify_block_size, NULL, 0, NULL))) { 1601 ErrorLogWithPath("Verification failed with error %d, uplPos = %lld, uplSize = %d, did_read = %d, valid_pages = %d, invalid_pages = %d, tail_page_valid = %d\n", 1602 err, (long long)uplPos, (int)rounded_uplSize, (int)did_read, num_valid_pages, num_invalid_pages, file_tail_page_valid); 1603 } 1604 /* XXX : If the verify block size changes, redo the read */ 1605 } 1606 1607 #if CONFIG_IOSCHED 1608 upl_unmark_decmp(pl); 1609 #endif /* CONFIG_IOSCHED */ 1610 1611 kr = ubc_upl_unmap(pl); data = NULL; /* make sure to set data to NULL so we don't try to unmap again below */ 1612 if (kr != KERN_SUCCESS) { 1613 ErrorLogWithPath("ubc_upl_unmap error %d\n", (int)kr); 1614 } else { 1615 if (!err) { 1616 /* commit our pages */ 1617 kr = commit_upl(pl, pl_offset, (size_t)rounded_uplSize, UPL_COMMIT_FREE_ON_EMPTY, 0 /* commit */); 1618 /* If there were any pages after the page containing EOF, abort them. */ 1619 if (rounded_uplSize < size) { 1620 kr = commit_upl(pl, (upl_offset_t)(pl_offset + rounded_uplSize), (size_t)(size - rounded_uplSize), 1621 UPL_ABORT_FREE_ON_EMPTY | UPL_ABORT_ERROR, 1 /* abort */); 1622 } 1623 } 1624 } 1625 1626 out: 1627 if (data) { 1628 ubc_upl_unmap(pl); 1629 } 1630 if (hdr != NULL) { 1631 kfree_data(hdr, alloc_size); 1632 } 1633 if (cmpdata_locked) { 1634 decmpfs_unlock_compressed_data(cp, 0); 1635 } 1636 if (err) { 1637 #if 0 1638 if (err != ENXIO && err != ENOSPC) { 1639 char *path = zalloc(ZV_NAMEI); 1640 panic("%s: decmpfs_pagein_compressed: err %d", vnpath(vp, path, PATH_MAX), err); 1641 zfree(ZV_NAMEI, path); 1642 } 1643 #endif /* 0 */ 1644 ErrorLogWithPath("err %d\n", err); 1645 } 1646 return err; 1647 } 1648 1649 errno_t 1650 decmpfs_read_compressed(struct vnop_read_args *ap, int *is_compressed, decmpfs_cnode *cp) 1651 { 1652 /* handles a read request from vfs for a compressed file */ 1653 1654 uio_t uio = ap->a_uio; 1655 vnode_t vp = ap->a_vp; 1656 int err = 0; 1657 int countInt = 0; 1658 off_t uplPos = 0; 1659 user_ssize_t uplSize = 0; 1660 user_ssize_t uplRemaining = 0; 1661 off_t curUplPos = 0; 1662 user_ssize_t curUplSize = 0; 1663 kern_return_t kr = KERN_SUCCESS; 1664 int abort_read = 0; 1665 void *data = NULL; 1666 uint64_t did_read = 0; 1667 upl_t upl = NULL; 1668 upl_page_info_t *pli = NULL; 1669 decmpfs_header *hdr = NULL; 1670 size_t alloc_size = 0; 1671 uint64_t cachedSize = 0; 1672 off_t uioPos = 0; 1673 user_ssize_t uioRemaining = 0; 1674 size_t verify_block_size = 0; 1675 size_t alignment_size = PAGE_SIZE; 1676 int cmpdata_locked = 0; 1677 1678 decmpfs_lock_compressed_data(cp, 0); cmpdata_locked = 1; 1679 1680 uplPos = uio_offset(uio); 1681 uplSize = uio_resid(uio); 1682 VerboseLogWithPath("uplPos %lld uplSize %lld\n", uplPos, uplSize); 1683 1684 cachedSize = decmpfs_cnode_get_vnode_cached_size(cp); 1685 1686 if ((uint64_t)uplPos + uplSize > cachedSize) { 1687 /* truncate the read to the size of the file */ 1688 uplSize = (user_ssize_t)(cachedSize - uplPos); 1689 } 1690 1691 /* give the cluster layer a chance to fill in whatever it already has */ 1692 countInt = (uplSize > INT_MAX) ? INT_MAX : (int)uplSize; 1693 err = cluster_copy_ubc_data(vp, uio, &countInt, 0); 1694 if (err != 0) { 1695 goto out; 1696 } 1697 1698 /* figure out what's left */ 1699 uioPos = uio_offset(uio); 1700 uioRemaining = uio_resid(uio); 1701 if ((uint64_t)uioPos + uioRemaining > cachedSize) { 1702 /* truncate the read to the size of the file */ 1703 uioRemaining = (user_ssize_t)(cachedSize - uioPos); 1704 } 1705 1706 if (uioRemaining <= 0) { 1707 /* nothing left */ 1708 goto out; 1709 } 1710 1711 err = decmpfs_fetch_compressed_header(vp, cp, &hdr, 0, &alloc_size); 1712 if (err != 0) { 1713 goto out; 1714 } 1715 if (!compression_type_valid(vp, hdr)) { 1716 err = ENOTSUP; 1717 goto out; 1718 } 1719 1720 uplPos = uioPos; 1721 uplSize = uioRemaining; 1722 #if COMPRESSION_DEBUG 1723 DebugLogWithPath("uplPos %lld uplSize %lld\n", (uint64_t)uplPos, (uint64_t)uplSize); 1724 #endif 1725 1726 lck_rw_lock_shared(&decompressorsLock); 1727 decmpfs_adjust_fetch_region_func adjust_fetch = decmp_get_func(vp, hdr->compression_type, adjust_fetch); 1728 if (adjust_fetch) { 1729 /* give the compressor a chance to adjust the portion of the file that we read */ 1730 adjust_fetch(vp, decmpfs_ctx, hdr, &uplPos, &uplSize); 1731 VerboseLogWithPath("adjusted uplPos %lld uplSize %lld\n", (uint64_t)uplPos, (uint64_t)uplSize); 1732 } 1733 lck_rw_unlock_shared(&decompressorsLock); 1734 1735 /* clip the adjusted size to the size of the file */ 1736 if ((uint64_t)uplPos + uplSize > cachedSize) { 1737 /* truncate the read to the size of the file */ 1738 uplSize = (user_ssize_t)(cachedSize - uplPos); 1739 } 1740 1741 if (uplSize <= 0) { 1742 /* nothing left */ 1743 goto out; 1744 } 1745 1746 /* 1747 * since we're going to create a upl for the given region of the file, 1748 * make sure we're on page boundaries 1749 */ 1750 1751 /* If the verify block size is larger than the page size, the UPL needs to aligned to it */ 1752 err = VNOP_VERIFY(vp, uplPos, NULL, 0, &verify_block_size, NULL, VNODE_VERIFY_DEFAULT, NULL); 1753 if (err) { 1754 goto out; 1755 } else if (verify_block_size) { 1756 if (verify_block_size & (verify_block_size - 1)) { 1757 ErrorLogWithPath("verify block size is not power of 2, no verification will be done\n"); 1758 verify_block_size = 0; 1759 } else if (verify_block_size > PAGE_SIZE) { 1760 alignment_size = verify_block_size; 1761 } 1762 } 1763 1764 if (uplPos & (alignment_size - 1)) { 1765 /* round position down to page boundary */ 1766 uplSize += (uplPos & (alignment_size - 1)); 1767 uplPos &= ~(alignment_size - 1); 1768 } 1769 1770 /* round size up to alignement_size multiple */ 1771 uplSize = (uplSize + (alignment_size - 1)) & ~(alignment_size - 1); 1772 1773 VerboseLogWithPath("new uplPos %lld uplSize %lld\n", (uint64_t)uplPos, (uint64_t)uplSize); 1774 1775 uplRemaining = uplSize; 1776 curUplPos = uplPos; 1777 curUplSize = 0; 1778 1779 while (uplRemaining > 0) { 1780 /* start after the last upl */ 1781 curUplPos += curUplSize; 1782 1783 /* clip to max upl size */ 1784 curUplSize = uplRemaining; 1785 if (curUplSize > MAX_UPL_SIZE_BYTES) { 1786 curUplSize = MAX_UPL_SIZE_BYTES; 1787 } 1788 1789 /* create the upl */ 1790 kr = ubc_create_upl_kernel(vp, curUplPos, (int)curUplSize, &upl, &pli, UPL_SET_LITE, VM_KERN_MEMORY_FILE); 1791 if (kr != KERN_SUCCESS) { 1792 ErrorLogWithPath("ubc_create_upl error %d\n", (int)kr); 1793 err = EINVAL; 1794 goto out; 1795 } 1796 VerboseLogWithPath("curUplPos %lld curUplSize %lld\n", (uint64_t)curUplPos, (uint64_t)curUplSize); 1797 1798 #if CONFIG_IOSCHED 1799 /* Mark the UPL as the requesting UPL for decompression */ 1800 upl_mark_decmp(upl); 1801 #endif /* CONFIG_IOSCHED */ 1802 1803 /* map the upl */ 1804 kr = ubc_upl_map(upl, (vm_offset_t*)&data); 1805 if (kr != KERN_SUCCESS) { 1806 commit_upl(upl, 0, curUplSize, UPL_ABORT_FREE_ON_EMPTY, 1); 1807 #if 0 1808 char *path = zalloc(ZV_NAMEI); 1809 panic("%s: decmpfs_read_compressed: ubc_upl_map error %d", vnpath(vp, path, PATH_MAX), (int)kr); 1810 zfree(ZV_NAMEI, path); 1811 #else /* 0 */ 1812 ErrorLogWithPath("ubc_upl_map kr=0x%x\n", (int)kr); 1813 #endif /* 0 */ 1814 err = EINVAL; 1815 goto out; 1816 } 1817 1818 /* make sure the map succeeded */ 1819 if (!data) { 1820 commit_upl(upl, 0, curUplSize, UPL_ABORT_FREE_ON_EMPTY, 1); 1821 1822 ErrorLogWithPath("ubc_upl_map mapped null\n"); 1823 err = EINVAL; 1824 goto out; 1825 } 1826 1827 /* fetch uncompressed data into the mapped upl */ 1828 decmpfs_vector vec; 1829 decompress: 1830 vec = (decmpfs_vector){ .buf = data, .size = curUplSize }; 1831 err = decmpfs_fetch_uncompressed_data(vp, cp, hdr, curUplPos, curUplSize, 1, &vec, &did_read); 1832 if (err) { 1833 ErrorLogWithPath("decmpfs_fetch_uncompressed_data err %d\n", err); 1834 1835 /* maybe the file is converting to decompressed */ 1836 int cmp_state = decmpfs_fast_get_state(cp); 1837 if (cmp_state == FILE_IS_CONVERTING) { 1838 ErrorLogWithPath("cmp_state == FILE_IS_CONVERTING\n"); 1839 cmp_state = wait_for_decompress(cp); 1840 if (cmp_state == FILE_IS_COMPRESSED) { 1841 ErrorLogWithPath("cmp_state == FILE_IS_COMPRESSED\n"); 1842 /* a decompress was attempted but it failed, let's try fetching again */ 1843 goto decompress; 1844 } 1845 } 1846 if (cmp_state == FILE_IS_NOT_COMPRESSED) { 1847 ErrorLogWithPath("cmp_state == FILE_IS_NOT_COMPRESSED\n"); 1848 /* the file was decompressed after we started reading it */ 1849 *is_compressed = 0; /* instruct caller to fall back to its normal path */ 1850 } 1851 kr = KERN_FAILURE; 1852 abort_read = 1; /* we're not going to commit our data */ 1853 did_read = 0; 1854 } 1855 1856 /* zero out the remainder of the last page */ 1857 memset((char*)data + did_read, 0, (size_t)(curUplSize - did_read)); 1858 if (!err && verify_block_size) { 1859 size_t cur_verify_block_size = verify_block_size; 1860 1861 if ((err = VNOP_VERIFY(vp, curUplPos, data, curUplSize, &cur_verify_block_size, NULL, 0, NULL))) { 1862 ErrorLogWithPath("Verification failed with error %d\n", err); 1863 abort_read = 1; 1864 } 1865 /* XXX : If the verify block size changes, redo the read */ 1866 } 1867 1868 kr = ubc_upl_unmap(upl); 1869 if (kr != KERN_SUCCESS) { 1870 /* A failure to unmap here will eventually cause a panic anyway */ 1871 panic("ubc_upl_unmap returned error %d (kern_return_t)", (int)kr); 1872 } 1873 1874 if (abort_read) { 1875 kr = commit_upl(upl, 0, curUplSize, UPL_ABORT_FREE_ON_EMPTY, 1); 1876 } else { 1877 VerboseLogWithPath("uioPos %lld uioRemaining %lld\n", (uint64_t)uioPos, (uint64_t)uioRemaining); 1878 if (uioRemaining) { 1879 off_t uplOff = uioPos - curUplPos; 1880 if (uplOff < 0) { 1881 ErrorLogWithPath("uplOff %lld should never be negative\n", (int64_t)uplOff); 1882 err = EINVAL; 1883 } else if (uplOff > INT_MAX) { 1884 ErrorLogWithPath("uplOff %lld too large\n", (int64_t)uplOff); 1885 err = EINVAL; 1886 } else { 1887 off_t count = curUplPos + curUplSize - uioPos; 1888 if (count < 0) { 1889 /* this upl is entirely before the uio */ 1890 } else { 1891 if (count > uioRemaining) { 1892 count = uioRemaining; 1893 } 1894 int icount = (count > INT_MAX) ? INT_MAX : (int)count; 1895 int io_resid = icount; 1896 err = cluster_copy_upl_data(uio, upl, (int)uplOff, &io_resid); 1897 int copied = icount - io_resid; 1898 VerboseLogWithPath("uplOff %lld count %lld copied %lld\n", (uint64_t)uplOff, (uint64_t)count, (uint64_t)copied); 1899 if (err) { 1900 ErrorLogWithPath("cluster_copy_upl_data err %d\n", err); 1901 } 1902 uioPos += copied; 1903 uioRemaining -= copied; 1904 } 1905 } 1906 } 1907 kr = commit_upl(upl, 0, curUplSize, UPL_COMMIT_FREE_ON_EMPTY | UPL_COMMIT_INACTIVATE, 0); 1908 } 1909 1910 if (err) { 1911 goto out; 1912 } 1913 1914 uplRemaining -= curUplSize; 1915 } 1916 1917 out: 1918 1919 if (hdr != NULL) { 1920 kfree_data(hdr, alloc_size); 1921 } 1922 if (cmpdata_locked) { 1923 decmpfs_unlock_compressed_data(cp, 0); 1924 } 1925 if (err) {/* something went wrong */ 1926 ErrorLogWithPath("err %d\n", err); 1927 return err; 1928 } 1929 1930 #if COMPRESSION_DEBUG 1931 uplSize = uio_resid(uio); 1932 if (uplSize) { 1933 VerboseLogWithPath("still %lld bytes to copy\n", uplSize); 1934 } 1935 #endif 1936 return 0; 1937 } 1938 1939 int 1940 decmpfs_free_compressed_data(vnode_t vp, decmpfs_cnode *cp) 1941 { 1942 /* 1943 * call out to the decompressor to free remove any data associated with this compressed file 1944 * then delete the file's compression xattr 1945 */ 1946 decmpfs_header *hdr = NULL; 1947 size_t alloc_size = 0; 1948 1949 /* 1950 * Trace the following parameters on entry with event-id 0x03120010. 1951 * 1952 * @vp->v_id: vnode-id of the file for which to free compressed data. 1953 */ 1954 DECMPFS_EMIT_TRACE_ENTRY(DECMPDBG_FREE_COMPRESSED_DATA, vp->v_id); 1955 1956 int err = decmpfs_fetch_compressed_header(vp, cp, &hdr, 0, &alloc_size); 1957 if (err) { 1958 ErrorLogWithPath("decmpfs_fetch_compressed_header err %d\n", err); 1959 } else { 1960 lck_rw_lock_shared(&decompressorsLock); 1961 decmpfs_free_compressed_data_func free_data = decmp_get_func(vp, hdr->compression_type, free_data); 1962 if (free_data) { 1963 err = free_data(vp, decmpfs_ctx, hdr); 1964 } else { 1965 /* nothing to do, so no error */ 1966 err = 0; 1967 } 1968 lck_rw_unlock_shared(&decompressorsLock); 1969 1970 if (err != 0) { 1971 ErrorLogWithPath("decompressor err %d\n", err); 1972 } 1973 } 1974 /* 1975 * Trace the following parameters on return with event-id 0x03120010. 1976 * 1977 * @vp->v_id: vnode-id of the file for which to free compressed data. 1978 * @err: value returned from this function. 1979 */ 1980 DECMPFS_EMIT_TRACE_RETURN(DECMPDBG_FREE_COMPRESSED_DATA, vp->v_id, err); 1981 1982 /* delete the xattr */ 1983 err = vn_removexattr(vp, DECMPFS_XATTR_NAME, 0, decmpfs_ctx); 1984 1985 if (hdr != NULL) { 1986 kfree_data(hdr, alloc_size); 1987 } 1988 return err; 1989 } 1990 1991 #pragma mark --- file conversion routines --- 1992 1993 static int 1994 unset_compressed_flag(vnode_t vp) 1995 { 1996 int err = 0; 1997 struct vnode_attr va; 1998 struct fsioc_cas_bsdflags cas; 1999 int i; 2000 2001 # define MAX_CAS_BSDFLAGS_LOOPS 4 2002 /* UF_COMPRESSED should be manipulated only with FSIOC_CAS_BSDFLAGS */ 2003 for (i = 0; i < MAX_CAS_BSDFLAGS_LOOPS; i++) { 2004 VATTR_INIT(&va); 2005 VATTR_WANTED(&va, va_flags); 2006 err = vnode_getattr(vp, &va, decmpfs_ctx); 2007 if (err != 0) { 2008 ErrorLogWithPath("vnode_getattr err %d, num retries %d\n", err, i); 2009 goto out; 2010 } 2011 2012 cas.expected_flags = va.va_flags; 2013 cas.new_flags = va.va_flags & ~UF_COMPRESSED; 2014 err = VNOP_IOCTL(vp, FSIOC_CAS_BSDFLAGS, (caddr_t)&cas, FWRITE, decmpfs_ctx); 2015 2016 if ((err == 0) && (va.va_flags == cas.actual_flags)) { 2017 goto out; 2018 } 2019 2020 if ((err != 0) && (err != EAGAIN)) { 2021 break; 2022 } 2023 } 2024 2025 /* fallback to regular chflags if FSIOC_CAS_BSDFLAGS is not supported */ 2026 if (err == ENOTTY) { 2027 VATTR_INIT(&va); 2028 VATTR_SET(&va, va_flags, cas.new_flags); 2029 err = vnode_setattr(vp, &va, decmpfs_ctx); 2030 if (err != 0) { 2031 ErrorLogWithPath("vnode_setattr err %d\n", err); 2032 } 2033 } else if (va.va_flags != cas.actual_flags) { 2034 ErrorLogWithPath("FSIOC_CAS_BSDFLAGS err: flags mismatc. actual (%x) expected (%x), num retries %d\n", cas.actual_flags, va.va_flags, i); 2035 } else if (err != 0) { 2036 ErrorLogWithPath("FSIOC_CAS_BSDFLAGS err %d, num retries %d\n", err, i); 2037 } 2038 2039 out: 2040 return err; 2041 } 2042 2043 int 2044 decmpfs_decompress_file(vnode_t vp, decmpfs_cnode *cp, off_t toSize, int truncate_okay, int skiplock) 2045 { 2046 /* convert a compressed file to an uncompressed file */ 2047 2048 int err = 0; 2049 char *data = NULL; 2050 uio_t uio_w = 0; 2051 off_t offset = 0; 2052 uint32_t old_state = 0; 2053 uint32_t new_state = 0; 2054 int update_file_state = 0; 2055 size_t allocSize = 0; 2056 decmpfs_header *hdr = NULL; 2057 size_t hdr_size = 0; 2058 int cmpdata_locked = 0; 2059 off_t remaining = 0; 2060 uint64_t uncompressed_size = 0; 2061 2062 /* 2063 * Trace the following parameters on entry with event-id 0x03120000. 2064 * 2065 * @vp->v_id: vnode-id of the file being decompressed. 2066 * @toSize: uncompress given bytes of the file. 2067 * @truncate_okay: on error it is OK to truncate. 2068 * @skiplock: compressed data is locked, skip locking again. 2069 * 2070 * Please NOTE: @toSize can overflow in theory but here it is safe. 2071 */ 2072 DECMPFS_EMIT_TRACE_ENTRY(DECMPDBG_DECOMPRESS_FILE, vp->v_id, 2073 (int)toSize, truncate_okay, skiplock); 2074 2075 if (!skiplock) { 2076 decmpfs_lock_compressed_data(cp, 1); cmpdata_locked = 1; 2077 } 2078 2079 decompress: 2080 old_state = decmpfs_fast_get_state(cp); 2081 2082 switch (old_state) { 2083 case FILE_IS_NOT_COMPRESSED: 2084 { 2085 /* someone else decompressed the file */ 2086 err = 0; 2087 goto out; 2088 } 2089 2090 case FILE_TYPE_UNKNOWN: 2091 { 2092 /* the file is in an unknown state, so update the state and retry */ 2093 (void)decmpfs_file_is_compressed(vp, cp); 2094 2095 /* try again */ 2096 goto decompress; 2097 } 2098 2099 case FILE_IS_COMPRESSED: 2100 { 2101 /* the file is compressed, so decompress it */ 2102 break; 2103 } 2104 2105 default: 2106 { 2107 /* 2108 * this shouldn't happen since multiple calls to decmpfs_decompress_file lock each other out, 2109 * and when decmpfs_decompress_file returns, the state should be always be set back to 2110 * FILE_IS_NOT_COMPRESSED or FILE_IS_UNKNOWN 2111 */ 2112 err = EINVAL; 2113 goto out; 2114 } 2115 } 2116 2117 err = decmpfs_fetch_compressed_header(vp, cp, &hdr, 0, &hdr_size); 2118 if (err != 0) { 2119 goto out; 2120 } 2121 2122 uncompressed_size = hdr->uncompressed_size; 2123 if (toSize == -1) { 2124 toSize = hdr->uncompressed_size; 2125 } 2126 2127 if (toSize == 0) { 2128 /* special case truncating the file to zero bytes */ 2129 goto nodecmp; 2130 } else if ((uint64_t)toSize > hdr->uncompressed_size) { 2131 /* the caller is trying to grow the file, so we should decompress all the data */ 2132 toSize = hdr->uncompressed_size; 2133 } 2134 2135 allocSize = MIN(64 * 1024, (size_t)toSize); 2136 data = (char *)kalloc_data(allocSize, Z_WAITOK); 2137 if (!data) { 2138 err = ENOMEM; 2139 goto out; 2140 } 2141 2142 uio_w = uio_create(1, 0LL, UIO_SYSSPACE, UIO_WRITE); 2143 if (!uio_w) { 2144 err = ENOMEM; 2145 goto out; 2146 } 2147 uio_w->uio_flags |= UIO_FLAGS_IS_COMPRESSED_FILE; 2148 2149 remaining = toSize; 2150 2151 /* tell the buffer cache that this is an empty file */ 2152 ubc_setsize(vp, 0); 2153 2154 /* if we got here, we need to decompress the file */ 2155 decmpfs_cnode_set_vnode_state(cp, FILE_IS_CONVERTING, 1); 2156 2157 while (remaining > 0) { 2158 /* loop decompressing data from the file and writing it into the data fork */ 2159 2160 uint64_t bytes_read = 0; 2161 decmpfs_vector vec = { .buf = data, .size = (user_ssize_t)MIN(allocSize, remaining) }; 2162 err = decmpfs_fetch_uncompressed_data(vp, cp, hdr, offset, vec.size, 1, &vec, &bytes_read); 2163 if (err != 0) { 2164 ErrorLogWithPath("decmpfs_fetch_uncompressed_data err %d\n", err); 2165 goto out; 2166 } 2167 2168 if (bytes_read == 0) { 2169 /* we're done reading data */ 2170 break; 2171 } 2172 2173 uio_reset(uio_w, offset, UIO_SYSSPACE, UIO_WRITE); 2174 err = uio_addiov(uio_w, CAST_USER_ADDR_T(data), (user_size_t)bytes_read); 2175 if (err != 0) { 2176 ErrorLogWithPath("uio_addiov err %d\n", err); 2177 err = ENOMEM; 2178 goto out; 2179 } 2180 2181 err = VNOP_WRITE(vp, uio_w, 0, decmpfs_ctx); 2182 if (err != 0) { 2183 /* if the write failed, truncate the file to zero bytes */ 2184 ErrorLogWithPath("VNOP_WRITE err %d\n", err); 2185 break; 2186 } 2187 offset += bytes_read; 2188 remaining -= bytes_read; 2189 } 2190 2191 if (err == 0) { 2192 if (offset != toSize) { 2193 ErrorLogWithPath("file decompressed to %lld instead of %lld\n", offset, toSize); 2194 err = EINVAL; 2195 goto out; 2196 } 2197 } 2198 2199 if (err == 0) { 2200 /* sync the data and metadata */ 2201 err = VNOP_FSYNC(vp, MNT_WAIT, decmpfs_ctx); 2202 if (err != 0) { 2203 ErrorLogWithPath("VNOP_FSYNC err %d\n", err); 2204 goto out; 2205 } 2206 } 2207 2208 if (err != 0) { 2209 /* write, setattr, or fsync failed */ 2210 ErrorLogWithPath("aborting decompress, err %d\n", err); 2211 if (truncate_okay) { 2212 /* truncate anything we might have written */ 2213 int error = vnode_setsize(vp, 0, 0, decmpfs_ctx); 2214 ErrorLogWithPath("vnode_setsize err %d\n", error); 2215 } 2216 goto out; 2217 } 2218 2219 nodecmp: 2220 /* if we're truncating the file to zero bytes, we'll skip ahead to here */ 2221 2222 /* unset the compressed flag */ 2223 unset_compressed_flag(vp); 2224 2225 /* free the compressed data associated with this file */ 2226 err = decmpfs_free_compressed_data(vp, cp); 2227 if (err != 0) { 2228 ErrorLogWithPath("decmpfs_free_compressed_data err %d\n", err); 2229 } 2230 2231 /* 2232 * even if free_compressed_data or vnode_getattr/vnode_setattr failed, return success 2233 * since we succeeded in writing all of the file data to the data fork 2234 */ 2235 err = 0; 2236 2237 /* if we got this far, the file was successfully decompressed */ 2238 update_file_state = 1; 2239 new_state = FILE_IS_NOT_COMPRESSED; 2240 2241 #if COMPRESSION_DEBUG 2242 { 2243 uint64_t filesize = 0; 2244 vnsize(vp, &filesize); 2245 DebugLogWithPath("new file size %lld\n", filesize); 2246 } 2247 #endif 2248 2249 out: 2250 if (hdr != NULL) { 2251 kfree_data(hdr, hdr_size); 2252 } 2253 kfree_data(data, allocSize); 2254 2255 if (uio_w) { 2256 uio_free(uio_w); 2257 } 2258 2259 if (err != 0) { 2260 /* if there was a failure, reset compression flags to unknown and clear the buffer cache data */ 2261 update_file_state = 1; 2262 new_state = FILE_TYPE_UNKNOWN; 2263 if (uncompressed_size) { 2264 ubc_setsize(vp, 0); 2265 ubc_setsize(vp, uncompressed_size); 2266 } 2267 } 2268 2269 if (update_file_state) { 2270 lck_mtx_lock(&decompress_channel_mtx); 2271 decmpfs_cnode_set_vnode_state(cp, new_state, 1); 2272 wakeup((caddr_t)&decompress_channel); /* wake up anyone who might have been waiting for decompression */ 2273 lck_mtx_unlock(&decompress_channel_mtx); 2274 } 2275 2276 if (cmpdata_locked) { 2277 decmpfs_unlock_compressed_data(cp, 1); 2278 } 2279 /* 2280 * Trace the following parameters on return with event-id 0x03120000. 2281 * 2282 * @vp->v_id: vnode-id of the file being decompressed. 2283 * @err: value returned from this function. 2284 */ 2285 DECMPFS_EMIT_TRACE_RETURN(DECMPDBG_DECOMPRESS_FILE, vp->v_id, err); 2286 return err; 2287 } 2288 2289 #pragma mark --- Type1 compressor --- 2290 2291 /* 2292 * The "Type1" compressor stores the data fork directly in the compression xattr 2293 */ 2294 2295 static int 2296 decmpfs_validate_compressed_file_Type1(__unused vnode_t vp, __unused vfs_context_t ctx, decmpfs_header *hdr) 2297 { 2298 int err = 0; 2299 2300 if (hdr->uncompressed_size + sizeof(decmpfs_disk_header) != (uint64_t)hdr->attr_size) { 2301 err = EINVAL; 2302 goto out; 2303 } 2304 out: 2305 return err; 2306 } 2307 2308 static int 2309 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) 2310 { 2311 int err = 0; 2312 int i; 2313 user_ssize_t remaining; 2314 2315 if (hdr->uncompressed_size + sizeof(decmpfs_disk_header) != (uint64_t)hdr->attr_size) { 2316 err = EINVAL; 2317 goto out; 2318 } 2319 2320 #if COMPRESSION_DEBUG 2321 static int dummy = 0; // prevent syslog from coalescing printfs 2322 DebugLogWithPath("%d memcpy %lld at %lld\n", dummy++, size, (uint64_t)offset); 2323 #endif 2324 2325 remaining = size; 2326 for (i = 0; (i < nvec) && (remaining > 0); i++) { 2327 user_ssize_t curCopy = vec[i].size; 2328 if (curCopy > remaining) { 2329 curCopy = remaining; 2330 } 2331 memcpy(vec[i].buf, hdr->attr_bytes + offset, curCopy); 2332 offset += curCopy; 2333 remaining -= curCopy; 2334 } 2335 2336 if ((bytes_read) && (err == 0)) { 2337 *bytes_read = (size - remaining); 2338 } 2339 2340 out: 2341 return err; 2342 } 2343 2344 SECURITY_READ_ONLY_EARLY(static decmpfs_registration) Type1Reg = 2345 { 2346 .decmpfs_registration = DECMPFS_REGISTRATION_VERSION, 2347 .validate = decmpfs_validate_compressed_file_Type1, 2348 .adjust_fetch = NULL,/* no adjust necessary */ 2349 .fetch = decmpfs_fetch_uncompressed_data_Type1, 2350 .free_data = NULL,/* no free necessary */ 2351 .get_flags = NULL/* no flags */ 2352 }; 2353 2354 #pragma mark --- decmpfs initialization --- 2355 2356 void 2357 decmpfs_init(void) 2358 { 2359 static int done = 0; 2360 if (done) { 2361 return; 2362 } 2363 2364 decmpfs_ctx = vfs_context_create(vfs_context_kernel()); 2365 2366 register_decmpfs_decompressor(CMP_Type1, &Type1Reg); 2367 2368 ktriage_register_subsystem_strings(KDBG_TRIAGE_SUBSYS_DECMPFS, &ktriage_decmpfs_subsystem_strings); 2369 2370 done = 1; 2371 } 2372 #endif /* FS_COMPRESSION */ 2373