Skip to contentSkip to conversation

crypto: switch to static calls for CRC-T10DIF

PATCH In review Ard Biesheuvel 4 participants 16 messages Jan 11, 2021 – Jan 28, 2021

Subsystems (7)
lore
Share & tools
lore

Ard Biesheuvel

author reviewer
#0 lore raw

cover crypto: switch to static calls for CRC-T10DIF

CRC-T10DIF is a very poor match for the crypto API:
- every user in the kernel calls it via a library wrapper around the shash API, so all callers share a single instance of the transform
- each architecture provides at most a single optimized implementation, based on SIMD instructions for carryless multiplication

In other words, none of the flexibility it provides is put to good use, and so it is better to get rid of this complexity, and expose the optimized implementations via static calls instead. This removes a substantial chunk of code, and also gets rid of any indirect calls on architectures that obsess about those (x86)

If this approach is deemed suitable, there are other places where we might consider adopting it: CRC32 and CRC32(C).

Patch #1 does some preparatory refactoring and removes the library wrapper around the shash transform.

Patch #2 introduces the actual static calls, along with the registration routines to update the crc-t10dif implementation at runtime.

Patch #3 updates the generic CRC-T10DIF shash driver so it distinguishes between the optimized library code and the generic library code.

Patches #4 to #7 update the various arch implementations to switch over to the new method.

Special request to Peter to take a look at patch #2, and in particular, whether synchronize_rcu_tasks() is sufficient to ensure that a module providing the target of a static call can be unloaded safely.

Cc "Martin K. Petersen" <[email protected]>
Cc Eric Biggers <[email protected]>
Cc Peter Zijlstra <[email protected]>

Ard Biesheuvel (7):
crypto: crc-t10dif - turn library wrapper for shash into generic
library
crypto: lib/crc-t10dif - add static call support for optimized
versions
crypto: generic/crc-t10dif - expose both arch and generic shashes
crypto: x86/crc-t10dif - convert to static call library API
crypto: arm/crc-t10dif - convert to static call library API
crypto: arm64/crc-t10dif - convert to static call API
crypto: powerpc/crc-t10dif - convert to static call API

 arch/arm/crypto/Kconfig                     |   2 +-
 arch/arm/crypto/crct10dif-ce-glue.c         |  58 ++------
 arch/arm64/crypto/Kconfig                   |   3 +-
 arch/arm64/crypto/crct10dif-ce-glue.c       |  85 ++---------
 arch/powerpc/crypto/crct10dif-vpmsum_glue.c |  51 +------
 arch/x86/crypto/crct10dif-pclmul_glue.c     |  90 ++----------
 crypto/Kconfig                              |   7 +-
 crypto/Makefile                             |   2 +-
 crypto/crct10dif_common.c                   |  82 -----------
 crypto/crct10dif_generic.c                  | 100 +++++++++----
 include/linux/crc-t10dif.h                  |  21 ++-
 lib/Kconfig                                 |   2 -
 lib/crc-t10dif.c                            | 152 +++++++++-----------
 13 files changed, 204 insertions(+), 451 deletions(-)
 delete mode 100644 crypto/crct10dif_common.c
Signature · 1 line
2.17.1
author reviewer
#1 lore raw

PATCH 1/7 crypto: crc-t10dif - turn library wrapper for shash into generic library

As a first step towards moving CRC-T10DIF out of the crypto API, drop the shash wrapping code from the library implementation, and move the generic core CRC-T10DIF into it from the generic crypto SHASH driver.

In a future patch, the library interface will be augmented with the facilities to register and unregister optimized implementations.

---
 arch/arm/crypto/Kconfig   |   2 +-
 arch/arm64/crypto/Kconfig |   3 +-
 crypto/Kconfig            |   7 +-
 crypto/Makefile           |   2 +-
 crypto/crct10dif_common.c |  82 ------------
 lib/Kconfig               |   2 -
 lib/crc-t10dif.c          | 136 +++++++-------------
 7 files changed, 57 insertions(+), 177 deletions(-)
arch/arm/crypto/Kconfig +1 -1
index 2b575792363e..939de9ceed0f 100644
@@ -138,8 +138,8 @@ config CRYPTO_GHASH_ARM_CE
 config CRYPTO_CRCT10DIF_ARM_CE
 	tristate "CRCT10DIF digest algorithm using PMULL instructions"
 	depends on KERNEL_MODE_NEON
-	depends on CRC_T10DIF
 	select CRYPTO_HASH
+	select CRC_T10DIF
 
 config CRYPTO_CRC32_ARM_CE
 	tristate "CRC32(C) digest algorithm using CRC and/or PMULL instructions"
arch/arm64/crypto/Kconfig +2 -1
index b8eb0453123d..e5d2f989521f 100644
@@ -62,8 +62,9 @@ config CRYPTO_GHASH_ARM64_CE
 
 config CRYPTO_CRCT10DIF_ARM64_CE
 	tristate "CRCT10DIF digest algorithm using PMULL instructions"
-	depends on KERNEL_MODE_NEON && CRC_T10DIF
+	depends on KERNEL_MODE_NEON
 	select CRYPTO_HASH
+	select CRC_T10DIF
 
 config CRYPTO_AES_ARM64
 	tristate "AES core cipher using scalar instructions"
crypto/Kconfig +5 -2
index 94f0fde06b94..3e8cf6c2215a 100644
@@ -700,6 +700,7 @@ config CRYPTO_BLAKE2S_X86
 config CRYPTO_CRCT10DIF
 	tristate "CRCT10DIF algorithm"
 	select CRYPTO_HASH
+	select CRC_T10DIF
 	help
 	  CRC T10 Data Integrity Field computation is being cast as
 	  a crypto transform.  This allows for faster crc t10 diff
@@ -707,8 +708,9 @@ config CRYPTO_CRCT10DIF
 
 config CRYPTO_CRCT10DIF_PCLMUL
 	tristate "CRCT10DIF PCLMULQDQ hardware acceleration"
-	depends on X86 && 64BIT && CRC_T10DIF
+	depends on X86 && 64BIT
 	select CRYPTO_HASH
+	select CRC_T10DIF
 	help
 	  For x86_64 processors with SSE4.2 and PCLMULQDQ supported,
 	  CRC T10 DIF PCLMULQDQ computation can be hardware
@@ -718,8 +720,9 @@ config CRYPTO_CRCT10DIF_PCLMUL
 
 config CRYPTO_CRCT10DIF_VPMSUM
 	tristate "CRC32T10DIF powerpc64 hardware acceleration"
-	depends on PPC64 && ALTIVEC && CRC_T10DIF
+	depends on PPC64 && ALTIVEC
 	select CRYPTO_HASH
+	select CRC_T10DIF
 	help
 	  CRC10T10DIF algorithm implemented using vector polynomial
 	  multiply-sum (vpmsum) instructions, introduced in POWER8. Enable on
crypto/Makefile +1 -1
index b279483fba50..69d06a28c8e6 100644
@@ -148,7 +148,7 @@ obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o
 obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
 obj-$(CONFIG_CRYPTO_CRC32C) += crc32c_generic.o
 obj-$(CONFIG_CRYPTO_CRC32) += crc32_generic.o
