Blame view

lib/crc-t10dif.c 2.93 KB
40b0b3f8f   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
f11f594ed   Martin K. Petersen   [SCSI] lib: Add s...
2
3
4
5
6
  /*
   * T10 Data Integrity Field CRC16 calculation
   *
   * Copyright (c) 2007 Oracle Corporation.  All rights reserved.
   * Written by Martin K. Petersen <martin.petersen@oracle.com>
f11f594ed   Martin K. Petersen   [SCSI] lib: Add s...
7
8
9
10
11
   */
  
  #include <linux/types.h>
  #include <linux/module.h>
  #include <linux/crc-t10dif.h>
68411521c   Herbert Xu   Reinstate "crypto...
12
13
14
  #include <linux/err.h>
  #include <linux/init.h>
  #include <crypto/hash.h>
b76377543   Martin K. Petersen   crc-t10dif: Pick ...
15
  #include <crypto/algapi.h>
26052f9b9   Herbert Xu   crypto: crct10dif...
16
  #include <linux/static_key.h>
b76377543   Martin K. Petersen   crc-t10dif: Pick ...
17
  #include <linux/notifier.h>
f11f594ed   Martin K. Petersen   [SCSI] lib: Add s...
18

b76377543   Martin K. Petersen   crc-t10dif: Pick ...
19
  static struct crypto_shash __rcu *crct10dif_tfm;
26052f9b9   Herbert Xu   crypto: crct10dif...
20
  static struct static_key crct10dif_fallback __read_mostly;
a7e7edfea   kbuild test robot   crc-t10dif: crc_t...
21
  static DEFINE_MUTEX(crc_t10dif_mutex);
b76377543   Martin K. Petersen   crc-t10dif: Pick ...
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
  
  static int crc_t10dif_rehash(struct notifier_block *self, unsigned long val, void *data)
  {
  	struct crypto_alg *alg = data;
  	struct crypto_shash *new, *old;
  
  	if (val != CRYPTO_MSG_ALG_LOADED ||
  	    static_key_false(&crct10dif_fallback) ||
  	    strncmp(alg->cra_name, CRC_T10DIF_STRING, strlen(CRC_T10DIF_STRING)))
  		return 0;
  
  	mutex_lock(&crc_t10dif_mutex);
  	old = rcu_dereference_protected(crct10dif_tfm,
  					lockdep_is_held(&crc_t10dif_mutex));
  	if (!old) {
  		mutex_unlock(&crc_t10dif_mutex);
  		return 0;
  	}
  	new = crypto_alloc_shash("crct10dif", 0, 0);
  	if (IS_ERR(new)) {
  		mutex_unlock(&crc_t10dif_mutex);
  		return 0;
  	}
  	rcu_assign_pointer(crct10dif_tfm, new);
  	mutex_unlock(&crc_t10dif_mutex);
  
  	synchronize_rcu();
  	crypto_free_shash(old);
  	return 0;
  }
  
  static struct notifier_block crc_t10dif_nb = {
  	.notifier_call = crc_t10dif_rehash,
  };
f11f594ed   Martin K. Petersen   [SCSI] lib: Add s...
56

10081fb53   Akinobu Mita   lib: introduce cr...
57
  __u16 crc_t10dif_update(__u16 crc, const unsigned char *buffer, size_t len)
f11f594ed   Martin K. Petersen   [SCSI] lib: Add s...
58
  {
68411521c   Herbert Xu   Reinstate "crypto...
59
60
61
62
63
  	struct {
  		struct shash_desc shash;
  		char ctx[2];
  	} desc;
  	int err;
26052f9b9   Herbert Xu   crypto: crct10dif...
64
  	if (static_key_false(&crct10dif_fallback))
10081fb53   Akinobu Mita   lib: introduce cr...
65
  		return crc_t10dif_generic(crc, buffer, len);
26052f9b9   Herbert Xu   crypto: crct10dif...
66

b76377543   Martin K. Petersen   crc-t10dif: Pick ...
67
68
  	rcu_read_lock();
  	desc.shash.tfm = rcu_dereference(crct10dif_tfm);
10081fb53   Akinobu Mita   lib: introduce cr...
69
  	*(__u16 *)desc.ctx = crc;
f11f594ed   Martin K. Petersen   [SCSI] lib: Add s...
70

68411521c   Herbert Xu   Reinstate "crypto...
71
  	err = crypto_shash_update(&desc.shash, buffer, len);
b76377543   Martin K. Petersen   crc-t10dif: Pick ...
72
  	rcu_read_unlock();
68411521c   Herbert Xu   Reinstate "crypto...
73
  	BUG_ON(err);
f11f594ed   Martin K. Petersen   [SCSI] lib: Add s...
74

68411521c   Herbert Xu   Reinstate "crypto...
75
  	return *(__u16 *)desc.ctx;
f11f594ed   Martin K. Petersen   [SCSI] lib: Add s...
76
  }
10081fb53   Akinobu Mita   lib: introduce cr...
77
78
79
80
81
82
  EXPORT_SYMBOL(crc_t10dif_update);
  
  __u16 crc_t10dif(const unsigned char *buffer, size_t len)
  {
  	return crc_t10dif_update(0, buffer, len);
  }
f11f594ed   Martin K. Petersen   [SCSI] lib: Add s...
83
  EXPORT_SYMBOL(crc_t10dif);
68411521c   Herbert Xu   Reinstate "crypto...
84
85
  static int __init crc_t10dif_mod_init(void)
  {
b76377543   Martin K. Petersen   crc-t10dif: Pick ...
86
  	crypto_register_notifier(&crc_t10dif_nb);
68411521c   Herbert Xu   Reinstate "crypto...
87
  	crct10dif_tfm = crypto_alloc_shash("crct10dif", 0, 0);
26052f9b9   Herbert Xu   crypto: crct10dif...
88
89
90
91
92
  	if (IS_ERR(crct10dif_tfm)) {
  		static_key_slow_inc(&crct10dif_fallback);
  		crct10dif_tfm = NULL;
  	}
  	return 0;
68411521c   Herbert Xu   Reinstate "crypto...
93
94
95
96
  }
  
  static void __exit crc_t10dif_mod_fini(void)
  {
b76377543   Martin K. Petersen   crc-t10dif: Pick ...
97
  	crypto_unregister_notifier(&crc_t10dif_nb);
68411521c   Herbert Xu   Reinstate "crypto...
98
99
100
101
102
  	crypto_free_shash(crct10dif_tfm);
  }
  
  module_init(crc_t10dif_mod_init);
  module_exit(crc_t10dif_mod_fini);
11dcb1037   Martin K. Petersen   crc-t10dif: Allow...
103
104
105
106
107
108
109
110
111
112
113
114
  static int crc_t10dif_transform_show(char *buffer, const struct kernel_param *kp)
  {
  	if (static_key_false(&crct10dif_fallback))
  		return sprintf(buffer, "fallback
  ");
  
  	return sprintf(buffer, "%s
  ",
  		crypto_tfm_alg_driver_name(crypto_shash_tfm(crct10dif_tfm)));
  }
  
  module_param_call(transform, NULL, crc_t10dif_transform_show, NULL, 0644);
f11f594ed   Martin K. Petersen   [SCSI] lib: Add s...
115
116
  MODULE_DESCRIPTION("T10 DIF CRC calculation");
  MODULE_LICENSE("GPL");
68411521c   Herbert Xu   Reinstate "crypto...
117
  MODULE_SOFTDEP("pre: crct10dif");