forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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]>
- Loading branch information
1 parent
cbc0a40
commit f3813f4
Showing
9 changed files
with
258 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
// SPDX-License-Identifier: GPL-2.0-only | ||
|
||
#include <linux/crc64.h> | ||
#include <linux/module.h> | ||
#include <crypto/internal/hash.h> | ||
#include <asm/unaligned.h> | ||
|
||
static int chksum_init(struct shash_desc *desc) | ||
{ | ||
u64 *crc = shash_desc_ctx(desc); | ||
|
||
*crc = 0; | ||
|
||
return 0; | ||
} | ||
|
||
static int chksum_update(struct shash_desc *desc, const u8 *data, | ||
unsigned int length) | ||
{ | ||
u64 *crc = shash_desc_ctx(desc); | ||
|
||
*crc = crc64_rocksoft_generic(*crc, data, length); | ||
|
||
return 0; | ||
} | ||
|
||
static int chksum_final(struct shash_desc *desc, u8 *out) | ||
{ | ||
u64 *crc = shash_desc_ctx(desc); | ||
|
||
put_unaligned_le64(*crc, out); | ||
return 0; | ||
} | ||
|
||
static int __chksum_finup(u64 crc, const u8 *data, unsigned int len, u8 *out) | ||
{ | ||
crc = crc64_rocksoft_generic(crc, data, len); | ||
put_unaligned_le64(crc, out); | ||
return 0; | ||
} | ||
|
||
static int chksum_finup(struct shash_desc *desc, const u8 *data, | ||
unsigned int len, u8 *out) | ||
{ | ||
u64 *crc = shash_desc_ctx(desc); | ||
|
||
return __chksum_finup(*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 = sizeof(u64), | ||
.init = chksum_init, | ||
.update = chksum_update, | ||
.final = chksum_final, | ||
.finup = chksum_finup, | ||
.digest = chksum_digest, | ||
.descsize = sizeof(u64), | ||
.base = { | ||
.cra_name = CRC64_ROCKSOFT_STRING, | ||
.cra_driver_name = "crc64-rocksoft-generic", | ||
.cra_priority = 200, | ||
.cra_blocksize = 1, | ||
.cra_module = THIS_MODULE, | ||
} | ||
}; | ||
|
||
static int __init crc64_rocksoft_init(void) | ||
{ | ||
return crypto_register_shash(&alg); | ||
} | ||
|
||
static void __exit crc64_rocksoft_exit(void) | ||
{ | ||
crypto_unregister_shash(&alg); | ||
} | ||
|
||
module_init(crc64_rocksoft_init); | ||
module_exit(crc64_rocksoft_exit); | ||
|
||
MODULE_LICENSE("GPL"); | ||
MODULE_DESCRIPTION("Rocksoft model CRC64 calculation."); | ||
MODULE_ALIAS_CRYPTO("crc64-rocksoft"); | ||
MODULE_ALIAS_CRYPTO("crc64-rocksoft-generic"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
// SPDX-License-Identifier: GPL-2.0-only | ||
|
||
#include <linux/types.h> | ||
#include <linux/module.h> | ||
#include <linux/crc64.h> | ||
#include <linux/err.h> | ||
#include <linux/init.h> | ||
#include <crypto/hash.h> | ||
#include <crypto/algapi.h> | ||
#include <linux/static_key.h> | ||
#include <linux/notifier.h> | ||
|
||
static struct crypto_shash __rcu *crc64_rocksoft_tfm; | ||
static DEFINE_STATIC_KEY_TRUE(crc64_rocksoft_fallback); | ||
static DEFINE_MUTEX(crc64_rocksoft_mutex); | ||
static struct work_struct crc64_rocksoft_rehash_work; | ||
|
||
static int crc64_rocksoft_notify(struct notifier_block *self, unsigned long val, void *data) | ||
{ | ||
struct crypto_alg *alg = data; | ||
|
||
if (val != CRYPTO_MSG_ALG_LOADED || | ||
strcmp(alg->cra_name, CRC64_ROCKSOFT_STRING)) | ||
return NOTIFY_DONE; | ||
|
||
schedule_work(&crc64_rocksoft_rehash_work); | ||
return NOTIFY_OK; | ||
} | ||
|
||
static void crc64_rocksoft_rehash(struct work_struct *work) | ||
{ | ||
struct crypto_shash *new, *old; | ||
|
||
mutex_lock(&crc64_rocksoft_mutex); | ||
old = rcu_dereference_protected(crc64_rocksoft_tfm, | ||
lockdep_is_held(&crc64_rocksoft_mutex)); | ||
new = crypto_alloc_shash(CRC64_ROCKSOFT_STRING, 0, 0); | ||
if (IS_ERR(new)) { | ||
mutex_unlock(&crc64_rocksoft_mutex); | ||
return; | ||
} | ||
rcu_assign_pointer(crc64_rocksoft_tfm, new); | ||
mutex_unlock(&crc64_rocksoft_mutex); | ||
|
||
if (old) { | ||
synchronize_rcu(); | ||
crypto_free_shash(old); | ||
} else { | ||
static_branch_disable(&crc64_rocksoft_fallback); | ||
} | ||
} | ||
|
||
static struct notifier_block crc64_rocksoft_nb = { | ||
.notifier_call = crc64_rocksoft_notify, | ||
}; | ||
|
||
u64 crc64_rocksoft_update(u64 crc, const unsigned char *buffer, size_t len) | ||
{ | ||
struct { | ||
struct shash_desc shash; | ||
u64 crc; | ||
} desc; | ||
int err; | ||
|
||
if (static_branch_unlikely(&crc64_rocksoft_fallback)) | ||
return crc64_rocksoft_generic(crc, buffer, len); | ||
|
||
rcu_read_lock(); | ||
desc.shash.tfm = rcu_dereference(crc64_rocksoft_tfm); | ||
desc.crc = crc; | ||
err = crypto_shash_update(&desc.shash, buffer, len); | ||
rcu_read_unlock(); | ||
|
||
BUG_ON(err); | ||
|
||
return desc.crc; | ||
} | ||
EXPORT_SYMBOL_GPL(crc64_rocksoft_update); | ||
|
||
u64 crc64_rocksoft(const unsigned char *buffer, size_t len) | ||
{ | ||
return crc64_rocksoft_update(0, buffer, len); | ||
} | ||
EXPORT_SYMBOL_GPL(crc64_rocksoft); | ||
|
||
static int __init crc64_rocksoft_mod_init(void) | ||
{ | ||
INIT_WORK(&crc64_rocksoft_rehash_work, crc64_rocksoft_rehash); | ||
crypto_register_notifier(&crc64_rocksoft_nb); | ||
crc64_rocksoft_rehash(&crc64_rocksoft_rehash_work); | ||
return 0; | ||
} | ||
|
||
static void __exit crc64_rocksoft_mod_fini(void) | ||
{ | ||
crypto_unregister_notifier(&crc64_rocksoft_nb); | ||
cancel_work_sync(&crc64_rocksoft_rehash_work); | ||
crypto_free_shash(rcu_dereference_protected(crc64_rocksoft_tfm, 1)); | ||
} | ||
|
||
module_init(crc64_rocksoft_mod_init); | ||
module_exit(crc64_rocksoft_mod_fini); | ||
|
||
static int crc64_rocksoft_transform_show(char *buffer, const struct kernel_param *kp) | ||
{ | ||
struct crypto_shash *tfm; | ||
int len; | ||
|
||
if (static_branch_unlikely(&crc64_rocksoft_fallback)) | ||
return sprintf(buffer, "fallback\n"); | ||
|
||
rcu_read_lock(); | ||
tfm = rcu_dereference(crc64_rocksoft_tfm); | ||
len = snprintf(buffer, PAGE_SIZE, "%s\n", | ||
crypto_shash_driver_name(tfm)); | ||
rcu_read_unlock(); | ||
|
||
return len; | ||
} | ||
|
||
module_param_call(transform, NULL, crc64_rocksoft_transform_show, NULL, 0444); | ||
|
||
MODULE_AUTHOR("Keith Busch <[email protected]>"); | ||
MODULE_DESCRIPTION("Rocksoft model CRC64 calculation (library API)"); | ||
MODULE_LICENSE("GPL"); | ||
MODULE_SOFTDEP("pre: crc64"); |