Skip to content

Commit f3813f4

Browse files
keithbuschaxboe
authored andcommitted
crypto: add rocksoft 64b crc guard tag framework
Hardware specific features may be able to calculate a crc64, so provide a framework for drivers to register their implementation. If nothing is registered, fallback to the generic table lookup implementation. The implementation is modeled after the crct10dif equivalent. Signed-off-by: Keith Busch <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jens Axboe <[email protected]>
1 parent cbc0a40 commit f3813f4

File tree

9 files changed

+258
-0
lines changed

9 files changed

+258
-0
lines changed

crypto/Kconfig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -735,6 +735,11 @@ config CRYPTO_CRCT10DIF_VPMSUM
735735
multiply-sum (vpmsum) instructions, introduced in POWER8. Enable on
736736
POWER8 and newer processors for improved performance.
737737

738+
config CRYPTO_CRC64_ROCKSOFT
739+
tristate "Rocksoft Model CRC64 algorithm"
740+
depends on CRC64
741+
select CRYPTO_HASH
742+
738743
config CRYPTO_VPMSUM_TESTER
739744
tristate "Powerpc64 vpmsum hardware acceleration tester"
740745
depends on CRYPTO_CRCT10DIF_VPMSUM && CRYPTO_CRC32C_VPMSUM

crypto/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
152152
obj-$(CONFIG_CRYPTO_CRC32C) += crc32c_generic.o
153153
obj-$(CONFIG_CRYPTO_CRC32) += crc32_generic.o
154154
obj-$(CONFIG_CRYPTO_CRCT10DIF) += crct10dif_common.o crct10dif_generic.o
155+
obj-$(CONFIG_CRYPTO_CRC64_ROCKSOFT) += crc64_rocksoft_generic.o
155156
obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o authencesn.o
156157
obj-$(CONFIG_CRYPTO_LZO) += lzo.o lzo-rle.o
157158
obj-$(CONFIG_CRYPTO_LZ4) += lz4.o

crypto/crc64_rocksoft_generic.c

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
3+
#include <linux/crc64.h>
4+
#include <linux/module.h>
5+
#include <crypto/internal/hash.h>
6+
#include <asm/unaligned.h>
7+
8+
static int chksum_init(struct shash_desc *desc)
9+
{
10+
u64 *crc = shash_desc_ctx(desc);
11+
12+
*crc = 0;
13+
14+
return 0;
15+
}
16+
17+
static int chksum_update(struct shash_desc *desc, const u8 *data,
18+
unsigned int length)
19+
{
20+
u64 *crc = shash_desc_ctx(desc);
21+
22+
*crc = crc64_rocksoft_generic(*crc, data, length);
23+
24+
return 0;
25+
}
26+
27+
static int chksum_final(struct shash_desc *desc, u8 *out)
28+
{
29+
u64 *crc = shash_desc_ctx(desc);
30+
31+
put_unaligned_le64(*crc, out);
32+
return 0;
33+
}
34+
35+
static int __chksum_finup(u64 crc, const u8 *data, unsigned int len, u8 *out)
36+
{
37+
crc = crc64_rocksoft_generic(crc, data, len);
38+
put_unaligned_le64(crc, out);
39+
return 0;
40+
}
41+
42+
static int chksum_finup(struct shash_desc *desc, const u8 *data,
43+
unsigned int len, u8 *out)
44+
{
45+
u64 *crc = shash_desc_ctx(desc);
46+
47+
return __chksum_finup(*crc, data, len, out);
48+
}
49+
50+
static int chksum_digest(struct shash_desc *desc, const u8 *data,
51+
unsigned int length, u8 *out)
52+
{
53+
return __chksum_finup(0, data, length, out);
54+
}
55+
56+
static struct shash_alg alg = {
57+
.digestsize = sizeof(u64),
58+
.init = chksum_init,
59+
.update = chksum_update,
60+
.final = chksum_final,
61+
.finup = chksum_finup,
62+
.digest = chksum_digest,
63+
.descsize = sizeof(u64),
64+
.base = {
65+
.cra_name = CRC64_ROCKSOFT_STRING,
66+
.cra_driver_name = "crc64-rocksoft-generic",
67+
.cra_priority = 200,
68+
.cra_blocksize = 1,
69+
.cra_module = THIS_MODULE,
70+
}
71+
};
72+
73+
static int __init crc64_rocksoft_init(void)
74+
{
75+
return crypto_register_shash(&alg);
76+
}
77+
78+
static void __exit crc64_rocksoft_exit(void)
79+
{
80+
crypto_unregister_shash(&alg);
81+
}
82+
83+
module_init(crc64_rocksoft_init);
84+
module_exit(crc64_rocksoft_exit);
85+
86+
MODULE_LICENSE("GPL");
87+
MODULE_DESCRIPTION("Rocksoft model CRC64 calculation.");
88+
MODULE_ALIAS_CRYPTO("crc64-rocksoft");
89+
MODULE_ALIAS_CRYPTO("crc64-rocksoft-generic");

