lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <c93aab13-7a9a-4188-803e-14b8df6a8109@xiaomi.com>
Date: Mon, 19 May 2025 02:37:34 +0000
From: Huang Jianan <huangjianan@...omi.com>
To: Bo Liu <liubo03@...pur.com>
CC: "linux-erofs@...ts.ozlabs.org" <linux-erofs@...ts.ozlabs.org>,
	"linux-kernel@...r.kernel.org" <linux-kernel@...r.kernel.org>,
	"xiang@...nel.org" <xiang@...nel.org>, "chao@...nel.org" <chao@...nel.org>
Subject: Re: [External Mail][PATCH v3] erofs: support deflate decompress by
 using Intel QAT

On 2025/5/16 16:26, Bo Liu wrote:
> [外部邮件] 此邮件来源于小米公司外部,请谨慎处理。若对邮件安全性存疑,请将邮件转发给misec@...omi.com进行反馈
> 
> This patch introdueces the use of the Intel QAT to decompress compressed
> data in the EROFS filesystem, aiming to improve the decompression speed
> of compressed datea.
> 
> We created a 285MiB compressed file and then used the following command to
> create EROFS images with different cluster size.
>       # mkfs.erofs -zdeflate,level=9 -C16384
> 
> fio command was used to test random read and small random read(~5%) and
> sequential read performance.
>       # fio -filename=testfile  -bs=4k -rw=read -name=job1
>       # fio -filename=testfile  -bs=4k -rw=randread -name=job1
>       # fio -filename=testfile  -bs=4k -rw=randread --io_size=14m -name=job1
> 
> Here are some performance numbers for reference:
> 
> Processors: Intel(R) Xeon(R) 6766E(144 core)
> Memory:     521 GiB
> 
> |-----------------------------------------------------------------------------|
> |           | Cluster size | sequential read | randread  | small randread(5%) |
> |-----------|--------------|-----------------|-----------|--------------------|
> | Intel QAT |    4096      |    538  MiB/s   | 112 MiB/s |     20.76 MiB/s    |
> | Intel QAT |    16384     |    699  MiB/s   | 158 MiB/s |     21.02 MiB/s    |
> | Intel QAT |    65536     |    917  MiB/s   | 278 MiB/s |     20.90 MiB/s    |
> | Intel QAT |    131072    |    1056 MiB/s   | 351 MiB/s |     23.36 MiB/s    |
> | Intel QAT |    262144    |    1145 MiB/s   | 431 MiB/s |     26.66 MiB/s    |
> | deflate   |    4096      |    499  MiB/s   | 108 MiB/s |     21.50 MiB/s    |
> | deflate   |    16384     |    422  MiB/s   | 125 MiB/s |     18.94 MiB/s    |
> | deflate   |    65536     |    452  MiB/s   | 159 MiB/s |     13.02 MiB/s    |
> | deflate   |    131072    |    452  MiB/s   | 177 MiB/s |     11.44 MiB/s    |
> | deflate   |    262144    |    466  MiB/s   | 194 MiB/s |     10.60 MiB/s    |
> 
> Signed-off-by: Bo Liu <liubo03@...pur.com>
> ---
> v1: https://lore.kernel.org/linux-erofs/20250410042048.3044-1-liubo03@inspur.com/
> v2: https://lore.kernel.org/linux-erofs/20250410042048.3044-1-liubo03@inspur.com/T/#t
> 
> Changes since v2:
>   - Add a new kernel config option CONFIG_EROFS_FS_ZIP_CRYPTO.
>   - Modify the sysfs interface to merge enable and disable into
>     a single entry point, and add a read function to view the current state.
>   - Optimize the relevant code,use the sg_alloc_table_from_pages_segment interface.
> 
>   fs/erofs/Kconfig                |  14 +++
>   fs/erofs/Makefile               |   1 +
>   fs/erofs/compress.h             |  14 +++
>   fs/erofs/decompressor_crypto.c  | 199 ++++++++++++++++++++++++++++++++
>   fs/erofs/decompressor_deflate.c |  16 ++-
>   fs/erofs/sysfs.c                |  36 ++++++
>   6 files changed, 279 insertions(+), 1 deletion(-)
>   create mode 100644 fs/erofs/decompressor_crypto.c
> 
> diff --git a/fs/erofs/Kconfig b/fs/erofs/Kconfig
> index 331e49cd1b8d..db49ae3c1922 100644
> --- a/fs/erofs/Kconfig
> +++ b/fs/erofs/Kconfig
> @@ -144,6 +144,20 @@ config EROFS_FS_ZIP_ZSTD
> 
>            If unsure, say N.
> 
> +config EROFS_FS_ZIP_CRYPTO
> +       bool "EROFS hardware decompression support (crypto interface)"
> +       depends on EROFS_FS_ZIP
> +       help
> +         Saying Y here includes support for reading EROFS file systems
> +         containing crypto compressed data.  It gives better decompression
> +         speed than the software-implemented compression, and it costs
> +         lower CPU overhead.
> +
> +         Crypto support is an experimental feature for now and so most
> +         file systems will be readable without selecting this option.
> +
> +         If unsure, say N.
> +
>   config EROFS_FS_ONDEMAND
>          bool "EROFS fscache-based on-demand read support (deprecated)"
>          depends on EROFS_FS
> diff --git a/fs/erofs/Makefile b/fs/erofs/Makefile
> index 4331d53c7109..247b263eb667 100644
> --- a/fs/erofs/Makefile
> +++ b/fs/erofs/Makefile
> @@ -7,5 +7,6 @@ erofs-$(CONFIG_EROFS_FS_ZIP) += decompressor.o zmap.o zdata.o zutil.o
>   erofs-$(CONFIG_EROFS_FS_ZIP_LZMA) += decompressor_lzma.o
>   erofs-$(CONFIG_EROFS_FS_ZIP_DEFLATE) += decompressor_deflate.o
>   erofs-$(CONFIG_EROFS_FS_ZIP_ZSTD) += decompressor_zstd.o
> +erofs-$(CONFIG_EROFS_FS_ZIP_CRYPTO) += decompressor_crypto.o
>   erofs-$(CONFIG_EROFS_FS_BACKED_BY_FILE) += fileio.o
>   erofs-$(CONFIG_EROFS_FS_ONDEMAND) += fscache.o
> diff --git a/fs/erofs/compress.h b/fs/erofs/compress.h
> index 2704d7a592a5..356ae2473bd5 100644
> --- a/fs/erofs/compress.h
> +++ b/fs/erofs/compress.h
> @@ -70,10 +70,24 @@ struct z_erofs_stream_dctx {
>          bool bounced;                   /* is the bounce buffer used now? */
>   };
> 
> +struct z_erofs_crypto_engine {
> +       char *crypto_name;
> +       bool enabled;
> +       struct crypto_acomp *erofs_tfm;
> +};
> +
> +extern struct z_erofs_crypto_engine z_erofs_crypto[Z_EROFS_COMPRESSION_MAX][2];
> +
>   int z_erofs_stream_switch_bufs(struct z_erofs_stream_dctx *dctx, void **dst,
>                                 void **src, struct page **pgpl);
>   int z_erofs_fixup_insize(struct z_erofs_decompress_req *rq, const char *padbuf,
>                           unsigned int padbufsize);
>   int __init z_erofs_init_decompressor(void);
>   void z_erofs_exit_decompressor(void);
> +int z_erofs_crypto_decompress(struct z_erofs_decompress_req *rq,
> +                                               struct crypto_acomp *erofs_tfm, struct page **pgpl);
> +struct crypto_acomp *z_erofs_crypto_get_engine(int type);
> +int z_erofs_crypto_enable_engine(const char *name);
> +void z_erofs_crypto_disable_engine(void);
> +int z_erofs_crypto_engine_format(char *buf);
>   #endif
> diff --git a/fs/erofs/decompressor_crypto.c b/fs/erofs/decompressor_crypto.c
> new file mode 100644
> index 000000000000..55f6a9e6dcf6
> --- /dev/null
> +++ b/fs/erofs/decompressor_crypto.c
> @@ -0,0 +1,199 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +#include <linux/scatterlist.h>
> +#include <crypto/acompress.h>
> +
> +#include "compress.h"
> +
> +static int z_erofs_crypto_decompress_mem(struct z_erofs_decompress_req *rq,
> +                               struct crypto_acomp *erofs_tfm)
> +{
> +       struct sg_table st_src, st_dst;
> +       struct acomp_req *req;
> +       struct crypto_wait wait;
> +       u8 *headpage;
> +       int ret;
> +
> +       headpage = kmap_local_page(*rq->in);
> +       ret = z_erofs_fixup_insize(rq, headpage + rq->pageofs_in,
> +                               min_t(unsigned int, rq->inputsize,
> +                                                       rq->sb->s_blocksize - rq->pageofs_in));
> +       kunmap_local(headpage);
> +       if (ret)
> +               return ret;
> +
> +       req = acomp_request_alloc(erofs_tfm);
> +       if (!req) {
> +               erofs_err(rq->sb, "failed to alloc decompress request");
> +               return -ENOMEM;
> +       }
> +
> +       ret = sg_alloc_table_from_pages_segment(&st_src,
> +                                       rq->in, rq->inpages, rq->pageofs_in,
> +                                       rq->inputsize, UINT_MAX, GFP_KERNEL);
> +       if (ret < 0)
> +               goto failed_src_alloc;
> +
> +       ret = sg_alloc_table_from_pages_segment(&st_dst,
> +                                       rq->out, rq->outpages, rq->pageofs_out,
> +                                       rq->outputsize, UINT_MAX, GFP_KERNEL);
> +       if (ret < 0)
> +               goto failed_dst_alloc;
> +
> +       acomp_request_set_params(req, st_src.sgl,
> +               st_dst.sgl, rq->inputsize, rq->outputsize);
> +
> +       crypto_init_wait(&wait);
> +       acomp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
> +                               crypto_req_done, &wait);
> +
> +       ret = crypto_wait_req(crypto_acomp_decompress(req), &wait);
> +       if (ret < 0) {
> +               erofs_err(rq->sb, "failed to decompress %d in[%u, %u] out[%u]",
> +                                       ret, rq->inputsize, rq->pageofs_in, rq->outputsize);
> +               ret = -EIO;
> +       } else
> +               ret = 0;
> +
> +       sg_free_table(&st_dst);
> +failed_dst_alloc:
> +       sg_free_table(&st_src);
> +failed_src_alloc:
> +       acomp_request_free(req);
> +       return ret;
> +}
> +
> +int z_erofs_crypto_decompress(struct z_erofs_decompress_req *rq,
> +                               struct crypto_acomp *erofs_tfm, struct page **pgpl)
> +{
> +       int i;
> +
> +       for (i = 0; i < rq->outpages; i++) {
> +               struct page *const page = rq->out[i];
> +               struct page *victim;
> +
> +               if (!page) {
> +                       victim = __erofs_allocpage(pgpl, rq->gfp, true);
> +                       if (!victim)
> +                               return -ENOMEM;
> +                       set_page_private(victim, Z_EROFS_SHORTLIVED_PAGE);
> +                       rq->out[i] = victim;
> +               }
> +       }
> +
> +       return z_erofs_crypto_decompress_mem(rq, erofs_tfm);
> +}
> +
> +struct crypto_acomp *z_erofs_crypto_get_engine(int type)
> +{
> +       int i = 0;
> +
> +       while (z_erofs_crypto[type][i].crypto_name) {
> +               if (z_erofs_crypto[type][i].enabled)
> +                       return z_erofs_crypto[type][i].erofs_tfm;
> +               i++;
> +       }
> +       return NULL;
> +}
> +
> +static int z_erofs_crypto_get_compress_type(const char *name)
> +{
> +       int i, j;
> +
> +       for (i = 0; i < Z_EROFS_COMPRESSION_MAX; i++) {
> +               j = 0;
> +               while (z_erofs_crypto[i][j].crypto_name) {

Is it possible to use z_erofs_crypto_engine itself instead of crypto_name to
check if there is a supported compression engine, like:

#define Z_EROFS_CRYPTO_ENGINE_MAX 1
struct z_erofs_crypto_engine *z_erofs_crypto[Z_EROFS_COMPRESSION_MAX][Z_EROFS_CRYPTO_ENGINE_MAX] = {
	[Z_EROFS_COMPRESSION_LZ4] = { },
	[Z_EROFS_COMPRESSION_LZMA] = { },
	[Z_EROFS_COMPRESSION_DEFLATE] = {
		&(struct z_erofs_crypto_engine) {
			.crypto_name = "qat_deflate",
			.enabled = false,
			.erofs_tfm = NULL,
		}
	},
	[Z_EROFS_COMPRESSION_ZSTD] = {
	},
};

for (i = 0; z_erofs_crypto[type][i]; ++i) {
	...
}

> +                       if (!strcmp(name, z_erofs_crypto[i][j].crypto_name))
> +                               return i;
> +
> +                       j++;
> +               }
> +       }
> +       return -EINVAL;
> +}
> +
> +int z_erofs_crypto_enable_engine(const char *name)
> +{
> +       int i = 0, type;
> +
> +       type = z_erofs_crypto_get_compress_type(name);
> +       if (type < 0)
> +               return -EINVAL;
> +
> +       while (z_erofs_crypto[type][i].crypto_name) {
> +               if (!strcmp(z_erofs_crypto[type][i].crypto_name, name)) {
> +                       if (z_erofs_crypto[type][i].enabled)
> +                               break;

Maybe an error is needed to inform duplicate enable.

> +
> +                       z_erofs_crypto[type][i].erofs_tfm =
> +                               crypto_alloc_acomp(z_erofs_crypto[type][i].crypto_name, 0, 0);
> +                       if (IS_ERR(z_erofs_crypto[type][i].erofs_tfm)) {
> +                               z_erofs_crypto[type][i].erofs_tfm = NULL;
> +                               return -ENXIO;
> +                       }
> +                       z_erofs_crypto[type][i].enabled = true;
> +               } else if (z_erofs_crypto[type][i].enabled) {
> +                       if (z_erofs_crypto[type][i].erofs_tfm)
> +                               crypto_free_acomp(z_erofs_crypto[type][i].erofs_tfm);
> +                       z_erofs_crypto[type][i].enabled = false;

This may be concurrent with z_erofs_deflate_decompress, so it should be
disabled first and may require a memory barrier.

> +               }
> +               i++;
> +       }
> +       return 0;
> +}
> +
> +void z_erofs_crypto_disable_engine(void)
> +{
> +       int i = 0, type;
> +
> +       for (type = 0; type < Z_EROFS_COMPRESSION_MAX; type++) {
> +               i = 0;
> +               while (z_erofs_crypto[type][i].crypto_name) {
> +                       if (z_erofs_crypto[type][i].enabled &&
> +                                       z_erofs_crypto[type][i].erofs_tfm) {
> +                               crypto_free_acomp(z_erofs_crypto[type][i].erofs_tfm);
> +                               z_erofs_crypto[type][i].erofs_tfm = NULL;
> +                               z_erofs_crypto[type][i].enabled = false;
> +                       }
> +                       i++;
> +               }
> +       }
> +}
> +
> +int z_erofs_crypto_engine_format(char *buf)
> +{
> +       int type, i, len = 0;
> +
> +       for (type = 0; type < Z_EROFS_COMPRESSION_MAX; type++) {
> +               i = 0;
> +               while (z_erofs_crypto[type][i].crypto_name) {
> +                       if (z_erofs_crypto[type][i].enabled)
> +                               len += scnprintf(buf + len, PATH_MAX - len, "%s ",
> +                                                       z_erofs_crypto[type][i].crypto_name);
> +                       i++;
> +               }
> +       }
> +       return len;
> +}
> +
> +struct z_erofs_crypto_engine z_erofs_crypto[Z_EROFS_COMPRESSION_MAX][2] = {
> +       [Z_EROFS_COMPRESSION_LZ4] = {
> +               (struct z_erofs_crypto_engine) {NULL},
> +               (struct z_erofs_crypto_engine) {NULL},
> +       },
> +       [Z_EROFS_COMPRESSION_LZMA] = {
> +               (struct z_erofs_crypto_engine) {NULL},
> +               (struct z_erofs_crypto_engine) {NULL},
> +       },
> +       [Z_EROFS_COMPRESSION_DEFLATE] = {
> +               (struct z_erofs_crypto_engine) {
> +                       .crypto_name = "qat_deflate",
> +                       .enabled = false,
> +                       .erofs_tfm = NULL,
> +               },
> +               (struct z_erofs_crypto_engine) {NULL},
> +       },
> +       [Z_EROFS_COMPRESSION_ZSTD] = {
> +               (struct z_erofs_crypto_engine) {NULL},
> +               (struct z_erofs_crypto_engine) {NULL},
> +       },
> +};
> diff --git a/fs/erofs/decompressor_deflate.c b/fs/erofs/decompressor_deflate.c
> index c6908a487054..bebbf1eccd3d 100644
> --- a/fs/erofs/decompressor_deflate.c
> +++ b/fs/erofs/decompressor_deflate.c
> @@ -97,7 +97,7 @@ static int z_erofs_load_deflate_config(struct super_block *sb,
>          return -ENOMEM;
>   }
> 
> -static int z_erofs_deflate_decompress(struct z_erofs_decompress_req *rq,
> +static int __z_erofs_deflate_decompress(struct z_erofs_decompress_req *rq,
>                                        struct page **pgpl)
>   {
>          struct super_block *sb = rq->sb;
> @@ -178,6 +178,20 @@ static int z_erofs_deflate_decompress(struct z_erofs_decompress_req *rq,
>          return err;
>   }
> 
> +static int z_erofs_deflate_decompress(struct z_erofs_decompress_req *rq,
> +                               struct page **pgpl)
> +{
> +#ifdef CONFIG_EROFS_FS_ZIP_CRYPTO
> +       struct crypto_acomp *erofs_tfm = NULL;
> +
> +       erofs_tfm = z_erofs_crypto_get_engine(Z_EROFS_COMPRESSION_DEFLATE);
> +       if (erofs_tfm && !rq->partial_decoding)
> +               return z_erofs_crypto_decompress(rq, erofs_tfm, pgpl);
> +       else

Unnecessary else.

> +#endif
> +               return __z_erofs_deflate_decompress(rq, pgpl);
> +}
> +
>   const struct z_erofs_decompressor z_erofs_deflate_decomp = {
>          .config = z_erofs_load_deflate_config,
>          .decompress = z_erofs_deflate_decompress,
> diff --git a/fs/erofs/sysfs.c b/fs/erofs/sysfs.c
> index dad4e6c6c155..00123c4d3196 100644
> --- a/fs/erofs/sysfs.c
> +++ b/fs/erofs/sysfs.c
> @@ -7,12 +7,14 @@
>   #include <linux/kobject.h>
> 
>   #include "internal.h"
> +#include "compress.h"
> 
>   enum {
>          attr_feature,
>          attr_drop_caches,
>          attr_pointer_ui,
>          attr_pointer_bool,
> +       attr_crypto,
>   };
> 
>   enum {
> @@ -60,6 +62,9 @@ static struct erofs_attr erofs_attr_##_name = {                       \
>   EROFS_ATTR_RW_UI(sync_decompress, erofs_mount_opts);
>   EROFS_ATTR_FUNC(drop_caches, 0200);
>   #endif
> +#ifdef CONFIG_EROFS_FS_ZIP_CRYPTO
> +EROFS_ATTR_FUNC(crypto, 0644);
> +#endif
> 
>   static struct attribute *erofs_attrs[] = {
>   #ifdef CONFIG_EROFS_FS_ZIP
> @@ -95,6 +100,9 @@ static struct attribute *erofs_feat_attrs[] = {
>          ATTR_LIST(fragments),
>          ATTR_LIST(dedupe),
>          ATTR_LIST(48bit),
> +#ifdef CONFIG_EROFS_FS_ZIP_CRYPTO
> +       ATTR_LIST(crypto),
> +#endif
>          NULL,
>   };
>   ATTRIBUTE_GROUPS(erofs_feat);
> @@ -128,6 +136,10 @@ static ssize_t erofs_attr_show(struct kobject *kobj,
>                  if (!ptr)
>                          return 0;
>                  return sysfs_emit(buf, "%d\n", *(bool *)ptr);
> +#ifdef CONFIG_EROFS_FS_ZIP_CRYPTO
> +       case attr_crypto:
> +               return z_erofs_crypto_engine_format(buf);
> +#endif
>          }
>          return 0;
>   }
> @@ -141,6 +153,10 @@ static ssize_t erofs_attr_store(struct kobject *kobj, struct attribute *attr,
>          unsigned char *ptr = __struct_ptr(sbi, a->struct_type, a->offset);
>          unsigned long t;
>          int ret;
> +#ifdef CONFIG_EROFS_FS_ZIP_CRYPTO
> +       char *crypto_name;
> +       size_t sz;
> +#endif
> 
>          switch (a->attr_id) {
>          case attr_pointer_ui:
> @@ -181,6 +197,26 @@ static ssize_t erofs_attr_store(struct kobject *kobj, struct attribute *attr,
>                  if (t & 1)
>                          invalidate_mapping_pages(MNGD_MAPPING(sbi), 0, -1);
>                  return len;
> +#endif
> +#ifdef CONFIG_EROFS_FS_ZIP_CRYPTO
> +       case attr_crypto:
> +               buf = skip_spaces(buf);
> +               sz = strlen(buf);
> +               crypto_name = kstrdup(buf, GFP_KERNEL);
> +               if (!crypto_name)
> +                       return -ENOMEM;
> +
> +               /* ignore trailing newline */
> +               if (sz > 0 && crypto_name[sz - 1] == '\n')
> +                       crypto_name[sz - 1] = 0x00;
> +
> +               if (strlen(crypto_name) > 0) {
> +                       ret = z_erofs_crypto_enable_engine(crypto_name);
> +                       if (ret < 0)
> +                               return ret;
> +               } else
> +                       z_erofs_crypto_disable_engine();

Is it possible to support disable a single engine?

Thanks,
Jianan

> +               return len;
>   #endif
>          }
>          return 0;
> --
> 2.31.1
> 
> 

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