-obj-$(CONFIG_CRYPTO_CRCT10DIF) += crct10dif_common.o crct10dif_generic.o
+obj-$(CONFIG_CRYPTO_CRCT10DIF) += crct10dif_generic.o
 obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o authencesn.o
 obj-$(CONFIG_CRYPTO_LZO) += lzo.o lzo-rle.o
 obj-$(CONFIG_CRYPTO_LZ4) += lz4.o
crypto/crct10dif_common.c deleted +0 -82

82 lines not on this page · raw message

lib/Kconfig +0 -2
index 46806332a8cc..203a50674602 100644
@@ -120,8 +120,6 @@ config CRC16
 
 config CRC_T10DIF
 	tristate "CRC calculation for the T10 Data Integrity Field"
-	select CRYPTO
-	select CRYPTO_CRCT10DIF
 	help
 	  This option is only needed if a module that's not in the
 	  kernel tree needs to calculate CRC checks for use with the
lib/crc-t10dif.c +48 -88

167 lines not on this page · raw message

Signature · 1 line
2.17.1
author reviewer
#2 lore raw

PATCH 2/7 crypto: lib/crc-t10dif - add static call support for optimized versions

In reply to Ard Biesheuvel

Wire up the new static call facility to the CRC-T10DIF library code, so that optimized implementations can be swapped in easily, without having to rely on the complexity of the crypto API shash infrastructure.

---
 include/linux/crc-t10dif.h | 21 ++++++++++++--
 lib/crc-t10dif.c           | 30 +++++++++++++++-----
 2 files changed, 42 insertions(+), 9 deletions(-)
include/linux/crc-t10dif.h +19 -2
index 6bb0c0bf357b..ad8b0a358680 100644
@@ -3,6 +3,7 @@
 #define _LINUX_CRC_T10DIF_H
 
 #include <linux/types.h>
+#include <linux/static_call.h>
 
 #define CRC_T10DIF_DIGEST_SIZE 2
 #define CRC_T10DIF_BLOCK_SIZE 1
@@ -10,7 +11,23 @@
 
 extern __u16 crc_t10dif_generic(__u16 crc, const unsigned char *buffer,
 				size_t len);
-extern __u16 crc_t10dif(unsigned char const *, size_t);
-extern __u16 crc_t10dif_update(__u16 crc, unsigned char const *, size_t);
+
+DECLARE_STATIC_CALL(crc_t10dif_arch, crc_t10dif_generic);
+
+static inline __u16 crc_t10dif_update(__u16 crc, unsigned char const *buffer,
+				      size_t len)
+{
+	return static_call(crc_t10dif_arch)(crc, buffer, len);
+}
+
+static inline __u16 crc_t10dif(unsigned char const *buffer, size_t len)
+{
+	return crc_t10dif_update(0, buffer, len);
+}
+
+int crc_t10dif_register(__u16 (*)(__u16, const unsigned char *, size_t),
+			const char *name);
+
+int crc_t10dif_unregister(void);
 
 #endif
lib/crc-t10dif.c +23 -7
index cbb739f0a0d7..b657cdfb118a 100644
@@ -18,6 +18,11 @@
 #include <linux/static_key.h>
 #include <linux/notifier.h>
 
