brintos

brintos / linux-shallow public Read only

0
0
Text · 3.2 KiB · fc9ae0d Raw
127 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2 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 13static struct crypto_shash __rcu *crc64_rocksoft_tfm;14static DEFINE_STATIC_KEY_TRUE(crc64_rocksoft_fallback);15static DEFINE_MUTEX(crc64_rocksoft_mutex);16static struct work_struct crc64_rocksoft_rehash_work;17 18static 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 30static 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 53static struct notifier_block crc64_rocksoft_nb = {54	.notifier_call = crc64_rocksoft_notify,55};56 57u64 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}78EXPORT_SYMBOL_GPL(crc64_rocksoft_update);79 80u64 crc64_rocksoft(const unsigned char *buffer, size_t len)81{82	return crc64_rocksoft_update(0, buffer, len);83}84EXPORT_SYMBOL_GPL(crc64_rocksoft);85 86static 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 94static 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 101module_init(crc64_rocksoft_mod_init);102module_exit(crc64_rocksoft_mod_fini);103 104static 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 121module_param_call(transform, NULL, crc64_rocksoft_transform_show, NULL, 0444);122 123MODULE_AUTHOR("Keith Busch <kbusch@kernel.org>");124MODULE_DESCRIPTION("Rocksoft model CRC64 calculation (library API)");125MODULE_LICENSE("GPL");126MODULE_SOFTDEP("pre: crc64");127