1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/zfs_context.h> 29 #include <sys/compress.h> 30 #include <sys/spa.h> 31 #include <sys/zio.h> 32 #include <sys/zio_compress.h> 33 34 /* 35 * Compression vectors. 36 */ 37 38 zio_compress_info_t zio_compress_table[ZIO_COMPRESS_FUNCTIONS] = { 39 {NULL, NULL, "inherit"}, 40 {NULL, NULL, "on"}, 41 {NULL, NULL, "uncompressed"}, 42 {lzjb_compress, lzjb_decompress, "lzjb"}, 43 }; 44 45 uint8_t 46 zio_compress_select(uint8_t child, uint8_t parent) 47 { 48 ASSERT(child < ZIO_COMPRESS_FUNCTIONS); 49 ASSERT(parent < ZIO_COMPRESS_FUNCTIONS); 50 ASSERT(parent != ZIO_COMPRESS_INHERIT && parent != ZIO_COMPRESS_ON); 51 52 if (child == ZIO_COMPRESS_INHERIT) 53 return (parent); 54 55 if (child == ZIO_COMPRESS_ON) 56 return (ZIO_COMPRESS_ON_VALUE); 57 58 return (child); 59 } 60 61 int 62 zio_compress_data(int cpfunc, void *src, uint64_t srcsize, void **destp, 63 uint64_t *destsizep, uint64_t *destbufsizep) 64 { 65 uint64_t *word, *word_end; 66 uint64_t ciosize, gapsize, destbufsize; 67 zio_compress_info_t *ci = &zio_compress_table[cpfunc]; 68 char *dest; 69 uint_t allzero; 70 71 ASSERT((uint_t)cpfunc < ZIO_COMPRESS_FUNCTIONS); 72 ASSERT(ci->ci_compress != NULL); 73 74 /* 75 * If the data is all zeroes, we don't even need to allocate 76 * a block for it. We indicate this by setting *destsizep = 0. 77 */ 78 allzero = 1; 79 word = src; 80 word_end = (uint64_t *)(uintptr_t)((uintptr_t)word + srcsize); 81 while (word < word_end) { 82 if (*word++ != 0) { 83 allzero = 0; 84 break; 85 } 86 } 87 if (allzero) { 88 *destp = NULL; 89 *destsizep = 0; 90 *destbufsizep = 0; 91 return (1); 92 } 93 94 /* Compress at least 12.5% */ 95 destbufsize = P2ALIGN(srcsize - (srcsize >> 3), SPA_MINBLOCKSIZE); 96 if (destbufsize == 0) 97 return (0); 98 dest = zio_buf_alloc(destbufsize); 99 100 ciosize = ci->ci_compress(src, dest, (size_t)srcsize, 101 (size_t)destbufsize); 102 if (ciosize > destbufsize) { 103 zio_buf_free(dest, destbufsize); 104 return (0); 105 } 106 107 /* Cool. We compressed at least as much as we were hoping to. */ 108 109 /* For security, make sure we don't write random heap crap to disk */ 110 gapsize = P2ROUNDUP(ciosize, SPA_MINBLOCKSIZE) - ciosize; 111 if (gapsize != 0) { 112 bzero(dest + ciosize, gapsize); 113 ciosize += gapsize; 114 } 115 116 ASSERT3U(ciosize, <=, destbufsize); 117 ASSERT(P2PHASE(ciosize, SPA_MINBLOCKSIZE) == 0); 118 *destp = dest; 119 *destsizep = ciosize; 120 *destbufsizep = destbufsize; 121 122 return (1); 123 } 124 125 int 126 zio_decompress_data(int cpfunc, void *src, uint64_t srcsize, 127 void *dest, uint64_t destsize) 128 { 129 ASSERT((uint_t)cpfunc < ZIO_COMPRESS_FUNCTIONS); 130 131 return (zio_compress_table[cpfunc].ci_decompress(src, dest, 132 srcsize, destsize)); 133 } 134