+DEFINE_STATIC_CALL(crc_t10dif_arch, crc_t10dif_generic);
+EXPORT_STATIC_CALL(crc_t10dif_arch);
+
+static char const *crc_t10dif_arch_name;
+
 /* Table generated using the following polynomium:
  * x^16 + x^15 + x^11 + x^9 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1
  * gt: 0x8bb7
@@ -68,21 +73,32 @@ __u16 crc_t10dif_generic(__u16 crc, const unsigned char *buffer, size_t len)
 }
 EXPORT_SYMBOL(crc_t10dif_generic);
 
-__u16 crc_t10dif_update(__u16 crc, const unsigned char *buffer, size_t len)
+int crc_t10dif_register(__u16 (*func)(__u16, const unsigned char *, size_t),
+			const char *name)
 {
-	return crc_t10dif_generic(crc, buffer, len);
+	if (!name || cmpxchg(&crc_t10dif_arch_name, NULL, name) != NULL)
+		return -EBUSY;
+
+	static_call_update(crc_t10dif_arch, func);
+	return 0;
 }
-EXPORT_SYMBOL(crc_t10dif_update);
+EXPORT_SYMBOL_NS(crc_t10dif_register, CRYPTO_INTERNAL);
 
-__u16 crc_t10dif(const unsigned char *buffer, size_t len)
+int crc_t10dif_unregister(void)
 {
-	return crc_t10dif_update(0, buffer, len);
+	// revert to generic implementation
+	static_call_update(crc_t10dif_arch, crc_t10dif_generic);
+	crc_t10dif_arch_name = NULL;
+
+	// wait for all potential callers of the unregistered routine to finish
+	synchronize_rcu_tasks();
+	return 0;
 }
-EXPORT_SYMBOL(crc_t10dif);
+EXPORT_SYMBOL_NS(crc_t10dif_unregister, CRYPTO_INTERNAL);
 
 static int crc_t10dif_transform_show(char *buffer, const struct kernel_param *kp)
 {
-	return sprintf(buffer, "fallback\n");
+	return sprintf(buffer, "%s\n", crc_t10dif_arch_name ?: "fallback");
 }
 
 module_param_call(transform, NULL, crc_t10dif_transform_show, NULL, 0444);
Signature · 1 line
2.17.1
author reviewer
#3 lore raw

PATCH 3/7 crypto: generic/crc-t10dif - expose both arch and generic shashes

In reply to Ard Biesheuvel

In order to retain the ability to check accelerated implementations of CRC-T10DIF against the generic C implementation, expose both via the generic crypto API shash driver. This relies on the arch specific version to be registered beforehand - this will generally be the case, given that the modules in question are autoloaded via CPU feature matching, but let's use a module soft-dependency as well to trigger a load of such modules if they exist on the system.

---
 crypto/crct10dif_generic.c | 100 ++++++++++++++------
 1 file changed, 72 insertions(+), 28 deletions(-)
crypto/crct10dif_generic.c +72 -28
index e843982073bb..7878eda7513e 100644
@@ -48,8 +48,8 @@ static int chksum_init(struct shash_desc *desc)
 	return 0;
 }
 
-static int chksum_update(struct shash_desc *desc, const u8 *data,
-			 unsigned int length)
+static int chksum_generic_update(struct shash_desc *desc, const u8 *data,
+				 unsigned int length)
 {
 	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
 
@@ -65,54 +65,97 @@ static int chksum_final(struct shash_desc *desc, u8 *out)
 	return 0;
 }
 
-static int __chksum_finup(__u16 crc, const u8 *data, unsigned int len, u8 *out)
+static int __chksum_generic_finup(__u16 crc, const u8 *data, unsigned int len,
+				  u8 *out)
 {
 	*(__u16 *)out = crc_t10dif_generic(crc, data, len);
 	return 0;
 }
 
-static int chksum_finup(struct shash_desc *desc, const u8 *data,
-			unsigned int len, u8 *out)
+static int chksum_generic_finup(struct shash_desc *desc, const u8 *data,
+				unsigned int len, u8 *out)
 {
 	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
 
-	return __chksum_finup(ctx->crc, data, len, out);
+	return __chksum_generic_finup(ctx->crc, data, len, out);
 }
 
-static int chksum_digest(struct shash_desc *desc, const u8 *data,
-			 unsigned int length, u8 *out)
+static int chksum_generic_digest(struct shash_desc *desc, const u8 *data,
+				 unsigned int length, u8 *out)
 {
-	return __chksum_finup(0, data, length, out);
+	return __chksum_generic_finup(0, data, length, out);
 }
 
-static struct shash_alg alg = {
-	.digestsize		=	CRC_T10DIF_DIGEST_SIZE,
-	.init		=	chksum_init,
-	.update		=	chksum_update,
-	.final		=	chksum_final,
-	.finup		=	chksum_finup,
-	.digest		=	chksum_digest,
-	.descsize		=	sizeof(struct chksum_desc_ctx),
-	.base			=	{
-		.cra_name		=	"crct10dif",
-		.cra_driver_name	=	"crct10dif-generic",
-		.cra_priority		=	100,
-		.cra_blocksize		=	CRC_T10DIF_BLOCK_SIZE,
-		.cra_module		=	THIS_MODULE,
-	}
-};
+static int chksum_arch_update(struct shash_desc *desc, const u8 *data,
+			      unsigned int length)
+{
+	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
+
+	ctx->crc = crc_t10dif_update(ctx->crc, data, length);
+	return 0;
+}
+
+static int __chksum_arch_finup(__u16 crc, const u8 *data, unsigned int len,
+			       u8 *out)
+{
+	*(__u16 *)out = crc_t10dif_update(crc, data, len);
+	return 0;
+}
+
+static int chksum_arch_finup(struct shash_desc *desc, const u8 *data,
+			     unsigned int len, u8 *out)
+{
+	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
+
+	return __chksum_arch_finup(ctx->crc, data, len, out);
+}
+
+static int chksum_arch_digest(struct shash_desc *desc, const u8 *data,
+			      unsigned int length, u8 *out)
+{
+	return __chksum_arch_finup(0, data, length, out);
+}
+
+static struct shash_alg algs[] = {{
+	.digestsize		= CRC_T10DIF_DIGEST_SIZE,
+	.init			= chksum_init,
+	.update			= chksum_generic_update,
+	.final			= chksum_final,
+	.finup			= chksum_generic_finup,
+	.digest			= chksum_generic_digest,
+	.descsize		= sizeof(struct chksum_desc_ctx),
+
+	.base.cra_name		= "crct10dif",
+	.base.cra_driver_name	= "crct10dif-generic",
+	.base.cra_blocksize	= CRC_T10DIF_BLOCK_SIZE,
+	.base.cra_module	= THIS_MODULE,
+}, {
+	.digestsize		= CRC_T10DIF_DIGEST_SIZE,
+	.init			= chksum_init,
+	.update			= chksum_arch_update,
+	.final			= chksum_final,
+	.finup			= chksum_arch_finup,
+	.digest			= chksum_arch_digest,
+	.descsize		= sizeof(struct chksum_desc_ctx),
+
+	.base.cra_name		= "crct10dif",
+	.base.cra_driver_name	= "crct10dif-arch",
+	.base.cra_priority	= 100,
+	.base.cra_blocksize	= CRC_T10DIF_BLOCK_SIZE,
+	.base.cra_module	= THIS_MODULE,
+}};
 
 static int __init crct10dif_mod_init(void)
 {
-	return crypto_register_shash(&alg);
+	return crypto_register_shashes(algs, ARRAY_SIZE(algs));
 }
 
 static void __exit crct10dif_mod_fini(void)
 {
-	crypto_unregister_shash(&alg);
+	crypto_unregister_shashes(algs, ARRAY_SIZE(algs));
 }
 
-subsys_initcall(crct10dif_mod_init);
+module_init(crct10dif_mod_init);
 module_exit(crct10dif_mod_fini);
 
 MODULE_AUTHOR("Tim Chen <[email protected]>");
@@ -120,3 +163,4 @@ MODULE_DESCRIPTION("T10 DIF CRC calculation.");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_CRYPTO("crct10dif");
 MODULE_ALIAS_CRYPTO("crct10dif-generic");
+MODULE_SOFTDEP("pre: crct10dif-arch");
Signature · 1 line
2.17.1
author reviewer
#4 lore raw

PATCH 4/7 crypto: x86/crc-t10dif - convert to static call library API

In reply to Ard Biesheuvel

Get rid of the shash boilerplate, and register the accelerated x86 version of the CRC-T10DIF algorithm with the library interface instead.

---
 arch/x86/crypto/crct10dif-pclmul_glue.c | 90 +++-----------------
 1 file changed, 10 insertions(+), 80 deletions(-)
arch/x86/crypto/crct10dif-pclmul_glue.c +10 -80
index 71291d5af9f4..6f06499d96a3 100644
@@ -25,7 +25,6 @@
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/crc-t10dif.h>
-#include <crypto/internal/hash.h>
 #include <crypto/internal/simd.h>
 #include <linux/init.h>
 #include <linux/string.h>
@@ -36,82 +35,17 @@
 
 asmlinkage u16 crc_t10dif_pcl(u16 init_crc, const u8 *buf, size_t len);
 
-struct chksum_desc_ctx {
-	__u16 crc;
-};
-
-static int chksum_init(struct shash_desc *desc)
-{
-	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
-
-	ctx->crc = 0;
-
-	return 0;
-}
-
-static int chksum_update(struct shash_desc *desc, const u8 *data,
-			 unsigned int length)
-{
-	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
-
-	if (length >= 16 && crypto_simd_usable()) {
-		kernel_fpu_begin();
-		ctx->crc = crc_t10dif_pcl(ctx->crc, data, length);
-		kernel_fpu_end();
-	} else
-		ctx->crc = crc_t10dif_generic(ctx->crc, data, length);
-	return 0;
-}
-
-static int chksum_final(struct shash_desc *desc, u8 *out)
-{
-	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
-
-	*(__u16 *)out = ctx->crc;
-	return 0;
-}
-
-static int __chksum_finup(__u16 crc, const u8 *data, unsigned int len, u8 *out)
+static u16 crc_t10dif_x86(u16 crc, const u8 *data, size_t len)
 {
 	if (len >= 16 && crypto_simd_usable()) {
 		kernel_fpu_begin();
-		*(__u16 *)out = crc_t10dif_pcl(crc, data, len);
+		crc = crc_t10dif_pcl(crc, data, len);
 		kernel_fpu_end();
-	} else
-		*(__u16 *)out = crc_t10dif_generic(crc, data, len);
-	return 0;
-}
-
-static int chksum_finup(struct shash_desc *desc, const u8 *data,
-			unsigned int len, u8 *out)
-{
-	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
-
-	return __chksum_finup(ctx->crc, data, len, out);
-}
-
-static int chksum_digest(struct shash_desc *desc, const u8 *data,
-			 unsigned int length, u8 *out)
-{
-	return __chksum_finup(0, data, length, out);
-}
-
-static struct shash_alg alg = {
-	.digestsize		=	CRC_T10DIF_DIGEST_SIZE,
-	.init		=	chksum_init,
-	.update		=	chksum_update,
-	.final		=	chksum_final,
-	.finup		=	chksum_finup,
-	.digest		=	chksum_digest,
-	.descsize		=	sizeof(struct chksum_desc_ctx),
-	.base			=	{
-		.cra_name		=	"crct10dif",
-		.cra_driver_name	=	"crct10dif-pclmul",
-		.cra_priority		=	200,
-		.cra_blocksize		=	CRC_T10DIF_BLOCK_SIZE,
-		.cra_module		=	THIS_MODULE,
+	} else {
+		crc = crc_t10dif_generic(crc, data, len);
 	}
-};
+	return crc;
+}
 
 static const struct x86_cpu_id crct10dif_cpu_id[] = {
 	X86_MATCH_FEATURE(X86_FEATURE_PCLMULQDQ, NULL),
@@ -121,15 +55,12 @@ MODULE_DEVICE_TABLE(x86cpu, crct10dif_cpu_id);
 
 static int __init crct10dif_intel_mod_init(void)
 {
-	if (!x86_match_cpu(crct10dif_cpu_id))
-		return -ENODEV;
-
-	return crypto_register_shash(&alg);
+	return crc_t10dif_register(crc_t10dif_x86, "crct10dif-pclmul");
 }
 
 static void __exit crct10dif_intel_mod_fini(void)
 {
-	crypto_unregister_shash(&alg);
+	crc_t10dif_unregister();
 }
 
 module_init(crct10dif_intel_mod_init);
@@ -138,6 +69,5 @@ module_exit(crct10dif_intel_mod_fini);
 MODULE_AUTHOR("Tim Chen <[email protected]>");
 MODULE_DESCRIPTION("T10 DIF CRC calculation accelerated with PCLMULQDQ.");
 MODULE_LICENSE("GPL");
-
-MODULE_ALIAS_CRYPTO("crct10dif");
-MODULE_ALIAS_CRYPTO("crct10dif-pclmul");
+MODULE_ALIAS("crct10dif-arch");
+MODULE_IMPORT_NS(CRYPTO_INTERNAL);
Signature · 1 line
2.17.1
#5 lore raw

Re: [PATCH 4/7] crypto: x86/crc-t10dif - convert to static call library API

I love your patch! Perhaps something to improve:

Hi Ard,

I love your patch! Perhaps something to improve:

[auto build test WARNING on cryptodev/master]
[also build test WARNING on crypto/master linus/master v5.11-rc3 next-20210111] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Ard-Biesheuvel/crypto-switch-to-static-calls-for-CRC-T10DIF/20210112-005632
base:   https://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git master
config: x86_64-randconfig-a012-20210111 (attached as .config)
compiler: clang version 12.0.0 (https://github.com/llvm/llvm-project 7be3285248bf54d0784a76174cf44cf7c1e780a5)

reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross
# install x86_64 cross compiling tool for clang build
# apt-get install binutils-x86-64-linux-gnu
# https://github.com/0day-ci/linux/commit/df3e7f87b3c1edc4daace5f5df09d9a1896b97dc
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Ard-Biesheuvel/crypto-switch-to-static-calls-for-CRC-T10DIF/20210112-005632 git checkout df3e7f87b3c1edc4daace5f5df09d9a1896b97dc
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=x86_64

If you fix the issue, kindly add following tag as appropriate

All warnings (new ones prefixed by >>):

>> arch/x86/crypto/crct10dif-pclmul_glue.c:50:32: warning: unused variable 'crct10dif_cpu_id' [-Wunused-const-variable]
   static const struct x86_cpu_id crct10dif_cpu_id[] = {
                                  ^

1 warning generated.

vim +/crct10dif_cpu_id +50 arch/x86/crypto/crct10dif-pclmul_glue.c

68411521cc6055ed Herbert Xu 2013-09-07 49

68411521cc6055ed Herbert Xu      2013-09-07 @50  static const struct x86_cpu_id crct10dif_cpu_id[] = {
f30cfacad1ee948c Thomas Gleixner 2020-03-20  51  	X86_MATCH_FEATURE(X86_FEATURE_PCLMULQDQ, NULL),
68411521cc6055ed Herbert Xu      2013-09-07  52  	{}
68411521cc6055ed Herbert Xu      2013-09-07  53  };
68411521cc6055ed Herbert Xu      2013-09-07  54  MODULE_DEVICE_TABLE(x86cpu, crct10dif_cpu_id);

68411521cc6055ed Herbert Xu 2013-09-07 55

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

author reviewer
#6 lore raw

PATCH 5/7 crypto: arm/crc-t10dif - convert to static call library API

In reply to Ard Biesheuvel

Get rid of the shash boilerplate, and register the accelerated ARM version of the CRC-T10DIF algorithm with the library interface instead.

---
 arch/arm/crypto/crct10dif-ce-glue.c | 58 ++++----------------
 1 file changed, 11 insertions(+), 47 deletions(-)
arch/arm/crypto/crct10dif-ce-glue.c +11 -47
index e9191a8c87b9..ce21f958fd49 100644
@@ -5,13 +5,13 @@
  * Copyright (C) 2016 Linaro Ltd <[email protected]>
  */
 
