Home | History | Annotate | Line # | Download | only in zfs
      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 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 /*
     27  * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
     28  */
     29 
     30 /*
     31  * Copyright (c) 2013 by Delphix. All rights reserved.
     32  */
     33 
     34 #include <sys/zfs_context.h>
     35 #include <sys/compress.h>
     36 #include <sys/kstat.h>
     37 #include <sys/spa.h>
     38 #include <sys/zfeature.h>
     39 #include <sys/zio.h>
     40 #include <sys/zio_compress.h>
     41 
     42 typedef struct zcomp_stats {
     43 	kstat_named_t zcompstat_attempts;
     44 	kstat_named_t zcompstat_empty;
     45 	kstat_named_t zcompstat_skipped_insufficient_gain;
     46 } zcomp_stats_t;
     47 
     48 static zcomp_stats_t zcomp_stats = {
     49 	{ "attempts",			KSTAT_DATA_UINT64 },
     50 	{ "empty",			KSTAT_DATA_UINT64 },
     51 	{ "skipped_insufficient_gain",	KSTAT_DATA_UINT64 }
     52 };
     53 
     54 #define	ZCOMPSTAT_INCR(stat, val) \
     55 	atomic_add_64(&zcomp_stats.stat.value.ui64, (val));
     56 
     57 #define	ZCOMPSTAT_BUMP(stat)		ZCOMPSTAT_INCR(stat, 1);
     58 
     59 kstat_t		*zcomp_ksp;
     60 
     61 /*
     62  * Compression vectors.
     63  */
     64 
     65 zio_compress_info_t zio_compress_table[ZIO_COMPRESS_FUNCTIONS] = {
     66 	{NULL,			NULL,			0,	"inherit"},
     67 	{NULL,			NULL,			0,	"on"},
     68 	{NULL,			NULL,			0,	"uncompressed"},
     69 	{lzjb_compress,		lzjb_decompress,	0,	"lzjb"},
     70 	{NULL,			NULL,			0,	"empty"},
     71 	{gzip_compress,		gzip_decompress,	1,	"gzip-1"},
     72 	{gzip_compress,		gzip_decompress,	2,	"gzip-2"},
     73 	{gzip_compress,		gzip_decompress,	3,	"gzip-3"},
     74 	{gzip_compress,		gzip_decompress,	4,	"gzip-4"},
     75 	{gzip_compress,		gzip_decompress,	5,	"gzip-5"},
     76 	{gzip_compress,		gzip_decompress,	6,	"gzip-6"},
     77 	{gzip_compress,		gzip_decompress,	7,	"gzip-7"},
     78 	{gzip_compress,		gzip_decompress,	8,	"gzip-8"},
     79 	{gzip_compress,		gzip_decompress,	9,	"gzip-9"},
     80 	{zle_compress,		zle_decompress,		64,	"zle"},
     81 	{lz4_compress,		lz4_decompress,		0,	"lz4"},
     82 };
     83 
     84 enum zio_compress
     85 zio_compress_select(spa_t *spa, enum zio_compress child,
     86     enum zio_compress parent)
     87 {
     88 	enum zio_compress result;
     89 
     90 	ASSERT(child < ZIO_COMPRESS_FUNCTIONS);
     91 	ASSERT(parent < ZIO_COMPRESS_FUNCTIONS);
     92 	ASSERT(parent != ZIO_COMPRESS_INHERIT);
     93 
     94 	result = child;
     95 	if (result == ZIO_COMPRESS_INHERIT)
     96 		result = parent;
     97 
     98 	if (result == ZIO_COMPRESS_ON) {
     99 		if (spa_feature_is_active(spa, SPA_FEATURE_LZ4_COMPRESS))
    100 			result = ZIO_COMPRESS_LZ4_ON_VALUE;
    101 		else
    102 			result = ZIO_COMPRESS_LEGACY_ON_VALUE;
    103 	}
    104 
    105 	return (result);
    106 }
    107 
    108 size_t
    109 zio_compress_data(enum zio_compress c, void *src, void *dst, size_t s_len)
    110 {
    111 	uint64_t *word, *word_end;
    112 	size_t c_len, d_len;
    113 	zio_compress_info_t *ci = &zio_compress_table[c];
    114 
    115 	ASSERT((uint_t)c < ZIO_COMPRESS_FUNCTIONS);
    116 	ASSERT((uint_t)c == ZIO_COMPRESS_EMPTY || ci->ci_compress != NULL);
    117 
    118 	ZCOMPSTAT_BUMP(zcompstat_attempts);
    119 
    120 	/*
    121 	 * If the data is all zeroes, we don't even need to allocate
    122 	 * a block for it.  We indicate this by returning zero size.
    123 	 */
    124 	word_end = (uint64_t *)((char *)src + s_len);
    125 	for (word = src; word < word_end; word++)
    126 		if (*word != 0)
    127 			break;
    128 
    129 	if (word == word_end) {
    130 		ZCOMPSTAT_BUMP(zcompstat_empty);
    131  		return (0);
    132 	}
    133 
    134 	if (c == ZIO_COMPRESS_EMPTY)
    135 		return (s_len);
    136 
    137 	/* Compress at least 12.5% */
    138 	d_len = s_len - (s_len >> 3);
    139 	c_len = ci->ci_compress(src, dst, s_len, d_len, ci->ci_level);
    140 
    141 	if (c_len > d_len) {
    142 		ZCOMPSTAT_BUMP(zcompstat_skipped_insufficient_gain);
    143 		return (s_len);
    144 	}
    145 
    146 	ASSERT3U(c_len, <=, d_len);
    147 	return (c_len);
    148 }
    149 
    150 int
    151 zio_decompress_data(enum zio_compress c, void *src, void *dst,
    152     size_t s_len, size_t d_len)
    153 {
    154 	zio_compress_info_t *ci = &zio_compress_table[c];
    155 
    156 	if ((uint_t)c >= ZIO_COMPRESS_FUNCTIONS || ci->ci_decompress == NULL)
    157 		return (SET_ERROR(EINVAL));
    158 
    159 	return (ci->ci_decompress(src, dst, s_len, d_len, ci->ci_level));
    160 }
    161 
    162 void
    163 zio_compress_init(void)
    164 {
    165 
    166 	zcomp_ksp = kstat_create("zfs", 0, "zcompstats", "misc",
    167 	    KSTAT_TYPE_NAMED, sizeof (zcomp_stats) / sizeof (kstat_named_t),
    168 	    KSTAT_FLAG_VIRTUAL);
    169 
    170 	if (zcomp_ksp != NULL) {
    171 		zcomp_ksp->ks_data = &zcomp_stats;
    172 		kstat_install(zcomp_ksp);
    173 	}
    174 }
    175 
    176 void
    177 zio_compress_fini(void)
    178 {
    179 	if (zcomp_ksp != NULL) {
    180 		kstat_delete(zcomp_ksp);
    181 		zcomp_ksp = NULL;
    182 	}
    183 }
    184