1168404Spjd/* 2168404Spjd * CDDL HEADER START 3168404Spjd * 4168404Spjd * The contents of this file are subject to the terms of the 5168404Spjd * Common Development and Distribution License (the "License"). 6168404Spjd * You may not use this file except in compliance with the License. 7168404Spjd * 8168404Spjd * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9168404Spjd * or http://www.opensolaris.org/os/licensing. 10168404Spjd * See the License for the specific language governing permissions 11168404Spjd * and limitations under the License. 12168404Spjd * 13168404Spjd * When distributing Covered Code, include this CDDL HEADER in each 14168404Spjd * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15168404Spjd * If applicable, add the following below this CDDL HEADER, with the 16168404Spjd * fields enclosed by brackets "[]" replaced with your own identifying 17168404Spjd * information: Portions Copyright [yyyy] [name of copyright owner] 18168404Spjd * 19168404Spjd * CDDL HEADER END 20168404Spjd */ 21168404Spjd 22168404Spjd/* 23219089Spjd * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24168404Spjd * Use is subject to license terms. 25168404Spjd */ 26246586Sdelphij/* 27246586Sdelphij * Copyright (c) 2013 by Saso Kiselkov. All rights reserved. 28246586Sdelphij */ 29168404Spjd 30249195Smm/* 31249195Smm * Copyright (c) 2013 by Delphix. All rights reserved. 32249195Smm */ 33249195Smm 34168404Spjd#include <sys/zfs_context.h> 35168404Spjd#include <sys/compress.h> 36254608Sgibbs#include <sys/kstat.h> 37168404Spjd#include <sys/spa.h> 38288542Smav#include <sys/zfeature.h> 39168404Spjd#include <sys/zio.h> 40168404Spjd#include <sys/zio_compress.h> 41168404Spjd 42254608Sgibbstypedef struct zcomp_stats { 43254608Sgibbs kstat_named_t zcompstat_attempts; 44254608Sgibbs kstat_named_t zcompstat_empty; 45254608Sgibbs kstat_named_t zcompstat_skipped_insufficient_gain; 46254608Sgibbs} zcomp_stats_t; 47254608Sgibbs 48254608Sgibbsstatic zcomp_stats_t zcomp_stats = { 49254608Sgibbs { "attempts", KSTAT_DATA_UINT64 }, 50254608Sgibbs { "empty", KSTAT_DATA_UINT64 }, 51254608Sgibbs { "skipped_insufficient_gain", KSTAT_DATA_UINT64 } 52254608Sgibbs}; 53254608Sgibbs 54254608Sgibbs#define ZCOMPSTAT_INCR(stat, val) \ 55254608Sgibbs atomic_add_64(&zcomp_stats.stat.value.ui64, (val)); 56254608Sgibbs 57254608Sgibbs#define ZCOMPSTAT_BUMP(stat) ZCOMPSTAT_INCR(stat, 1); 58254608Sgibbs 59254608Sgibbskstat_t *zcomp_ksp; 60254608Sgibbs 61168404Spjd/* 62168404Spjd * Compression vectors. 63168404Spjd */ 64168404Spjd 65168404Spjdzio_compress_info_t zio_compress_table[ZIO_COMPRESS_FUNCTIONS] = { 66168404Spjd {NULL, NULL, 0, "inherit"}, 67168404Spjd {NULL, NULL, 0, "on"}, 68168404Spjd {NULL, NULL, 0, "uncompressed"}, 69168404Spjd {lzjb_compress, lzjb_decompress, 0, "lzjb"}, 70168404Spjd {NULL, NULL, 0, "empty"}, 71168404Spjd {gzip_compress, gzip_decompress, 1, "gzip-1"}, 72168404Spjd {gzip_compress, gzip_decompress, 2, "gzip-2"}, 73168404Spjd {gzip_compress, gzip_decompress, 3, "gzip-3"}, 74168404Spjd {gzip_compress, gzip_decompress, 4, "gzip-4"}, 75168404Spjd {gzip_compress, gzip_decompress, 5, "gzip-5"}, 76168404Spjd {gzip_compress, gzip_decompress, 6, "gzip-6"}, 77168404Spjd {gzip_compress, gzip_decompress, 7, "gzip-7"}, 78168404Spjd {gzip_compress, gzip_decompress, 8, "gzip-8"}, 79168404Spjd {gzip_compress, gzip_decompress, 9, "gzip-9"}, 80219089Spjd {zle_compress, zle_decompress, 64, "zle"}, 81246586Sdelphij {lz4_compress, lz4_decompress, 0, "lz4"}, 82168404Spjd}; 83168404Spjd 84219089Spjdenum zio_compress 85288542Smavzio_compress_select(spa_t *spa, enum zio_compress child, 86288542Smav enum zio_compress parent) 87168404Spjd{ 88288542Smav enum zio_compress result; 89288542Smav 90168404Spjd ASSERT(child < ZIO_COMPRESS_FUNCTIONS); 91168404Spjd ASSERT(parent < ZIO_COMPRESS_FUNCTIONS); 92288542Smav ASSERT(parent != ZIO_COMPRESS_INHERIT); 93168404Spjd 94288542Smav result = child; 95288542Smav if (result == ZIO_COMPRESS_INHERIT) 96288542Smav result = parent; 97168404Spjd 98288542Smav if (result == ZIO_COMPRESS_ON) { 99288542Smav if (spa_feature_is_active(spa, SPA_FEATURE_LZ4_COMPRESS)) 100288542Smav result = ZIO_COMPRESS_LZ4_ON_VALUE; 101288542Smav else 102288542Smav result = ZIO_COMPRESS_LEGACY_ON_VALUE; 103288542Smav } 104168404Spjd 105288542Smav return (result); 106168404Spjd} 107168404Spjd 108219089Spjdsize_t 109269732Sdelphijzio_compress_data(enum zio_compress c, void *src, void *dst, size_t s_len) 110168404Spjd{ 111168404Spjd uint64_t *word, *word_end; 112268649Sdelphij size_t c_len, d_len; 113219089Spjd zio_compress_info_t *ci = &zio_compress_table[c]; 114168404Spjd 115219089Spjd ASSERT((uint_t)c < ZIO_COMPRESS_FUNCTIONS); 116219089Spjd ASSERT((uint_t)c == ZIO_COMPRESS_EMPTY || ci->ci_compress != NULL); 117168404Spjd 118254608Sgibbs ZCOMPSTAT_BUMP(zcompstat_attempts); 119254608Sgibbs 120168404Spjd /* 121168404Spjd * If the data is all zeroes, we don't even need to allocate 122219089Spjd * a block for it. We indicate this by returning zero size. 123168404Spjd */ 124219089Spjd word_end = (uint64_t *)((char *)src + s_len); 125219089Spjd for (word = src; word < word_end; word++) 126219089Spjd if (*word != 0) 127168404Spjd break; 128168404Spjd 129254608Sgibbs if (word == word_end) { 130254608Sgibbs ZCOMPSTAT_BUMP(zcompstat_empty); 131254608Sgibbs return (0); 132254608Sgibbs } 133168404Spjd 134219089Spjd if (c == ZIO_COMPRESS_EMPTY) 135219089Spjd return (s_len); 136219089Spjd 137168404Spjd /* Compress at least 12.5% */ 138268649Sdelphij d_len = s_len - (s_len >> 3); 139219089Spjd c_len = ci->ci_compress(src, dst, s_len, d_len, ci->ci_level); 140168404Spjd 141254608Sgibbs if (c_len > d_len) { 142254608Sgibbs ZCOMPSTAT_BUMP(zcompstat_skipped_insufficient_gain); 143219089Spjd return (s_len); 144254608Sgibbs } 145168404Spjd 146219089Spjd ASSERT3U(c_len, <=, d_len); 147219089Spjd return (c_len); 148168404Spjd} 149168404Spjd 150168404Spjdint 151219089Spjdzio_decompress_data(enum zio_compress c, void *src, void *dst, 152219089Spjd size_t s_len, size_t d_len) 153168404Spjd{ 154219089Spjd zio_compress_info_t *ci = &zio_compress_table[c]; 155168404Spjd 156219089Spjd if ((uint_t)c >= ZIO_COMPRESS_FUNCTIONS || ci->ci_decompress == NULL) 157249195Smm return (SET_ERROR(EINVAL)); 158168404Spjd 159219089Spjd return (ci->ci_decompress(src, dst, s_len, d_len, ci->ci_level)); 160168404Spjd} 161254608Sgibbs 162254608Sgibbsvoid 163254608Sgibbszio_compress_init(void) 164254608Sgibbs{ 165254608Sgibbs 166254608Sgibbs zcomp_ksp = kstat_create("zfs", 0, "zcompstats", "misc", 167254608Sgibbs KSTAT_TYPE_NAMED, sizeof (zcomp_stats) / sizeof (kstat_named_t), 168254608Sgibbs KSTAT_FLAG_VIRTUAL); 169254608Sgibbs 170254608Sgibbs if (zcomp_ksp != NULL) { 171254608Sgibbs zcomp_ksp->ks_data = &zcomp_stats; 172254608Sgibbs kstat_install(zcomp_ksp); 173254608Sgibbs } 174254608Sgibbs} 175254608Sgibbs 176254608Sgibbsvoid 177254608Sgibbszio_compress_fini(void) 178254608Sgibbs{ 179254608Sgibbs if (zcomp_ksp != NULL) { 180254608Sgibbs kstat_delete(zcomp_ksp); 181254608Sgibbs zcomp_ksp = NULL; 182254608Sgibbs } 183254608Sgibbs} 184