+#include <linux/cpufeature.h>
 #include <linux/crc-t10dif.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/string.h>
 
-#include <crypto/internal/hash.h>
 #include <crypto/internal/simd.h>
 
 #include <asm/neon.h>
@@ -21,68 +21,32 @@
 
 asmlinkage u16 crc_t10dif_pmull(u16 init_crc, const u8 *buf, size_t len);
 
-static int crct10dif_init(struct shash_desc *desc)
+static u16 crc_t10dif_arm(u16 crc, const u8 *data, size_t len)
 {
-	u16 *crc = shash_desc_ctx(desc);
-
-	*crc = 0;
-	return 0;
-}
-
-static int crct10dif_update(struct shash_desc *desc, const u8 *data,
-			    unsigned int length)
-{
-	u16 *crc = shash_desc_ctx(desc);
-
-	if (length >= CRC_T10DIF_PMULL_CHUNK_SIZE && crypto_simd_usable()) {
+	if (len >= CRC_T10DIF_PMULL_CHUNK_SIZE && crypto_simd_usable()) {
 		kernel_neon_begin();
-		*crc = crc_t10dif_pmull(*crc, data, length);
+		crc = crc_t10dif_pmull(crc, data, len);
 		kernel_neon_end();
 	} else {
-		*crc = crc_t10dif_generic(*crc, data, length);
+		crc = crc_t10dif_generic(crc, data, len);
 	}
-
-	return 0;
+	return crc;
 }
 
-static int crct10dif_final(struct shash_desc *desc, u8 *out)
-{
-	u16 *crc = shash_desc_ctx(desc);
-
-	*(u16 *)out = *crc;
-	return 0;
-}
-
-static struct shash_alg crc_t10dif_alg = {
-	.digestsize		= CRC_T10DIF_DIGEST_SIZE,
-	.init			= crct10dif_init,
-	.update			= crct10dif_update,
-	.final			= crct10dif_final,
-	.descsize		= CRC_T10DIF_DIGEST_SIZE,
-
-	.base.cra_name		= "crct10dif",
-	.base.cra_driver_name	= "crct10dif-arm-ce",
-	.base.cra_priority	= 200,
-	.base.cra_blocksize	= CRC_T10DIF_BLOCK_SIZE,
-	.base.cra_module	= THIS_MODULE,
-};
-
 static int __init crc_t10dif_mod_init(void)
 {
-	if (!(elf_hwcap2 & HWCAP2_PMULL))
-		return -ENODEV;
-
-	return crypto_register_shash(&crc_t10dif_alg);
+	return crc_t10dif_register(crc_t10dif_arm, "crct10dif-arm-ce");
 }
 
 static void __exit crc_t10dif_mod_exit(void)
 {
-	crypto_unregister_shash(&crc_t10dif_alg);
+	crc_t10dif_unregister();
 }
 
-module_init(crc_t10dif_mod_init);
+module_cpu_feature_match(PMULL, crc_t10dif_mod_init);
 module_exit(crc_t10dif_mod_exit);
 
 MODULE_AUTHOR("Ard Biesheuvel <[email protected]>");
 MODULE_LICENSE("GPL v2");
-MODULE_ALIAS_CRYPTO("crct10dif");
+MODULE_ALIAS("crct10dif-arch");
+MODULE_IMPORT_NS(CRYPTO_INTERNAL);
Signature · 1 line
2.17.1
author reviewer
#7 lore raw

PATCH 6/7 crypto: arm64/crc-t10dif - convert to static call API

In reply to Ard Biesheuvel

Get rid of the shash boilerplate, and register the accelerated arm64 version of the CRC-T10DIF algorithm with the library interface instead.

---
 arch/arm64/crypto/crct10dif-ce-glue.c | 85 ++++----------------
 1 file changed, 15 insertions(+), 70 deletions(-)
arch/arm64/crypto/crct10dif-ce-glue.c +15 -70
index ccc3f6067742..70c730866d4a 100644
@@ -12,7 +12,6 @@
 #include <linux/module.h>
 #include <linux/string.h>
 
-#include <crypto/internal/hash.h>
 #include <crypto/internal/simd.h>
 
 #include <asm/neon.h>
@@ -23,97 +22,43 @@
 asmlinkage u16 crc_t10dif_pmull_p8(u16 init_crc, const u8 *buf, size_t len);
 asmlinkage u16 crc_t10dif_pmull_p64(u16 init_crc, const u8 *buf, size_t len);
 
-static int crct10dif_init(struct shash_desc *desc)
+static u16 crct10dif_update_pmull_p8(u16 crc, const u8 *data, size_t length)
 {
-	u16 *crc = shash_desc_ctx(desc);
-
-	*crc = 0;
-	return 0;
-}
-
-static int crct10dif_update_pmull_p8(struct shash_desc *desc, const u8 *data,
-			    unsigned int length)
-{
-	u16 *crc = shash_desc_ctx(desc);
-
 	if (length >= CRC_T10DIF_PMULL_CHUNK_SIZE && crypto_simd_usable()) {
 		kernel_neon_begin();
-		*crc = crc_t10dif_pmull_p8(*crc, data, length);
+		crc = crc_t10dif_pmull_p8(crc, data, length);
 		kernel_neon_end();
 	} else {
-		*crc = crc_t10dif_generic(*crc, data, length);
+		crc = crc_t10dif_generic(crc, data, length);
 	}
-
-	return 0;
+	return crc;
 }
 
-static int crct10dif_update_pmull_p64(struct shash_desc *desc, const u8 *data,
-			    unsigned int length)
+static u16 crct10dif_update_pmull_p64(u16 crc, const u8 *data, size_t length)
 {
-	u16 *crc = shash_desc_ctx(desc);
-
 	if (length >= CRC_T10DIF_PMULL_CHUNK_SIZE && crypto_simd_usable()) {
 		kernel_neon_begin();
-		*crc = crc_t10dif_pmull_p64(*crc, data, length);
+		crc = crc_t10dif_pmull_p64(crc, data, length);
 		kernel_neon_end();
 	} else {
-		*crc = crc_t10dif_generic(*crc, data, length);
+		crc = crc_t10dif_generic(crc, data, length);
 	}
-
-	return 0;
+	return crc;
 }
 
-static int crct10dif_final(struct shash_desc *desc, u8 *out)
-{
-	u16 *crc = shash_desc_ctx(desc);
-
-	*(u16 *)out = *crc;
-	return 0;
-}
-
-static struct shash_alg crc_t10dif_alg[] = {{
-	.digestsize		= CRC_T10DIF_DIGEST_SIZE,
-	.init			= crct10dif_init,
-	.update			= crct10dif_update_pmull_p8,
-	.final			= crct10dif_final,
-	.descsize		= CRC_T10DIF_DIGEST_SIZE,
-
-	.base.cra_name		= "crct10dif",
-	.base.cra_driver_name	= "crct10dif-arm64-neon",
-	.base.cra_priority	= 100,
-	.base.cra_blocksize	= CRC_T10DIF_BLOCK_SIZE,
-	.base.cra_module	= THIS_MODULE,
-}, {
-	.digestsize		= CRC_T10DIF_DIGEST_SIZE,
-	.init			= crct10dif_init,
-	.update			= crct10dif_update_pmull_p64,
-	.final			= crct10dif_final,
-	.descsize		= CRC_T10DIF_DIGEST_SIZE,
-
-	.base.cra_name		= "crct10dif",
-	.base.cra_driver_name	= "crct10dif-arm64-ce",
-	.base.cra_priority	= 200,
-	.base.cra_blocksize	= CRC_T10DIF_BLOCK_SIZE,
-	.base.cra_module	= THIS_MODULE,
-}};
-
 static int __init crc_t10dif_mod_init(void)
 {
 	if (cpu_have_named_feature(PMULL))
-		return crypto_register_shashes(crc_t10dif_alg,
-					       ARRAY_SIZE(crc_t10dif_alg));
+		return crc_t10dif_register(crct10dif_update_pmull_p64,
+					   "crct10dif-arm64-ce");
 	else
-		/* only register the first array element */
-		return crypto_register_shash(crc_t10dif_alg);
+		return crc_t10dif_register(crct10dif_update_pmull_p8,
+					   "crct10dif-arm64-neon");
 }
 
 static void __exit crc_t10dif_mod_exit(void)
 {
-	if (cpu_have_named_feature(PMULL))
-		crypto_unregister_shashes(crc_t10dif_alg,
-					  ARRAY_SIZE(crc_t10dif_alg));
-	else
-		crypto_unregister_shash(crc_t10dif_alg);
+	crc_t10dif_unregister();
 }
 
 module_cpu_feature_match(ASIMD, crc_t10dif_mod_init);
@@ -121,5 +66,5 @@ module_exit(crc_t10dif_mod_exit);
 
 MODULE_AUTHOR("Ard Biesheuvel <[email protected]>");
 MODULE_LICENSE("GPL v2");
-MODULE_ALIAS_CRYPTO("crct10dif");
-MODULE_ALIAS_CRYPTO("crct10dif-arm64-ce");
+MODULE_ALIAS("crct10dif-arch");
+MODULE_IMPORT_NS(CRYPTO_INTERNAL);
Signature · 1 line
2.17.1
author reviewer
#8 lore raw

PATCH 7/7 crypto: powerpc/crc-t10dif - convert to static call API

In reply to Ard Biesheuvel

Get rid of the shash boilerplate, and register the accelerated PowerPC version of the CRC-T10DIF algorithm with the library interface instead.

---
 arch/powerpc/crypto/crct10dif-vpmsum_glue.c | 51 ++------------------
 1 file changed, 4 insertions(+), 47 deletions(-)
arch/powerpc/crypto/crct10dif-vpmsum_glue.c +4 -47
index 1dc8b6915178..26c7da181018 100644
@@ -7,7 +7,6 @@
  */
 
 #include <linux/crc-t10dif.h>
-#include <crypto/internal/hash.h>
 #include <crypto/internal/simd.h>
 #include <linux/init.h>
 #include <linux/module.h>
@@ -61,59 +60,17 @@ static u16 crct10dif_vpmsum(u16 crci, unsigned char const *p, size_t len)
 	return crc & 0xffff;
 }
 