crypto/testmgr.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4526,6 +4526,13 @@ static const struct alg_test_desc alg_test_descs[] = {
45264526
.suite = {
45274527
.hash = __VECS(crc32c_tv_template)
45284528
}
4529+
}, {
4530+
.alg = "crc64-rocksoft",
4531+
.test = alg_test_hash,
4532+
.fips_allowed = 1,
4533+
.suite = {
4534+
.hash = __VECS(crc64_rocksoft_tv_template)
4535+
}
45294536
}, {
45304537
.alg = "crct10dif",
45314538
.test = alg_test_hash,

crypto/testmgr.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3679,6 +3679,21 @@ static const struct hash_testvec rmd160_tv_template[] = {
36793679
}
36803680
};
36813681

3682+
static const u8 zeroes[4096] = { [0 ... 4095] = 0 };
3683+
static const u8 ones[4096] = { [0 ... 4095] = 0xff };
3684+
3685+
static const struct hash_testvec crc64_rocksoft_tv_template[] = {
3686+
{
3687+
.plaintext = zeroes,
3688+
.psize = 4096,
3689+
.digest = (u8 *)(u64[]){ 0x6482d367eb22b64eull },
3690+
}, {
3691+
.plaintext = ones,
3692+
.psize = 4096,
3693+
.digest = (u8 *)(u64[]){ 0xc0ddba7302eca3acull },
3694+
}
3695+
};
3696+
36823697
static const struct hash_testvec crct10dif_tv_template[] = {
36833698
{
36843699
.plaintext = "abc",

include/linux/crc64.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,12 @@
77

88
#include <linux/types.h>
99

10+
#define CRC64_ROCKSOFT_STRING "crc64-rocksoft"
11+
1012
u64 __pure crc64_be(u64 crc, const void *p, size_t len);
1113
u64 __pure crc64_rocksoft_generic(u64 crc, const void *p, size_t len);
1214

15+
u64 crc64_rocksoft(const unsigned char *buffer, size_t len);
16+
u64 crc64_rocksoft_update(u64 crc, const unsigned char *buffer, size_t len);
17+
1318
#endif /* _LINUX_CRC64_H */

lib/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,15 @@ config CRC_T10DIF
145145
kernel tree needs to calculate CRC checks for use with the
146146
SCSI data integrity subsystem.
147147

148+
config CRC64_ROCKSOFT
149+
tristate "CRC calculation for the Rocksoft model CRC64"
150+
select CRC64
151+
select CRYPTO
152+
select CRYPTO_CRC64_ROCKSOFT
153+
help
154+
This option provides a CRC64 API to a registered crypto driver.
155+
This is used with the block layer's data integrity subsystem.
156+
148157
config CRC_ITU_T
149158
tristate "CRC ITU-T V.41 functions"
150159
help

lib/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ obj-$(CONFIG_CRC4) += crc4.o
175175
obj-$(CONFIG_CRC7) += crc7.o
176176
obj-$(CONFIG_LIBCRC32C) += libcrc32c.o
177177
obj-$(CONFIG_CRC8) += crc8.o
178+
obj-$(CONFIG_CRC64_ROCKSOFT) += crc64-rocksoft.o
178179
obj-$(CONFIG_XXHASH) += xxhash.o
179180
obj-$(CONFIG_GENERIC_ALLOCATOR) += genalloc.o
180181

lib/crc64-rocksoft.c

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
3+
#include <linux/types.h>
4+
#include <linux/module.h>
5+
#include <linux/crc64.h>
6+
#include <linux/err.h>
7+
#include <linux/init.h>
8+
#include <crypto/hash.h>
9+
#include <crypto/algapi.h>
10+
#include <linux/static_key.h>
11+
#include <linux/notifier.h>
12+
13+
static struct crypto_shash __rcu *crc64_rocksoft_tfm;
14+
static DEFINE_STATIC_KEY_TRUE(crc64_rocksoft_fallback);
15+
static DEFINE_MUTEX(crc64_rocksoft_mutex);
16+
static struct work_struct crc64_rocksoft_rehash_work;
17+
18+
static int crc64_rocksoft_notify(struct notifier_block *self, unsigned long val, void *data)
19+
{
20+
struct crypto_alg *alg = data;
21+
22+
if (val != CRYPTO_MSG_ALG_LOADED ||
23+
strcmp(alg->cra_name, CRC64_ROCKSOFT_STRING))
24+
return NOTIFY_DONE;
25+
26+
schedule_work(&crc64_rocksoft_rehash_work);
27+
return NOTIFY_OK;
28+
}
29+
30+
static void crc64_rocksoft_rehash(struct work_struct *work)
31+
{
32+
struct crypto_shash *new, *old;
33+
34+
mutex_lock(&crc64_rocksoft_mutex);
35+
old = rcu_dereference_protected(crc64_rocksoft_tfm,
36+
lockdep_is_held(&crc64_rocksoft_mutex));
37+
new = crypto_alloc_shash(CRC64_ROCKSOFT_STRING, 0, 0);
38+
if (IS_ERR(new)) {
39+
mutex_unlock(&crc64_rocksoft_mutex);
40+
return;
41+
}
42+
rcu_assign_pointer(crc64_rocksoft_tfm, new);
43+
mutex_unlock(&crc64_rocksoft_mutex);
44+
45+
if (old) {
46+
synchronize_rcu();
47+
crypto_free_shash(old);
48+
} else {
49+
static_branch_disable(&crc64_rocksoft_fallback);
50+
}
51+
}
52+
53+
static struct notifier_block crc64_rocksoft_nb = {
54+
.notifier_call = crc64_rocksoft_notify,
55+
};
56+
57+
u64 crc64_rocksoft_update(u64 crc, const unsigned char *buffer, size_t len)
58+
{
59+
struct {
60+
struct shash_desc shash;
61+
u64 crc;
62+
} desc;
63+
int err;
64+
65+
if (static_branch_unlikely(&crc64_rocksoft_fallback))
66+
return crc64_rocksoft_generic(crc, buffer, len);
67+
68+
rcu_read_lock();
69+
desc.shash.tfm = rcu_dereference(crc64_rocksoft_tfm);
70+
desc.crc = crc;
71+
err = crypto_shash_update(&desc.shash, buffer, len);
72+
rcu_read_unlock();
73+
74+
BUG_ON(err);
75+
76+
return desc.crc;
77+
}
78+
EXPORT_SYMBOL_GPL(crc64_rocksoft_update);
79+
80+
u64 crc64_rocksoft(const unsigned char *buffer, size_t len)
81+
{
82+
return crc64_rocksoft_update(0, buffer, len);
83+
}
84+
EXPORT_SYMBOL_GPL(crc64_rocksoft);
85+
86+
static int __init crc64_rocksoft_mod_init(void)
87+
{
88+
INIT_WORK(&crc64_rocksoft_rehash_work, crc64_rocksoft_rehash);
89+
crypto_register_notifier(&crc64_rocksoft_nb);
90+
crc64_rocksoft_rehash(&crc64_rocksoft_rehash_work);
91+
return 0;
92+
}
93+
94+
static void __exit crc64_rocksoft_mod_fini(void)
95+
{
96+
crypto_unregister_notifier(&crc64_rocksoft_nb);
97+
cancel_work_sync(&crc64_rocksoft_rehash_work);
98+
crypto_free_shash(rcu_dereference_protected(crc64_rocksoft_tfm, 1));
99+
}
100+
101+
module_init(crc64_rocksoft_mod_init);
102+
module_exit(crc64_rocksoft_mod_fini);
103+
104+
static int crc64_rocksoft_transform_show(char *buffer, const struct kernel_param *kp)
105+
{
106+
struct crypto_shash *tfm;
107+
int len;
108+
109+
if (static_branch_unlikely(&crc64_rocksoft_fallback))
110+
return sprintf(buffer, "fallback\n");
111+
112+
rcu_read_lock();
113+
tfm = rcu_dereference(crc64_rocksoft_tfm);
114+
len = snprintf(buffer, PAGE_SIZE, "%s\n",
115+
crypto_shash_driver_name(tfm));
116+
rcu_read_unlock();
117+
118+
return len;
119+
}
120+
121+
module_param_call(transform, NULL, crc64_rocksoft_transform_show, NULL, 0444);
122+
123+
MODULE_AUTHOR("Keith Busch <[email protected]>");
124+
MODULE_DESCRIPTION("Rocksoft model CRC64 calculation (library API)");
125+
MODULE_LICENSE("GPL");
126+
MODULE_SOFTDEP("pre: crc64");

0 commit comments

Comments
 (0)