1    	/*
2    	 * Ceph - scalable distributed file system
3    	 *
4    	 * Copyright (C) 2015 Mirantis, Inc.
5    	 *
6    	 * Author: Alyona Kiseleva <akiselyova@mirantis.com>
7    	 *
8    	 *  This library is free software; you can redistribute it and/or
9    	 *  modify it under the terms of the GNU Lesser General Public
10   	 *  License as published by the Free Software Foundation; either
11   	 *  version 2.1 of the License, or (at your option) any later version.
12   	 *
13   	 */
14   	
15   	// -----------------------------------------------------------------------------
16   	#include "common/debug.h"
17   	#include "ZlibCompressor.h"
18   	#include "osd/osd_types.h"
19   	#include "isa-l/include/igzip_lib.h"
20   	// -----------------------------------------------------------------------------
21   	
22   	#include <zlib.h>
23   	
24   	// -----------------------------------------------------------------------------
25   	#define dout_context cct
26   	#define dout_subsys ceph_subsys_compressor
27   	#undef dout_prefix
28   	#define dout_prefix _prefix(_dout)
29   	// -----------------------------------------------------------------------------
30   	
31   	// -----------------------------------------------------------------------------
32   	
33   	static ostream&
34   	_prefix(std::ostream* _dout)
35   	{
36   	  return *_dout << "ZlibCompressor: ";
37   	}
38   	// -----------------------------------------------------------------------------
39   	
40   	#define MAX_LEN (CEPH_PAGE_SIZE)
41   	
42   	// default window size for Zlib 1.2.8, negated for raw deflate
43   	#define ZLIB_DEFAULT_WIN_SIZE -15
44   	
45   	// desired memory usage level. increasing to 9 doesn't speed things up
46   	// significantly (helps only on >=16K blocks) and sometimes degrades
47   	// compression ratio.
48   	#define ZLIB_MEMORY_LEVEL 8
49   	
50   	int ZlibCompressor::zlib_compress(const bufferlist &in, bufferlist &out)
51   	{
52   	  int ret;
53   	  unsigned have;
54   	  z_stream strm;
55   	  unsigned char* c_in;
56   	  int begin = 1;
57   	
58   	  /* allocate deflate state */
59   	  strm.zalloc = Z_NULL;
60   	  strm.zfree = Z_NULL;
61   	  strm.opaque = Z_NULL;
62   	  ret = deflateInit2(&strm, cct->_conf->compressor_zlib_level, Z_DEFLATED, ZLIB_DEFAULT_WIN_SIZE, ZLIB_MEMORY_LEVEL, Z_DEFAULT_STRATEGY);
63   	  if (ret != Z_OK) {
64   	    dout(1) << "Compression init error: init return "
65   	         << ret << " instead of Z_OK" << dendl;
66   	    return -1;
67   	  }
68   	
69   	  for (ceph::bufferlist::buffers_t::const_iterator i = in.buffers().begin();
70   	      i != in.buffers().end();) {
71   	
72   	    c_in = (unsigned char*) (*i).c_str();
73   	    long unsigned int len = (*i).length();
74   	    ++i;
75   	
76   	    strm.avail_in = len;
77   	    int flush = i != in.buffers().end() ? Z_NO_FLUSH : Z_FINISH;
78   	
79   	    strm.next_in = c_in;
80   	    do {
81   	      bufferptr ptr = buffer::create_page_aligned(MAX_LEN);
82   	      strm.next_out = (unsigned char*)ptr.c_str() + begin;
83   	      strm.avail_out = MAX_LEN - begin;
84   	      if (begin) {
85   	        // put a compressor variation mark in front of compressed stream, not used at the moment
86   	        ptr.c_str()[0] = 0;
87   	        begin = 0;
88   	      }
89   	      ret = deflate(&strm, flush);    /* no bad return value */
90   	      if (ret == Z_STREAM_ERROR) {
91   	         dout(1) << "Compression error: compress return Z_STREAM_ERROR("
92   	              << ret << ")" << dendl;
93   	         deflateEnd(&strm);
94   	         return -1;
95   	      }
96   	      have = MAX_LEN - strm.avail_out;
97   	      out.append(ptr, 0, have);
98   	    } while (strm.avail_out == 0);
99   	    if (strm.avail_in != 0) {
100  	      dout(10) << "Compression error: unused input" << dendl;
101  	      deflateEnd(&strm);
102  	      return -1;
103  	    }
104  	  }
105  	
106  	  deflateEnd(&strm);
107  	  return 0;
108  	}
109  	
110  	#if __x86_64__ && defined(HAVE_BETTER_YASM_ELF64)
111  	int ZlibCompressor::isal_compress(const bufferlist &in, bufferlist &out)
112  	{
113  	  int ret;
114  	  unsigned have;
(1) Event stack_use_local_overflow: Local variable "strm" uses 84608 bytes of stack space, which exceeds the maximum single use of 10000 bytes.
115  	  isal_zstream strm;
116  	  unsigned char* c_in;
117  	  int begin = 1;
118  	
119  	  /* allocate deflate state */
120  	  isal_deflate_init(&strm);
121  	  strm.end_of_stream = 0;
122  	
123  	  for (ceph::bufferlist::buffers_t::const_iterator i = in.buffers().begin();
124  	      i != in.buffers().end();) {
125  	
126  	    c_in = (unsigned char*) (*i).c_str();
127  	    long unsigned int len = (*i).length();
128  	    ++i;
129  	
130  	    strm.avail_in = len;
131  	    strm.end_of_stream = (i == in.buffers().end());
132  	    strm.flush = FINISH_FLUSH;
133  	
134  	    strm.next_in = c_in;
135  	
136  	    do {
137  	      bufferptr ptr = buffer::create_page_aligned(MAX_LEN);
138  	      strm.next_out = (unsigned char*)ptr.c_str() + begin;
139  	      strm.avail_out = MAX_LEN - begin;
140  	      if (begin) {
141  	        // put a compressor variation mark in front of compressed stream, not used at the moment
142  	        ptr.c_str()[0] = 1;
143  	        begin = 0;
144  	      }
145  	      ret = isal_deflate(&strm);
146  	      if (ret != COMP_OK) {
147  	         dout(1) << "Compression error: isal_deflate return error ("
148  	              << ret << ")" << dendl;
149  	         return -1;
150  	      }
151  	      have = MAX_LEN - strm.avail_out;
152  	      out.append(ptr, 0, have);
153  	    } while (strm.avail_out == 0);
154  	    if (strm.avail_in != 0) {
155  	      dout(10) << "Compression error: unused input" << dendl;
156  	      return -1;
157  	    }
158  	  }
159  	
160  	  return 0;  
161  	}
162  	#endif
163  	
164  	int ZlibCompressor::compress(const bufferlist &in, bufferlist &out)
165  	{
166  	#ifdef HAVE_QATZIP
167  	  if (qat_enabled)
168  	    return qat_accel.compress(in, out);
169  	#endif
170  	#if __x86_64__ && defined(HAVE_BETTER_YASM_ELF64)
171  	  if (isal_enabled)
172  	    return isal_compress(in, out);
173  	  else
174  	    return zlib_compress(in, out);
175  	#else
176  	  return zlib_compress(in, out);
177  	#endif
178  	}
179  	
180  	int ZlibCompressor::decompress(bufferlist::const_iterator &p, size_t compressed_size, bufferlist &out)
181  	{
182  	#ifdef HAVE_QATZIP
183  	  if (qat_enabled)
184  	    return qat_accel.decompress(p, compressed_size, out);
185  	#endif
186  	
187  	  int ret;
188  	  unsigned have;
189  	  z_stream strm;
190  	  const char* c_in;
191  	  int begin = 1;
192  	
193  	  /* allocate inflate state */
194  	  strm.zalloc = Z_NULL;
195  	  strm.zfree = Z_NULL;
196  	  strm.opaque = Z_NULL;
197  	  strm.avail_in = 0;
198  	  strm.next_in = Z_NULL;
199  	
200  	  // choose the variation of compressor
201  	  ret = inflateInit2(&strm, ZLIB_DEFAULT_WIN_SIZE);
202  	  if (ret != Z_OK) {
203  	    dout(1) << "Decompression init error: init return "
204  	         << ret << " instead of Z_OK" << dendl;
205  	    return -1;
206  	  }
207  	
208  	  size_t remaining = std::min<size_t>(p.get_remaining(), compressed_size);
209  	
210  	  while(remaining) {
211  	    long unsigned int len = p.get_ptr_and_advance(remaining, &c_in);
212  	    remaining -= len;
213  	    strm.avail_in = len - begin;
214  	    strm.next_in = (unsigned char*)c_in + begin;
215  	    begin = 0;
216  	
217  	    do {
218  	      strm.avail_out = MAX_LEN;
219  	      bufferptr ptr = buffer::create_page_aligned(MAX_LEN);
220  	      strm.next_out = (unsigned char*)ptr.c_str();
221  	      ret = inflate(&strm, Z_NO_FLUSH);
222  	      if (ret != Z_OK && ret != Z_STREAM_END && ret != Z_BUF_ERROR) {
223  	       dout(1) << "Decompression error: decompress return "
224  	            << ret << dendl;
225  	       inflateEnd(&strm);
226  	       return -1;
227  	      }
228  	      have = MAX_LEN - strm.avail_out;
229  	      out.append(ptr, 0, have);
230  	    } while (strm.avail_out == 0);
231  	  }
232  	
233  	  /* clean up and return */
234  	  (void)inflateEnd(&strm);
235  	  return 0;
236  	}
237  	
238  	int ZlibCompressor::decompress(const bufferlist &in, bufferlist &out)
239  	{
240  	#ifdef HAVE_QATZIP
241  	  if (qat_enabled)
242  	    return qat_accel.decompress(in, out);
243  	#endif
244  	  auto i = std::cbegin(in);
245  	  return decompress(i, in.length(), out);
246  	}
247