-static int crct10dif_vpmsum_init(struct shash_desc *desc)
-{
-	u16 *crc = shash_desc_ctx(desc);
-
-	*crc = 0;
-	return 0;
-}
-
-static int crct10dif_vpmsum_update(struct shash_desc *desc, const u8 *data,
-			    unsigned int length)
-{
-	u16 *crc = shash_desc_ctx(desc);
-
-	*crc = crct10dif_vpmsum(*crc, data, length);
-
-	return 0;
-}
-
-
-static int crct10dif_vpmsum_final(struct shash_desc *desc, u8 *out)
-{
-	u16 *crcp = shash_desc_ctx(desc);
-
-	*(u16 *)out = *crcp;
-	return 0;
-}
-
-static struct shash_alg alg = {
-	.init		= crct10dif_vpmsum_init,
-	.update		= crct10dif_vpmsum_update,
-	.final		= crct10dif_vpmsum_final,
-	.descsize	= CRC_T10DIF_DIGEST_SIZE,
-	.digestsize	= CRC_T10DIF_DIGEST_SIZE,
-	.base		= {
-		.cra_name		= "crct10dif",
-		.cra_driver_name	= "crct10dif-vpmsum",
-		.cra_priority		= 200,
-		.cra_blocksize		= CRC_T10DIF_BLOCK_SIZE,
-		.cra_module		= THIS_MODULE,
-	}
-};
-
 static int __init crct10dif_vpmsum_mod_init(void)
 {
 	if (!cpu_has_feature(CPU_FTR_ARCH_207S))
 		return -ENODEV;
 
-	return crypto_register_shash(&alg);
+	return crc_t10dif_register(crct10dif_vpmsum, "crct10dif-vpmsum");
 }
 
 static void __exit crct10dif_vpmsum_mod_fini(void)
 {
-	crypto_unregister_shash(&alg);
+	crc_t10dif_unregister();
 }
 
 module_cpu_feature_match(PPC_MODULE_FEATURE_VEC_CRYPTO, crct10dif_vpmsum_mod_init);
