[AS_HELP_STRING([--with-libzstd],
[Enable and build with of libzstd support @<:@default=auto@:>@])])
+AC_ARG_WITH(qpl,
+ [AS_HELP_STRING([--with-qpl],
+ [Enable and build with Intel QPL support @<:@default=disabled@:>@])], [],
+ [with_qpl="no"])
+
AC_ARG_ENABLE(fuse,
[AS_HELP_STRING([--enable-fuse], [enable erofsfuse @<:@default=no@:>@])],
[enable_fuse="$enableval"], [enable_fuse="no"])
])
])
+# Configure Intel QPL
+have_qpl="no"
+AS_IF([test "x$with_qpl" != "xno"], [
+ PKG_CHECK_MODULES([libqpl], [qpl >= 1.5.0], [
+ # Paranoia: don't trust the result reported by pkgconfig before trying out
+ saved_LIBS="$LIBS"
+ saved_CPPFLAGS=${CPPFLAGS}
+ CPPFLAGS="${libqpl_CFLAGS} ${CPPFLAGS}"
+ LIBS="${libqpl_LIBS} $LIBS"
+ AC_CHECK_HEADERS([qpl/qpl.h],[
+ AC_CHECK_LIB(qpl, qpl_execute_job, [], [
+ AC_MSG_ERROR([libqpl doesn't work properly])])
+ AC_CHECK_DECL(qpl_execute_job, [have_qpl="yes"],
+ [AC_MSG_ERROR([libqpl doesn't work properly])], [[
+#include <qpl/qpl.h>
+ ]])
+ ])
+ LIBS="${saved_LIBS}"
+ CPPFLAGS="${saved_CPPFLAGS}"], [
+ AS_IF([test "x$with_qpl" = "xyes"], [
+ AC_MSG_ERROR([Cannot find proper libqpl])
+ ])
+ ])
+])
+
# Enable 64-bit off_t
CFLAGS+=" -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64"
AM_CONDITIONAL([ENABLE_LIBLZMA], [test "x${have_liblzma}" = "xyes"])
AM_CONDITIONAL([ENABLE_LIBDEFLATE], [test "x${have_libdeflate}" = "xyes"])
AM_CONDITIONAL([ENABLE_LIBZSTD], [test "x${have_libzstd}" = "xyes"])
+AM_CONDITIONAL([ENABLE_QPL], [test "x${have_qpl}" = "xyes"])
if test "x$have_uuid" = "xyes"; then
AC_DEFINE([HAVE_LIBUUID], 1, [Define to 1 if libuuid is found])
AC_DEFINE([HAVE_LIBZSTD], 1, [Define to 1 if libzstd is found])
fi
+if test "x$have_qpl" = "xyes"; then
+ AC_DEFINE([HAVE_QPL], 1, [Define to 1 if qpl is found])
+ AC_SUBST([libqpl_LIBS])
+ AC_SUBST([libqpl_CFLAGS])
+fi
+
# Dump maximum block size
AS_IF([test "x$erofs_cv_max_block_size" = "x"],
[$erofs_cv_max_block_size = 4096], [])
}
#endif
+#ifdef HAVE_QPL
+#include <qpl/qpl.h>
+
+struct z_erofs_qpl_job {
+ struct z_erofs_qpl_job *next;
+ u8 job[];
+};
+static struct z_erofs_qpl_job *z_erofs_qpl_jobs;
+static unsigned int z_erofs_qpl_reclaim_quot;
+#ifdef HAVE_PTHREAD_H
+static pthread_mutex_t z_erofs_qpl_mutex;
+#endif
+
+int z_erofs_load_deflate_config(struct erofs_sb_info *sbi,
+ struct erofs_super_block *dsb, void *data, int size)
+{
+ struct z_erofs_deflate_cfgs *dfl = data;
+ static erofs_atomic_bool_t inited;
+
+ if (!dfl || size < sizeof(struct z_erofs_deflate_cfgs)) {
+ erofs_err("invalid deflate cfgs, size=%u", size);
+ return -EINVAL;
+ }
+
+ /*
+ * In Intel QPL, decompression is supported for DEFLATE streams where
+ * the size of the history buffer is no more than 4 KiB, otherwise
+ * QPL_STS_BAD_DIST_ERR code is returned.
+ */
+ sbi->useqpl = (dfl->windowbits <= 12);
+ if (sbi->useqpl) {
+ if (!erofs_atomic_test_and_set(&inited))
+ z_erofs_qpl_reclaim_quot = erofs_get_available_processors();
+ erofs_info("Intel QPL will be used for DEFLATE decompression");
+ }
+ return 0;
+}
+
+static qpl_job *z_erofs_qpl_get_job(void)
+{
+ qpl_path_t execution_path = qpl_path_auto;
+ struct z_erofs_qpl_job *job;
+ int32_t jobsize = 0;
+ qpl_status status;
+
+#ifdef HAVE_PTHREAD_H
+ pthread_mutex_lock(&z_erofs_qpl_mutex);
+#endif
+ job = z_erofs_qpl_jobs;
+ if (job)
+ z_erofs_qpl_jobs = job->next;
+#ifdef HAVE_PTHREAD_H
+ pthread_mutex_unlock(&z_erofs_qpl_mutex);
+#endif
+
+ if (!job) {
+ status = qpl_get_job_size(execution_path, &jobsize);
+ if (status != QPL_STS_OK) {
+ erofs_err("failed to get job size: %d", status);
+ return ERR_PTR(-EOPNOTSUPP);
+ }
+
+ job = malloc(jobsize + sizeof(struct z_erofs_qpl_job));
+ if (!job)
+ return ERR_PTR(-ENOMEM);
+
+ status = qpl_init_job(execution_path, (qpl_job *)job->job);
+ if (status != QPL_STS_OK) {
+ erofs_err("failed to initialize job: %d", status);
+ return ERR_PTR(-EOPNOTSUPP);
+ }
+ erofs_atomic_dec_return(&z_erofs_qpl_reclaim_quot);
+ }
+ return (qpl_job *)job->job;
+}
+
+static bool z_erofs_qpl_put_job(qpl_job *qjob)
+{
+ struct z_erofs_qpl_job *job =
+ container_of((void *)qjob, struct z_erofs_qpl_job, job);
+
+ if (erofs_atomic_inc_return(&z_erofs_qpl_reclaim_quot) <= 0) {
+ qpl_status status = qpl_fini_job(qjob);
+
+ free(job);
+ if (status != QPL_STS_OK)
+ erofs_err("failed to finalize job: %d", status);
+ return status == QPL_STS_OK;
+ }
+#ifdef HAVE_PTHREAD_H
+ pthread_mutex_lock(&z_erofs_qpl_mutex);
+#endif
+ job->next = z_erofs_qpl_jobs;
+ z_erofs_qpl_jobs = job;
+#ifdef HAVE_PTHREAD_H
+ pthread_mutex_unlock(&z_erofs_qpl_mutex);
+#endif
+ return true;
+}
+
+static int z_erofs_decompress_qpl(struct z_erofs_decompress_req *rq)
+{
+ u8 *dest = (u8 *)rq->out;
+ u8 *src = (u8 *)rq->in;
+ u8 *buff = NULL;
+ unsigned int inputmargin;
+ qpl_status status;
+ qpl_job *job;
+ int ret;
+
+ job = z_erofs_qpl_get_job();
+ if (IS_ERR(job))
+ return PTR_ERR(job);
+
+ inputmargin = z_erofs_fixup_insize(src, rq->inputsize);
+ if (inputmargin >= rq->inputsize)
+ return -EFSCORRUPTED;
+
+ if (rq->decodedskip) {
+ buff = malloc(rq->decodedlength);
+ if (!buff)
+ return -ENOMEM;
+ dest = buff;
+ }
+
+ job->op = qpl_op_decompress;
+ job->next_in_ptr = src + inputmargin;
+ job->next_out_ptr = dest;
+ job->available_in = rq->inputsize - inputmargin;
+ job->available_out = rq->decodedlength;
+ job->flags = QPL_FLAG_FIRST | QPL_FLAG_LAST;
+ status = qpl_execute_job(job);
+ if (status != QPL_STS_OK) {
+ erofs_err("failed to decompress: %d", status);
+ ret = -EIO;
+ goto out_inflate_end;
+ }
+
+ if (rq->decodedskip)
+ memcpy(rq->out, dest + rq->decodedskip,
+ rq->decodedlength - rq->decodedskip);
+ ret = 0;
+out_inflate_end:
+ if (!z_erofs_qpl_put_job(job))
+ ret = -EFAULT;
+ if (buff)
+ free(buff);
+ return ret;
+}
+#else
+int z_erofs_load_deflate_config(struct erofs_sb_info *sbi,
+ struct erofs_super_block *dsb, void *data, int size)
+{
+ return 0;
+}
+#endif
+
#ifdef HAVE_LIBDEFLATE
/* if libdeflate is available, use libdeflate instead. */
#include <libdeflate.h>
if (rq->alg == Z_EROFS_COMPRESSION_LZMA)
return z_erofs_decompress_lzma(rq);
#endif
+#ifdef HAVE_QPL
+ if (rq->alg == Z_EROFS_COMPRESSION_DEFLATE && rq->sbi->useqpl)
+ if (!z_erofs_decompress_qpl(rq))
+ return 0;
+#endif
#if defined(HAVE_ZLIB) || defined(HAVE_LIBDEFLATE)
if (rq->alg == Z_EROFS_COMPRESSION_DEFLATE)
return z_erofs_decompress_deflate(rq);
break;
}
- ret = 0;
+ if (alg == Z_EROFS_COMPRESSION_DEFLATE)
+ ret = z_erofs_load_deflate_config(sbi, dsb, data, size);
+ else
+ ret = 0;
free(data);
if (ret)
break;