From: Tao Zeng <tao.zeng@xxxxxxxxxxx>
Some SoCs have hardware decompressors which using private algorithms,
which can be used for accelerating decompression for EROFS, but
current EROFS decompressor architecture do not support external
decompressors, this change adds a crypto layer interface for decompression
and can be used to hook SoC vendor's decompressor by crypto name. Soc
vendors can develop their own code which can be added to crypto layer.
Signed-off-by: Tao Zeng <tao.zeng@xxxxxxxxxxx>
---
fs/erofs/Kconfig | 19 +++
fs/erofs/Makefile | 1 +
fs/erofs/compress.h | 28 ++++
fs/erofs/decompressor.c | 7 +
fs/erofs/decompressor_cryptor.c | 306 ++++++++++++++++++++++++++++++++++++++++
fs/erofs/erofs_fs.h | 14 ++
fs/erofs/internal.h | 4 +
fs/erofs/super.c | 8 +-
8 files changed, 386 insertions(+), 1 deletion(-)
diff --git a/fs/erofs/Kconfig b/fs/erofs/Kconfig
index 7dcdce660cac..72e29041244b 100644
--- a/fs/erofs/Kconfig
+++ b/fs/erofs/Kconfig
@@ -127,6 +127,25 @@ config EROFS_FS_ZIP_ZSTD
If unsure, say N.
+config EROFS_FS_ZIP_CRYPTO
+ bool "EROFS external crypto decompress support"
+ depends on EROFS_FS_ZIP
+ help
+ Saying Y here to support external crypto for decompressing EROFS
+ file systems. Some SoCs have hardware decompressor with private
+ algorithm, which can be used for accelarating decompression of
+ EROFS. This config enables external cryptos.
+
+ If unsure, say N.
+
+config EROFS_CRYPTO_MAX_DISTANCE_PAGES
+ int "EROFS max distance pages for crypto usage"
+ default 32
+ help
+ This config defines max distance pages for external crypto. Crypto
+ layer will use this value to grow up PCP buffers.
+ The default value is 128KB(32 pages).
+
config EROFS_FS_ONDEMAND
bool "EROFS fscache-based on-demand read support"
depends on EROFS_FS
diff --git a/fs/erofs/Makefile b/fs/erofs/Makefile
index 097d672e6b14..d2dc5e2d20bd 100644
--- a/fs/erofs/Makefile
+++ b/fs/erofs/Makefile
@@ -7,4 +7,5 @@ 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_cryptor.o
erofs-$(CONFIG_EROFS_FS_ONDEMAND) += fscache.o
diff --git a/fs/erofs/compress.h b/fs/erofs/compress.h
index 19d53c30c8af..8236775563a5 100644
--- a/fs/erofs/compress.h
+++ b/fs/erofs/compress.h
@@ -98,4 +98,32 @@ int z_erofs_deflate_decompress(struct z_erofs_decompress_req *rq,
struct page **pagepool);
int z_erofs_zstd_decompress(struct z_erofs_decompress_req *rq,
struct page **pgpl);
+
+#ifdef CONFIG_EROFS_FS_ZIP_CRYPTO
+/* for external cryto decompress */
+int z_erofs_crypto_decompress(struct z_erofs_decompress_req *rq,
+ struct page **pagepool);
+int z_erofs_load_crypto_config(struct super_block *sb,
+ struct erofs_super_block *dsb,
+ void *data, int size);
+#else
+static inline int z_erofs_crypto_decompress(struct z_erofs_decompress_req *rq,
+ struct page **pagepool)
+{
+ return -EINVAL;
+}
+
+static inline int z_erofs_load_crypto_config(struct super_block *sb,
+ struct erofs_super_block *dsb,
+ void *data,
+ int size);
+{
+ if (crypto) {
+ erofs_err(sb, "crypto algorithm isn't enabled");
+ return -EINVAL;
+ }
+ return 0;
+}
+#endif
+
#endif
diff --git a/fs/erofs/decompressor.c b/fs/erofs/decompressor.c
index 9d85b6c11c6b..83fde9e974e3 100644
--- a/fs/erofs/decompressor.c
+++ b/fs/erofs/decompressor.c
@@ -406,6 +406,13 @@ const struct z_erofs_decompressor erofs_decompressors[] = {
.name = "zstd"
},
#endif
+#ifdef CONFIG_EROFS_FS_ZIP_CRYPTO
+ [Z_EROFS_COMPRESSION_CRYPTO] = {
+ .config = z_erofs_load_crypto_config,
+ .decompress = z_erofs_crypto_decompress,
+ .name = "crypto"
+ },
+#endif
};
int z_erofs_parse_cfgs(struct super_block *sb, struct erofs_super_block *dsb)
diff --git a/fs/erofs/decompressor_cryptor.c b/fs/erofs/decompressor_cryptor.c
new file mode 100644
index 000000000000..87df4d285ad1
--- /dev/null
+++ b/fs/erofs/decompressor_cryptor.c
@@ -0,0 +1,306 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2024 Amlogic, Inc. All rights reserved.
+ */
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/highmem.h>
+#include <linux/xz.h>
+#include <linux/module.h>
+#include <linux/crypto.h>
+#include "compress.h"
+#include "internal.h"
+
+static int crypto_max_distance_pages;
+
+int z_erofs_load_crypto_config(struct super_block *sb,
+ struct erofs_super_block *dsb,
+ void *data, int size)
+{
+ struct erofs_sb_info *sbi;
+ struct z_erofs_crypto_cfgs *crypto = (struct z_erofs_crypto_cfgs *)data;
+ int max_pages;
+
+ sbi = EROFS_SB(sb);
+ if (!sbi)
+ return -EINVAL;
+
+ if (sbi->crypto) {
+ erofs_err(sb, "already have crypto\n");
+ return -EINVAL;
+ }
+ if (crypto) {
+ max_pages = BIT(crypto->max_distance) / PAGE_SIZE;
+ if (max_pages > CONFIG_EROFS_CRYPTO_MAX_DISTANCE_PAGES) {
+ erofs_err(sb, "bad max distance:%d\n", max_pages);
+ return -EINVAL;
+ }
+
+ if (max_pages > crypto_max_distance_pages)
+ crypto_max_distance_pages = max_pages;
+ sbi->crypto = crypto_alloc_comp(crypto->crypto_name, 0, 0);
+ if (IS_ERR(sbi->crypto)) {
+ erofs_err(sb, "failed to alloc cryto %s\n",
+ crypto->crypto_name);
+ return PTR_ERR(sbi->crypto);
+ }
+ erofs_info(sb, "max pcluster:%d, distance:%d, %d, crypto:%s\n",
+ crypto->max_pclusterblks,
+ crypto->max_distance, crypto_max_distance_pages,
+ crypto->crypto_name);
+ return z_erofs_gbuf_growsize(crypto_max_distance_pages);
+ } else {
+ return -EINVAL;
+ }
+}
+
+static void *z_erofs_crypto_handle_inplace_io(struct z_erofs_decompress_req *rq,
+ void *inpage,
+ unsigned int *inputmargin,
+ int *maptype,
+ bool support_0padding)
+{
+ unsigned int nrpages_in, nrpages_out;
+ return src;
+}
+
+static int z_erofs_crypto_decompress_mem(struct z_erofs_decompress_req *rq, u8 *out)
+{
+ return ret;
+}
+
+/*
+ * Fill all gaps with bounce pages if it's a sparse page list. Also check if
+ * all physical pages are consecutive, which can be seen for moderate CR.
+ */
+static int z_erofs_crypto_prepare_dstpages(struct z_erofs_decompress_req *rq,
+ struct page **pagepool)
+{
+ }
+ return kaddr ? 1 : 0;
+}
+
diff --git a/fs/erofs/erofs_fs.h b/fs/erofs/erofs_fs.h
index 6c0c270c42e1..993b7a1b656f 100644
--- a/fs/erofs/erofs_fs.h
+++ b/fs/erofs/erofs_fs.h
@@ -297,6 +297,10 @@ enum {
Z_EROFS_COMPRESSION_LZMA = 1,
Z_EROFS_COMPRESSION_DEFLATE = 2,
Z_EROFS_COMPRESSION_ZSTD = 3,
+#ifdef CONFIG_EROFS_FS_ZIP_CRYPTO
+ /* for generic crypto framework */
+ Z_EROFS_COMPRESSION_CRYPTO = 4,
+#endif
Z_EROFS_COMPRESSION_MAX
};
#define Z_EROFS_ALL_COMPR_ALGS ((1 << Z_EROFS_COMPRESSION_MAX) - 1)
@@ -330,6 +334,16 @@ struct z_erofs_zstd_cfgs {
u8 reserved[4];
} __packed;
+#ifdef CONFIG_EROFS_FS_ZIP_CRYPTO
+/* 16 bytes */
+struct z_erofs_crypto_cfgs {
+ char crypto_name[8];
+ __le16 max_distance;
+ __le16 max_pclusterblks;
+ u8 reserved[4];
+} __packed;
+#endif