@@ -122,5 +79,5 @@ module_exit(crct10dif_vpmsum_mod_fini);
 MODULE_AUTHOR("Daniel Axtens <[email protected]>");
 MODULE_DESCRIPTION("CRCT10DIF using vector polynomial multiply-sum instructions");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS_CRYPTO("crct10dif");
-MODULE_ALIAS_CRYPTO("crct10dif-vpmsum");
+MODULE_ALIAS("crct10dif-arch");
+MODULE_IMPORT_NS(CRYPTO_INTERNAL);
Signature · 1 line
2.17.1
author reviewer
#9 lore raw
In reply to Ard Biesheuvel
Quoted 25 lines · Ard Biesheuvel

CRC-T10DIF is a very poor match for the crypto API:
- every user in the kernel calls it via a library wrapper around the shash API, so all callers share a single instance of the transform
- each architecture provides at most a single optimized implementation, based on SIMD instructions for carryless multiplication

In other words, none of the flexibility it provides is put to good use, and so it is better to get rid of this complexity, and expose the optimized implementations via static calls instead. This removes a substantial chunk of code, and also gets rid of any indirect calls on architectures that obsess about those (x86)

If this approach is deemed suitable, there are other places where we might consider adopting it: CRC32 and CRC32(C).

Patch #1 does some preparatory refactoring and removes the library wrapper around the shash transform.

Patch #2 introduces the actual static calls, along with the registration routines to update the crc-t10dif implementation at runtime.

Patch #3 updates the generic CRC-T10DIF shash driver so it distinguishes between the optimized library code and the generic library code.

Quoted 7 lines

Patches #4 to #7 update the various arch implementations to switch over to the new method.

Special request to Peter to take a look at patch #2, and in particular, whether synchronize_rcu_tasks() is sufficient to ensure that a module providing the target of a static call can be unloaded safely.

It seems I may have managed to confuse myself slightly here: without an upper bound on the size of the input of the crc_t10dif() routine, I suppose we can never assume that all its callers have finished.

Insights welcome ...

author reviewer
#10 lore raw
Quoted 30 lines · Ard Biesheuvel
Quoted 28 lines · Ard Biesheuvel

CRC-T10DIF is a very poor match for the crypto API:
- every user in the kernel calls it via a library wrapper around the shash API, so all callers share a single instance of the transform
- each architecture provides at most a single optimized implementation, based on SIMD instructions for carryless multiplication

In other words, none of the flexibility it provides is put to good use, and so it is better to get rid of this complexity, and expose the optimized implementations via static calls instead. This removes a substantial chunk of code, and also gets rid of any indirect calls on architectures that obsess about those (x86)

If this approach is deemed suitable, there are other places where we might consider adopting it: CRC32 and CRC32(C).

Patch #1 does some preparatory refactoring and removes the library wrapper around the shash transform.

Patch #2 introduces the actual static calls, along with the registration routines to update the crc-t10dif implementation at runtime.

Patch #3 updates the generic CRC-T10DIF shash driver so it distinguishes between the optimized library code and the generic library code.

Patches #4 to #7 update the various arch implementations to switch over to the new method.

Quoted 9 lines
Quoted 4 lines

Special request to Peter to take a look at patch #2, and in particular, whether synchronize_rcu_tasks() is sufficient to ensure that a module providing the target of a static call can be unloaded safely.

It seems I may have managed to confuse myself slightly here: without an upper bound on the size of the input of the crc_t10dif() routine, I suppose we can never assume that all its callers have finished.

Replying to self again - apologies.

I think this is actually correct after all: synchronize_rcu_tasks() guarantees that all tasks have passed through a 'safe state', i.e., voluntary schedule(), return to userland, etc, which guarantees that no task could be executing the old static call target after synchronize_rcu_tasks() returns.

#11 lore raw
Quoted 12 lines · Ard Biesheuvel
Quoted 10 lines · Ard Biesheuvel
Quoted 3 lines · Ard Biesheuvel

Special request to Peter to take a look at patch #2, and in particular, whether synchronize_rcu_tasks() is sufficient to ensure that a module providing the target of a static call can be unloaded safely.

