Resolve QAT issues with incompressible data

Currently, when ZFS wants to accelerate compression with QAT, it
passes a destination buffer of the same size as the source buffer.
Unfortunately, if the data is incompressible, QAT can actually
"compress" the data to be larger than the source buffer. When this
happens, the QAT driver will return a FAILED error code and print
warnings to dmesg. This patch fixes these issues by providing the
QAT driver with an additional buffer to work with so that even
completely incompressible source data will not cause an overflow.

This patch also resolves an error handling issue where
incompressible data attempts compression twice: once by QAT and
once in software. To fix this issue, a new (and fake) error code
CPA_STATUS_INOMPRESSIBLE has been added so that the calling code
can correctly account for the difference between a hardware
failure and data that simply cannot be compressed.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Weigang Li <weigang.li@intel.com>
Signed-off-by: Tom Caputi <tcaputi@datto.com>
Closes #7338
This commit is contained in:
Tom Caputi
2018-03-29 20:40:34 -04:00
committed by Brian Behlendorf
parent 13a2ff2727
commit 32dce2da0c
3 changed files with 106 additions and 37 deletions
+12 -3
View File
@@ -53,16 +53,25 @@ typedef uLongf zlen_t;
size_t
gzip_compress(void *s_start, void *d_start, size_t s_len, size_t d_len, int n)
{
int ret;
zlen_t dstlen = d_len;
ASSERT(d_len <= s_len);
/* check if hardware accelerator can be used */
if (qat_dc_use_accel(s_len)) {
if (qat_compress(QAT_COMPRESS, s_start,
s_len, d_start, d_len, &dstlen) == CPA_STATUS_SUCCESS)
ret = qat_compress(QAT_COMPRESS, s_start, s_len, d_start,
d_len, &dstlen);
if (ret == CPA_STATUS_SUCCESS) {
return ((size_t)dstlen);
/* if hardware compress fail, do it again with software */
} else if (ret == CPA_STATUS_INCOMPRESSIBLE) {
if (d_len != s_len)
return (s_len);
bcopy(s_start, d_start, s_len);
return (s_len);
}
/* if hardware compression fails, do it again with software */
}
if (compress_func(d_start, &dstlen, s_start, s_len, n) != Z_OK) {