40b0b3f8fb2d8 (Thomas Gleixner 2019-06-03 07:44:46 +0200 1) // SPDX-License-Identifier: GPL-2.0-only
f11f594edba7f (Martin K. Petersen 2008-06-25 11:22:42 -0400 2) /*
f11f594edba7f (Martin K. Petersen 2008-06-25 11:22:42 -0400 3) * T10 Data Integrity Field CRC16 calculation
f11f594edba7f (Martin K. Petersen 2008-06-25 11:22:42 -0400 4) *
f11f594edba7f (Martin K. Petersen 2008-06-25 11:22:42 -0400 5) * Copyright (c) 2007 Oracle Corporation. All rights reserved.
f11f594edba7f (Martin K. Petersen 2008-06-25 11:22:42 -0400 6) * Written by Martin K. Petersen <martin.petersen@oracle.com>
f11f594edba7f (Martin K. Petersen 2008-06-25 11:22:42 -0400 7) */
f11f594edba7f (Martin K. Petersen 2008-06-25 11:22:42 -0400 8)
f11f594edba7f (Martin K. Petersen 2008-06-25 11:22:42 -0400 9) #include <linux/types.h>
f11f594edba7f (Martin K. Petersen 2008-06-25 11:22:42 -0400 10) #include <linux/module.h>
f11f594edba7f (Martin K. Petersen 2008-06-25 11:22:42 -0400 11) #include <linux/crc-t10dif.h>
68411521cc605 (Herbert Xu 2013-09-07 12:56:26 +1000 12) #include <linux/err.h>
68411521cc605 (Herbert Xu 2013-09-07 12:56:26 +1000 13) #include <linux/init.h>
68411521cc605 (Herbert Xu 2013-09-07 12:56:26 +1000 14) #include <crypto/hash.h>
b76377543b738 (Martin K. Petersen 2018-08-30 11:00:15 -0400 15) #include <crypto/algapi.h>
26052f9b9bb8d (Herbert Xu 2013-09-12 15:31:34 +1000 16) #include <linux/static_key.h>
b76377543b738 (Martin K. Petersen 2018-08-30 11:00:15 -0400 17) #include <linux/notifier.h>
f11f594edba7f (Martin K. Petersen 2008-06-25 11:22:42 -0400 18)
b76377543b738 (Martin K. Petersen 2018-08-30 11:00:15 -0400 19) static struct crypto_shash __rcu *crct10dif_tfm;
be924e0aaa315 (Eric Biggers 2020-06-09 23:39:42 -0700 20) static DEFINE_STATIC_KEY_TRUE(crct10dif_fallback);
a7e7edfea23fa (kbuild test robot 2018-09-05 01:52:44 +0800 21) static DEFINE_MUTEX(crc_t10dif_mutex);
3906f640224db (Herbert Xu 2020-06-05 16:59:18 +1000 22) static struct work_struct crct10dif_rehash_work;
b76377543b738 (Martin K. Petersen 2018-08-30 11:00:15 -0400 23)
3906f640224db (Herbert Xu 2020-06-05 16:59:18 +1000 24) static int crc_t10dif_notify(struct notifier_block *self, unsigned long val, void *data)
b76377543b738 (Martin K. Petersen 2018-08-30 11:00:15 -0400 25) {
b76377543b738 (Martin K. Petersen 2018-08-30 11:00:15 -0400 26) struct crypto_alg *alg = data;
b76377543b738 (Martin K. Petersen 2018-08-30 11:00:15 -0400 27)
b76377543b738 (Martin K. Petersen 2018-08-30 11:00:15 -0400 28) if (val != CRYPTO_MSG_ALG_LOADED ||
29195232fa2f7 (Eric Biggers 2020-06-09 23:39:43 -0700 29) strcmp(alg->cra_name, CRC_T10DIF_STRING))
29195232fa2f7 (Eric Biggers 2020-06-09 23:39:43 -0700 30) return NOTIFY_DONE;
b76377543b738 (Martin K. Petersen 2018-08-30 11:00:15 -0400 31)
3906f640224db (Herbert Xu 2020-06-05 16:59:18 +1000 32) schedule_work(&crct10dif_rehash_work);
29195232fa2f7 (Eric Biggers 2020-06-09 23:39:43 -0700 33) return NOTIFY_OK;
3906f640224db (Herbert Xu 2020-06-05 16:59:18 +1000 34) }
3906f640224db (Herbert Xu 2020-06-05 16:59:18 +1000 35)
3906f640224db (Herbert Xu 2020-06-05 16:59:18 +1000 36) static void crc_t10dif_rehash(struct work_struct *work)
3906f640224db (Herbert Xu 2020-06-05 16:59:18 +1000 37) {
3906f640224db (Herbert Xu 2020-06-05 16:59:18 +1000 38) struct crypto_shash *new, *old;
3906f640224db (Herbert Xu 2020-06-05 16:59:18 +1000 39)
b76377543b738 (Martin K. Petersen 2018-08-30 11:00:15 -0400 40) mutex_lock(&crc_t10dif_mutex);
b76377543b738 (Martin K. Petersen 2018-08-30 11:00:15 -0400 41) old = rcu_dereference_protected(crct10dif_tfm,
b76377543b738 (Martin K. Petersen 2018-08-30 11:00:15 -0400 42) lockdep_is_held(&crc_t10dif_mutex));
29195232fa2f7 (Eric Biggers 2020-06-09 23:39:43 -0700 43) new = crypto_alloc_shash(CRC_T10DIF_STRING, 0, 0);
b76377543b738 (Martin K. Petersen 2018-08-30 11:00:15 -0400 44) if (IS_ERR(new)) {
b76377543b738 (Martin K. Petersen 2018-08-30 11:00:15 -0400 45) mutex_unlock(&crc_t10dif_mutex);
3906f640224db (Herbert Xu 2020-06-05 16:59:18 +1000 46) return;
b76377543b738 (Martin K. Petersen 2018-08-30 11:00:15 -0400 47) }
b76377543b738 (Martin K. Petersen 2018-08-30 11:00:15 -0400 48) rcu_assign_pointer(crct10dif_tfm, new);
b76377543b738 (Martin K. Petersen 2018-08-30 11:00:15 -0400 49) mutex_unlock(&crc_t10dif_mutex);
b76377543b738 (Martin K. Petersen 2018-08-30 11:00:15 -0400 50)
be924e0aaa315 (Eric Biggers 2020-06-09 23:39:42 -0700 51) if (old) {
be924e0aaa315 (Eric Biggers 2020-06-09 23:39:42 -0700 52) synchronize_rcu();
be924e0aaa315 (Eric Biggers 2020-06-09 23:39:42 -0700 53) crypto_free_shash(old);
be924e0aaa315 (Eric Biggers 2020-06-09 23:39:42 -0700 54) } else {
be924e0aaa315 (Eric Biggers 2020-06-09 23:39:42 -0700 55) static_branch_disable(&crct10dif_fallback);
be924e0aaa315 (Eric Biggers 2020-06-09 23:39:42 -0700 56) }
b76377543b738 (Martin K. Petersen 2018-08-30 11:00:15 -0400 57) }
b76377543b738 (Martin K. Petersen 2018-08-30 11:00:15 -0400 58)
b76377543b738 (Martin K. Petersen 2018-08-30 11:00:15 -0400 59) static struct notifier_block crc_t10dif_nb = {
3906f640224db (Herbert Xu 2020-06-05 16:59:18 +1000 60) .notifier_call = crc_t10dif_notify,
b76377543b738 (Martin K. Petersen 2018-08-30 11:00:15 -0400 61) };
f11f594edba7f (Martin K. Petersen 2008-06-25 11:22:42 -0400 62)
10081fb532a2a (Akinobu Mita 2015-05-01 15:23:50 +0900 63) __u16 crc_t10dif_update(__u16 crc, const unsigned char *buffer, size_t len)
f11f594edba7f (Martin K. Petersen 2008-06-25 11:22:42 -0400 64) {
68411521cc605 (Herbert Xu 2013-09-07 12:56:26 +1000 65) struct {
68411521cc605 (Herbert Xu 2013-09-07 12:56:26 +1000 66) struct shash_desc shash;
29195232fa2f7 (Eric Biggers 2020-06-09 23:39:43 -0700 67) __u16 crc;
68411521cc605 (Herbert Xu 2013-09-07 12:56:26 +1000 68) } desc;
68411521cc605 (Herbert Xu 2013-09-07 12:56:26 +1000 69) int err;
68411521cc605 (Herbert Xu 2013-09-07 12:56:26 +1000 70)
be924e0aaa315 (Eric Biggers 2020-06-09 23:39:42 -0700 71) if (static_branch_unlikely(&crct10dif_fallback))
10081fb532a2a (Akinobu Mita 2015-05-01 15:23:50 +0900 72) return crc_t10dif_generic(crc, buffer, len);
26052f9b9bb8d (Herbert Xu 2013-09-12 15:31:34 +1000 73)
b76377543b738 (Martin K. Petersen 2018-08-30 11:00:15 -0400 74) rcu_read_lock();
b76377543b738 (Martin K. Petersen 2018-08-30 11:00:15 -0400 75) desc.shash.tfm = rcu_dereference(crct10dif_tfm);
29195232fa2f7 (Eric Biggers 2020-06-09 23:39:43 -0700 76) desc.crc = crc;
68411521cc605 (Herbert Xu 2013-09-07 12:56:26 +1000 77) err = crypto_shash_update(&desc.shash, buffer, len);
b76377543b738 (Martin K. Petersen 2018-08-30 11:00:15 -0400 78) rcu_read_unlock();
b76377543b738 (Martin K. Petersen 2018-08-30 11:00:15 -0400 79)
68411521cc605 (Herbert Xu 2013-09-07 12:56:26 +1000 80) BUG_ON(err);
f11f594edba7f (Martin K. Petersen 2008-06-25 11:22:42 -0400 81)
29195232fa2f7 (Eric Biggers 2020-06-09 23:39:43 -0700 82) return desc.crc;
f11f594edba7f (Martin K. Petersen 2008-06-25 11:22:42 -0400 83) }
10081fb532a2a (Akinobu Mita 2015-05-01 15:23:50 +0900 84) EXPORT_SYMBOL(crc_t10dif_update);
10081fb532a2a (Akinobu Mita 2015-05-01 15:23:50 +0900 85)
10081fb532a2a (Akinobu Mita 2015-05-01 15:23:50 +0900 86) __u16 crc_t10dif(const unsigned char *buffer, size_t len)
10081fb532a2a (Akinobu Mita 2015-05-01 15:23:50 +0900 87) {
10081fb532a2a (Akinobu Mita 2015-05-01 15:23:50 +0900 88) return crc_t10dif_update(0, buffer, len);
10081fb532a2a (Akinobu Mita 2015-05-01 15:23:50 +0900 89) }
f11f594edba7f (Martin K. Petersen 2008-06-25 11:22:42 -0400 90) EXPORT_SYMBOL(crc_t10dif);
f11f594edba7f (Martin K. Petersen 2008-06-25 11:22:42 -0400 91)
68411521cc605 (Herbert Xu 2013-09-07 12:56:26 +1000 92) static int __init crc_t10dif_mod_init(void)
68411521cc605 (Herbert Xu 2013-09-07 12:56:26 +1000 93) {
3906f640224db (Herbert Xu 2020-06-05 16:59:18 +1000 94) INIT_WORK(&crct10dif_rehash_work, crc_t10dif_rehash);
b76377543b738 (Martin K. Petersen 2018-08-30 11:00:15 -0400 95) crypto_register_notifier(&crc_t10dif_nb);
be924e0aaa315 (Eric Biggers 2020-06-09 23:39:42 -0700 96) crc_t10dif_rehash(&crct10dif_rehash_work);
26052f9b9bb8d (Herbert Xu 2013-09-12 15:31:34 +1000 97) return 0;
68411521cc605 (Herbert Xu 2013-09-07 12:56:26 +1000 98) }
68411521cc605 (Herbert Xu 2013-09-07 12:56:26 +1000 99)
68411521cc605 (Herbert Xu 2013-09-07 12:56:26 +1000 100) static void __exit crc_t10dif_mod_fini(void)
68411521cc605 (Herbert Xu 2013-09-07 12:56:26 +1000 101) {
b76377543b738 (Martin K. Petersen 2018-08-30 11:00:15 -0400 102) crypto_unregister_notifier(&crc_t10dif_nb);
3906f640224db (Herbert Xu 2020-06-05 16:59:18 +1000 103) cancel_work_sync(&crct10dif_rehash_work);
3906f640224db (Herbert Xu 2020-06-05 16:59:18 +1000 104) crypto_free_shash(rcu_dereference_protected(crct10dif_tfm, 1));
68411521cc605 (Herbert Xu 2013-09-07 12:56:26 +1000 105) }
68411521cc605 (Herbert Xu 2013-09-07 12:56:26 +1000 106)
68411521cc605 (Herbert Xu 2013-09-07 12:56:26 +1000 107) module_init(crc_t10dif_mod_init);
68411521cc605 (Herbert Xu 2013-09-07 12:56:26 +1000 108) module_exit(crc_t10dif_mod_fini);
68411521cc605 (Herbert Xu 2013-09-07 12:56:26 +1000 109)
11dcb1037f40a (Martin K. Petersen 2018-08-30 11:00:16 -0400 110) static int crc_t10dif_transform_show(char *buffer, const struct kernel_param *kp)
11dcb1037f40a (Martin K. Petersen 2018-08-30 11:00:16 -0400 111) {
3906f640224db (Herbert Xu 2020-06-05 16:59:18 +1000 112) struct crypto_shash *tfm;
3906f640224db (Herbert Xu 2020-06-05 16:59:18 +1000 113) int len;
3906f640224db (Herbert Xu 2020-06-05 16:59:18 +1000 114)
be924e0aaa315 (Eric Biggers 2020-06-09 23:39:42 -0700 115) if (static_branch_unlikely(&crct10dif_fallback))
11dcb1037f40a (Martin K. Petersen 2018-08-30 11:00:16 -0400 116) return sprintf(buffer, "fallback\n");
11dcb1037f40a (Martin K. Petersen 2018-08-30 11:00:16 -0400 117)
3906f640224db (Herbert Xu 2020-06-05 16:59:18 +1000 118) rcu_read_lock();
3906f640224db (Herbert Xu 2020-06-05 16:59:18 +1000 119) tfm = rcu_dereference(crct10dif_tfm);
29195232fa2f7 (Eric Biggers 2020-06-09 23:39:43 -0700 120) len = snprintf(buffer, PAGE_SIZE, "%s\n",
29195232fa2f7 (Eric Biggers 2020-06-09 23:39:43 -0700 121) crypto_shash_driver_name(tfm));
3906f640224db (Herbert Xu 2020-06-05 16:59:18 +1000 122) rcu_read_unlock();
3906f640224db (Herbert Xu 2020-06-05 16:59:18 +1000 123)
3906f640224db (Herbert Xu 2020-06-05 16:59:18 +1000 124) return len;
11dcb1037f40a (Martin K. Petersen 2018-08-30 11:00:16 -0400 125) }
11dcb1037f40a (Martin K. Petersen 2018-08-30 11:00:16 -0400 126)
29195232fa2f7 (Eric Biggers 2020-06-09 23:39:43 -0700 127) module_param_call(transform, NULL, crc_t10dif_transform_show, NULL, 0444);
11dcb1037f40a (Martin K. Petersen 2018-08-30 11:00:16 -0400 128)
29195232fa2f7 (Eric Biggers 2020-06-09 23:39:43 -0700 129) MODULE_DESCRIPTION("T10 DIF CRC calculation (library API)");
f11f594edba7f (Martin K. Petersen 2008-06-25 11:22:42 -0400 130) MODULE_LICENSE("GPL");
68411521cc605 (Herbert Xu 2013-09-07 12:56:26 +1000 131) MODULE_SOFTDEP("pre: crct10dif");