It seems I may have managed to confuse myself slightly here: without an upper bound on the size of the input of the crc_t10dif() routine, I suppose we can never assume that all its callers have finished.

Quoted 7 lines

Replying to self again - apologies.

I think this is actually correct after all: synchronize_rcu_tasks() guarantees that all tasks have passed through a 'safe state', i.e., voluntary schedule(), return to userland, etc, which guarantees that no task could be executing the old static call target after synchronize_rcu_tasks() returns.

Right, I think it should work.

My initial question was why you'd want to support the unreg at all. AFAICT these implementations are tiny, why bother having them as a module, or if you insist having them as a module, why allowing removal?

author reviewer
#12 lore raw
Quoted 22 lines · Peter Zijlstra
Quoted 12 lines · Ard Biesheuvel
Quoted 10 lines · Ard Biesheuvel
Quoted 3 lines · Ard Biesheuvel

Special request to Peter to take a look at patch #2, and in particular, whether synchronize_rcu_tasks() is sufficient to ensure that a module providing the target of a static call can be unloaded safely.

It seems I may have managed to confuse myself slightly here: without an upper bound on the size of the input of the crc_t10dif() routine, I suppose we can never assume that all its callers have finished.

Quoted 7 lines

Replying to self again - apologies.

I think this is actually correct after all: synchronize_rcu_tasks() guarantees that all tasks have passed through a 'safe state', i.e., voluntary schedule(), return to userland, etc, which guarantees that no task could be executing the old static call target after synchronize_rcu_tasks() returns.

Quoted 5 lines

Right, I think it should work.

My initial question was why you'd want to support the unreg at all. AFAICT these implementations are tiny, why bother having them as a module, or if you insist having them as a module, why allowing removal?

Yeah, good question.

Having the accelerated version as a module makes sense imo: it will only be loaded if it is supported on the system, and it can be blacklisted by the user if it does not want it for any reason. Unload is just for completeness/symmetry, but it is unlikely to be crucial to anyone in practice.

In any case, thanks for confirming - if this looks sane to you then we may be able to use this pattern in other places as well.

maintainer
#13 lore raw
In reply to Ard Biesheuvel
Quoted 46 lines · Ard Biesheuvel

CRC-T10DIF is a very poor match for the crypto API:
- every user in the kernel calls it via a library wrapper around the shash API, so all callers share a single instance of the transform
- each architecture provides at most a single optimized implementation, based on SIMD instructions for carryless multiplication

In other words, none of the flexibility it provides is put to good use, and so it is better to get rid of this complexity, and expose the optimized implementations via static calls instead. This removes a substantial chunk of code, and also gets rid of any indirect calls on architectures that obsess about those (x86)

If this approach is deemed suitable, there are other places where we might consider adopting it: CRC32 and CRC32(C).

Patch #1 does some preparatory refactoring and removes the library wrapper around the shash transform.

Patch #2 introduces the actual static calls, along with the registration routines to update the crc-t10dif implementation at runtime.

Patch #3 updates the generic CRC-T10DIF shash driver so it distinguishes between the optimized library code and the generic library code.

Patches #4 to #7 update the various arch implementations to switch over to the new method.

Special request to Peter to take a look at patch #2, and in particular, whether synchronize_rcu_tasks() is sufficient to ensure that a module providing the target of a static call can be unloaded safely.

Cc "Martin K. Petersen" <[email protected]>
Cc Eric Biggers <[email protected]>
Cc Peter Zijlstra <[email protected]>

Ard Biesheuvel (7):
crypto: crc-t10dif - turn library wrapper for shash into generic
library
crypto: lib/crc-t10dif - add static call support for optimized
versions
crypto: generic/crc-t10dif - expose both arch and generic shashes
crypto: x86/crc-t10dif - convert to static call library API
crypto: arm/crc-t10dif - convert to static call library API
crypto: arm64/crc-t10dif - convert to static call API
crypto: powerpc/crc-t10dif - convert to static call API

Quoted 15 lines
 arch/arm/crypto/Kconfig                     |   2 +-
 arch/arm/crypto/crct10dif-ce-glue.c         |  58 ++------
 arch/arm64/crypto/Kconfig                   |   3 +-
 arch/arm64/crypto/crct10dif-ce-glue.c       |  85 ++---------
 arch/powerpc/crypto/crct10dif-vpmsum_glue.c |  51 +------
 arch/x86/crypto/crct10dif-pclmul_glue.c     |  90 ++----------
 crypto/Kconfig                              |   7 +-
 crypto/Makefile                             |   2 +-
 crypto/crct10dif_common.c                   |  82 -----------
 crypto/crct10dif_generic.c                  | 100 +++++++++----
 include/linux/crc-t10dif.h                  |  21 ++-
 lib/Kconfig                                 |   2 -
 lib/crc-t10dif.c                            | 152 +++++++++-----------
 13 files changed, 204 insertions(+), 451 deletions(-)
 delete mode 100644 crypto/crct10dif_common.c

There is already a library API for two other hash functions, BLAKE2s and Poly1305, which takes advantage of architecture-specific implementations without using static calls. Also, those algorithms are likewise also exposed through the shash API, but in a different way from what this patchset proposes.

Is there a reason not to do things in the same way? What are the advantages of the new approach that you're proposing?

- Eric

author reviewer
#14 lore raw
Quoted 64 lines · Eric Biggers
Quoted 46 lines · Ard Biesheuvel

CRC-T10DIF is a very poor match for the crypto API:
- every user in the kernel calls it via a library wrapper around the shash API, so all callers share a single instance of the transform
- each architecture provides at most a single optimized implementation, based on SIMD instructions for carryless multiplication

In other words, none of the flexibility it provides is put to good use, and so it is better to get rid of this complexity, and expose the optimized implementations via static calls instead. This removes a substantial chunk of code, and also gets rid of any indirect calls on architectures that obsess about those (x86)

If this approach is deemed suitable, there are other places where we might consider adopting it: CRC32 and CRC32(C).

Patch #1 does some preparatory refactoring and removes the library wrapper around the shash transform.

Patch #2 introduces the actual static calls, along with the registration routines to update the crc-t10dif implementation at runtime.

Patch #3 updates the generic CRC-T10DIF shash driver so it distinguishes between the optimized library code and the generic library code.

Patches #4 to #7 update the various arch implementations to switch over to the new method.

Special request to Peter to take a look at patch #2, and in particular, whether synchronize_rcu_tasks() is sufficient to ensure that a module providing the target of a static call can be unloaded safely.

Cc "Martin K. Petersen" <[email protected]>
Cc Eric Biggers <[email protected]>
Cc Peter Zijlstra <[email protected]>

Ard Biesheuvel (7):
crypto: crc-t10dif - turn library wrapper for shash into generic
library
crypto: lib/crc-t10dif - add static call support for optimized
versions
crypto: generic/crc-t10dif - expose both arch and generic shashes
crypto: x86/crc-t10dif - convert to static call library API
crypto: arm/crc-t10dif - convert to static call library API
crypto: arm64/crc-t10dif - convert to static call API
crypto: powerpc/crc-t10dif - convert to static call API

Quoted 15 lines
 arch/arm/crypto/Kconfig                     |   2 +-
 arch/arm/crypto/crct10dif-ce-glue.c         |  58 ++------
 arch/arm64/crypto/Kconfig                   |   3 +-
 arch/arm64/crypto/crct10dif-ce-glue.c       |  85 ++---------
 arch/powerpc/crypto/crct10dif-vpmsum_glue.c |  51 +------
 arch/x86/crypto/crct10dif-pclmul_glue.c     |  90 ++----------
 crypto/Kconfig                              |   7 +-
 crypto/Makefile                             |   2 +-
 crypto/crct10dif_common.c                   |  82 -----------
 crypto/crct10dif_generic.c                  | 100 +++++++++----
 include/linux/crc-t10dif.h                  |  21 ++-
 lib/Kconfig                                 |   2 -
 lib/crc-t10dif.c                            | 152 +++++++++-----------
 13 files changed, 204 insertions(+), 451 deletions(-)
 delete mode 100644 crypto/crct10dif_common.c
Quoted 8 lines

There is already a library API for two other hash functions, BLAKE2s and Poly1305, which takes advantage of architecture-specific implementations without using static calls. Also, those algorithms are likewise also exposed through the shash API, but in a different way from what this patchset proposes.

Is there a reason not to do things in the same way? What are the advantages of the new approach that you're proposing?

The current approach uses build time dependencies - i.e., if you decide to build the accelerated implementation, you always have to load it, even if the accelerated implementation cannot be used on the system in question, and it is up to that code to use fallbacks for everything, This was kind of a compromise on my part when we were having the crypto library vs Wireguard discussion - I mentioned at the time that [in my opinion] it was a temporary approach because static call support was taking so long to arrive. (lwn article here [0] but the links in it seem to be dead). It also results in some nasty Kconfig dependencies because building the generic code into the kernel and building the accelerated code as a module gives problems.

I agree that having different approaches for doing the same thing is suboptimal, but I think the situation may be slightly different for plain SIMD code such as blake2 and poly1305 versus crc implementations based on carryless multiplication instructions which may be rare but 10-20x faster if they are supported.

So in summary, I think this approach is better. The generic code can be built in and superseded by module code, and there are no dependencies going both ways.

There are some complications as well, though:
- module softdeps don't work {afaik) if the depender is builtin
- our poly1305 implementations use a different layout for the state that is passed between the init/update/final calls, so it may be tricky to use a similar approach there.

[0] https://lwn.net/Articles/802376/

author reviewer
#15 lore raw
Quoted 97 lines · Ard Biesheuvel
Quoted 64 lines · Eric Biggers
Quoted 46 lines · Ard Biesheuvel

CRC-T10DIF is a very poor match for the crypto API:
- every user in the kernel calls it via a library wrapper around the shash API, so all callers share a single instance of the transform
- each architecture provides at most a single optimized implementation, based on SIMD instructions for carryless multiplication

In other words, none of the flexibility it provides is put to good use, and so it is better to get rid of this complexity, and expose the optimized implementations via static calls instead. This removes a substantial chunk of code, and also gets rid of any indirect calls on architectures that obsess about those (x86)

If this approach is deemed suitable, there are other places where we might consider adopting it: CRC32 and CRC32(C).

Patch #1 does some preparatory refactoring and removes the library wrapper around the shash transform.

Patch #2 introduces the actual static calls, along with the registration routines to update the crc-t10dif implementation at runtime.

Patch #3 updates the generic CRC-T10DIF shash driver so it distinguishes between the optimized library code and the generic library code.

Patches #4 to #7 update the various arch implementations to switch over to the new method.

Special request to Peter to take a look at patch #2, and in particular, whether synchronize_rcu_tasks() is sufficient to ensure that a module providing the target of a static call can be unloaded safely.

Cc "Martin K. Petersen" <[email protected]>
Cc Eric Biggers <[email protected]>
Cc Peter Zijlstra <[email protected]>

Ard Biesheuvel (7):
crypto: crc-t10dif - turn library wrapper for shash into generic
library
crypto: lib/crc-t10dif - add static call support for optimized
versions
crypto: generic/crc-t10dif - expose both arch and generic shashes
crypto: x86/crc-t10dif - convert to static call library API
crypto: arm/crc-t10dif - convert to static call library API
crypto: arm64/crc-t10dif - convert to static call API
crypto: powerpc/crc-t10dif - convert to static call API

Quoted 15 lines
 arch/arm/crypto/Kconfig                     |   2 +-
 arch/arm/crypto/crct10dif-ce-glue.c         |  58 ++------
 arch/arm64/crypto/Kconfig                   |   3 +-
 arch/arm64/crypto/crct10dif-ce-glue.c       |  85 ++---------
 arch/powerpc/crypto/crct10dif-vpmsum_glue.c |  51 +------
 arch/x86/crypto/crct10dif-pclmul_glue.c     |  90 ++----------
 crypto/Kconfig                              |   7 +-
 crypto/Makefile                             |   2 +-
 crypto/crct10dif_common.c                   |  82 -----------
 crypto/crct10dif_generic.c                  | 100 +++++++++----
 include/linux/crc-t10dif.h                  |  21 ++-
 lib/Kconfig                                 |   2 -
 lib/crc-t10dif.c                            | 152 +++++++++-----------
 13 files changed, 204 insertions(+), 451 deletions(-)
 delete mode 100644 crypto/crct10dif_common.c
Quoted 8 lines

There is already a library API for two other hash functions, BLAKE2s and Poly1305, which takes advantage of architecture-specific implementations without using static calls. Also, those algorithms are likewise also exposed through the shash API, but in a different way from what this patchset proposes.

Is there a reason not to do things in the same way? What are the advantages of the new approach that you're proposing?

The current approach uses build time dependencies - i.e., if you decide to build the accelerated implementation, you always have to load it, even if the accelerated implementation cannot be used on the system in question, and it is up to that code to use fallbacks for everything, This was kind of a compromise on my part when we were having the crypto library vs Wireguard discussion - I mentioned at the time that [in my opinion] it was a temporary approach because static call support was taking so long to arrive. (lwn article here [0] but the links in it seem to be dead). It also results in some nasty Kconfig dependencies because building the generic code into the kernel and building the accelerated code as a module gives problems.

I agree that having different approaches for doing the same thing is suboptimal, but I think the situation may be slightly different for plain SIMD code such as blake2 and poly1305 versus crc implementations based on carryless multiplication instructions which may be rare but 10-20x faster if they are supported.

So in summary, I think this approach is better. The generic code can be built in and superseded by module code, and there are no dependencies going both ways.

Quoted 7 lines

There are some complications as well, though:
- module softdeps don't work {afaik) if the depender is builtin
- our poly1305 implementations use a different layout for the state that is passed between the init/update/final calls, so it may be tricky to use a similar approach there.

This does not actually work. The kernel_fpu_end() occurring in the CRC-T10 code amounts to a voluntary schedule, which means synchronize_rcu_tasks() does not guarantee that the accelerated code is no longer live after the static call is updated to refer to the generic code again, and so the remove is risky.

There are some other issues I want to focus on first, so I am going to disregard this series for now.