Blame view

block/keyslot-manager.c 14.5 KB
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
1
2
  // SPDX-License-Identifier: GPL-2.0
  /*
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
3
4
5
6
7
8
9
10
11
12
   * Copyright 2019 Google LLC
   */
  
  /**
   * DOC: The Keyslot Manager
   *
   * Many devices with inline encryption support have a limited number of "slots"
   * into which encryption contexts may be programmed, and requests can be tagged
   * with a slot number to specify the key to use for en/decryption.
   *
c2b86b727   Satya Tangirala   FROMLIST: Update ...
13
   * As the number of slots is limited, and programming keys is expensive on
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
14
15
16
17
18
19
20
21
22
23
24
   * many inline encryption hardware, we don't want to program the same key into
   * multiple slots - if multiple requests are using the same key, we want to
   * program just one slot with that key and use that slot for all requests.
   *
   * The keyslot manager manages these keyslots appropriately, and also acts as
   * an abstraction between the inline encryption hardware and the upper layers.
   *
   * Lower layer devices will set up a keyslot manager in their request queue
   * and tell it how to perform device specific operations like programming/
   * evicting keys from keyslots.
   *
c2b86b727   Satya Tangirala   FROMLIST: Update ...
25
   * Upper layers will call blk_ksm_get_slot_for_key() to program a
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
26
27
   * key into some slot in the inline encryption hardware.
   */
c2b86b727   Satya Tangirala   FROMLIST: Update ...
28
29
  
  #define pr_fmt(fmt) "blk-crypto: " fmt
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
30
31
32
  #include <linux/keyslot-manager.h>
  #include <linux/atomic.h>
  #include <linux/mutex.h>
a59152c40   Eric Biggers   ANDROID: ufs, blo...
33
  #include <linux/pm_runtime.h>
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
34
35
  #include <linux/wait.h>
  #include <linux/blkdev.h>
c2b86b727   Satya Tangirala   FROMLIST: Update ...
36
  struct blk_ksm_keyslot {
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
37
38
  	atomic_t slot_refs;
  	struct list_head idle_slot_node;
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
39
  	struct hlist_node hash_node;
c2b86b727   Satya Tangirala   FROMLIST: Update ...
40
41
  	const struct blk_crypto_key *key;
  	struct blk_keyslot_manager *ksm;
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
42
  };
c2b86b727   Satya Tangirala   FROMLIST: Update ...
43
44
  static inline void blk_ksm_hw_enter(struct blk_keyslot_manager *ksm)
  {
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
45
  	/*
c2b86b727   Satya Tangirala   FROMLIST: Update ...
46
47
48
  	 * Calling into the driver requires ksm->lock held and the device
  	 * resumed.  But we must resume the device first, since that can acquire
  	 * and release ksm->lock via blk_ksm_reprogram_all_keys().
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
49
  	 */
a59152c40   Eric Biggers   ANDROID: ufs, blo...
50
51
  	if (ksm->dev)
  		pm_runtime_get_sync(ksm->dev);
c2b86b727   Satya Tangirala   FROMLIST: Update ...
52
  	down_write(&ksm->lock);
a59152c40   Eric Biggers   ANDROID: ufs, blo...
53
  }
c2b86b727   Satya Tangirala   FROMLIST: Update ...
54
  static inline void blk_ksm_hw_exit(struct blk_keyslot_manager *ksm)
a59152c40   Eric Biggers   ANDROID: ufs, blo...
55
  {
c2b86b727   Satya Tangirala   FROMLIST: Update ...
56
  	up_write(&ksm->lock);
a59152c40   Eric Biggers   ANDROID: ufs, blo...
57
58
59
  	if (ksm->dev)
  		pm_runtime_put_sync(ksm->dev);
  }
a59152c40   Eric Biggers   ANDROID: ufs, blo...
60

c2b86b727   Satya Tangirala   FROMLIST: Update ...
61
  static inline bool blk_ksm_is_passthrough(struct blk_keyslot_manager *ksm)
a59152c40   Eric Biggers   ANDROID: ufs, blo...
62
  {
c2b86b727   Satya Tangirala   FROMLIST: Update ...
63
  	return ksm->num_slots == 0;
a59152c40   Eric Biggers   ANDROID: ufs, blo...
64
  }
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
65
  /**
c2b86b727   Satya Tangirala   FROMLIST: Update ...
66
67
   * blk_ksm_init() - Initialize a keyslot manager
   * @ksm: The keyslot_manager to initialize.
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
68
   * @num_slots: The number of key slots to manage.
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
69
   *
c2b86b727   Satya Tangirala   FROMLIST: Update ...
70
71
   * Allocate memory for keyslots and initialize a keyslot manager. Called by
   * e.g. storage drivers to set up a keyslot manager in their request_queue.
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
72
   *
c2b86b727   Satya Tangirala   FROMLIST: Update ...
73
   * Return: 0 on success, or else a negative error code.
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
74
   */
c2b86b727   Satya Tangirala   FROMLIST: Update ...
75
  int blk_ksm_init(struct blk_keyslot_manager *ksm, unsigned int num_slots)
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
76
  {
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
77
78
  	unsigned int slot;
  	unsigned int i;
c2b86b727   Satya Tangirala   FROMLIST: Update ...
79
  	unsigned int slot_hashtable_size;
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
80

c2b86b727   Satya Tangirala   FROMLIST: Update ...
81
  	memset(ksm, 0, sizeof(*ksm));
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
82

c2b86b727   Satya Tangirala   FROMLIST: Update ...
83
84
  	if (num_slots == 0)
  		return -EINVAL;
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
85

c2b86b727   Satya Tangirala   FROMLIST: Update ...
86
87
88
  	ksm->slots = kvcalloc(num_slots, sizeof(ksm->slots[0]), GFP_KERNEL);
  	if (!ksm->slots)
  		return -ENOMEM;
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
89
90
  
  	ksm->num_slots = num_slots;
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
91
92
93
94
95
96
97
  
  	init_rwsem(&ksm->lock);
  
  	init_waitqueue_head(&ksm->idle_slots_wait_queue);
  	INIT_LIST_HEAD(&ksm->idle_slots);
  
  	for (slot = 0; slot < num_slots; slot++) {
c2b86b727   Satya Tangirala   FROMLIST: Update ...
98
  		ksm->slots[slot].ksm = ksm;
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
99
100
101
102
103
  		list_add_tail(&ksm->slots[slot].idle_slot_node,
  			      &ksm->idle_slots);
  	}
  
  	spin_lock_init(&ksm->idle_slots_lock);
c2b86b727   Satya Tangirala   FROMLIST: Update ...
104
  	slot_hashtable_size = roundup_pow_of_two(num_slots);
47a846536   Eric Biggers   block/keyslot-man...
105
106
107
108
109
110
  	/*
  	 * hash_ptr() assumes bits != 0, so ensure the hash table has at least 2
  	 * buckets.  This only makes a difference when there is only 1 keyslot.
  	 */
  	if (slot_hashtable_size < 2)
  		slot_hashtable_size = 2;
c2b86b727   Satya Tangirala   FROMLIST: Update ...
111
112
  	ksm->log_slot_ht_size = ilog2(slot_hashtable_size);
  	ksm->slot_hashtable = kvmalloc_array(slot_hashtable_size,
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
113
114
115
  					     sizeof(ksm->slot_hashtable[0]),
  					     GFP_KERNEL);
  	if (!ksm->slot_hashtable)
c2b86b727   Satya Tangirala   FROMLIST: Update ...
116
117
  		goto err_destroy_ksm;
  	for (i = 0; i < slot_hashtable_size; i++)
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
118
  		INIT_HLIST_HEAD(&ksm->slot_hashtable[i]);
c2b86b727   Satya Tangirala   FROMLIST: Update ...
119
  	return 0;
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
120

c2b86b727   Satya Tangirala   FROMLIST: Update ...
121
122
123
  err_destroy_ksm:
  	blk_ksm_destroy(ksm);
  	return -ENOMEM;
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
124
  }
c2b86b727   Satya Tangirala   FROMLIST: Update ...
125
  EXPORT_SYMBOL_GPL(blk_ksm_init);
770581355   Eric Biggers   ANDROID: block: b...
126

cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
127
  static inline struct hlist_head *
c2b86b727   Satya Tangirala   FROMLIST: Update ...
128
129
  blk_ksm_hash_bucket_for_key(struct blk_keyslot_manager *ksm,
  			    const struct blk_crypto_key *key)
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
130
  {
c2b86b727   Satya Tangirala   FROMLIST: Update ...
131
  	return &ksm->slot_hashtable[hash_ptr(key, ksm->log_slot_ht_size)];
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
132
  }
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
133

c2b86b727   Satya Tangirala   FROMLIST: Update ...
134
  static void blk_ksm_remove_slot_from_lru_list(struct blk_ksm_keyslot *slot)
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
135
  {
c2b86b727   Satya Tangirala   FROMLIST: Update ...
136
  	struct blk_keyslot_manager *ksm = slot->ksm;
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
137
138
139
  	unsigned long flags;
  
  	spin_lock_irqsave(&ksm->idle_slots_lock, flags);
c2b86b727   Satya Tangirala   FROMLIST: Update ...
140
  	list_del(&slot->idle_slot_node);
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
141
  	spin_unlock_irqrestore(&ksm->idle_slots_lock, flags);
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
142
  }
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
143

c2b86b727   Satya Tangirala   FROMLIST: Update ...
144
145
146
  static struct blk_ksm_keyslot *blk_ksm_find_keyslot(
  					struct blk_keyslot_manager *ksm,
  					const struct blk_crypto_key *key)
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
147
  {
c2b86b727   Satya Tangirala   FROMLIST: Update ...
148
149
  	const struct hlist_head *head = blk_ksm_hash_bucket_for_key(ksm, key);
  	struct blk_ksm_keyslot *slotp;
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
150
151
  
  	hlist_for_each_entry(slotp, head, hash_node) {
c2b86b727   Satya Tangirala   FROMLIST: Update ...
152
153
  		if (slotp->key == key)
  			return slotp;
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
154
  	}
c2b86b727   Satya Tangirala   FROMLIST: Update ...
155
  	return NULL;
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
156
  }
c2b86b727   Satya Tangirala   FROMLIST: Update ...
157
158
159
  static struct blk_ksm_keyslot *blk_ksm_find_and_grab_keyslot(
  					struct blk_keyslot_manager *ksm,
  					const struct blk_crypto_key *key)
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
160
  {
c2b86b727   Satya Tangirala   FROMLIST: Update ...
161
  	struct blk_ksm_keyslot *slot;
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
162

c2b86b727   Satya Tangirala   FROMLIST: Update ...
163
164
165
166
  	slot = blk_ksm_find_keyslot(ksm, key);
  	if (!slot)
  		return NULL;
  	if (atomic_inc_return(&slot->slot_refs) == 1) {
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
167
  		/* Took first reference to this slot; remove it from LRU list */
c2b86b727   Satya Tangirala   FROMLIST: Update ...
168
  		blk_ksm_remove_slot_from_lru_list(slot);
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
169
170
171
  	}
  	return slot;
  }
c2b86b727   Satya Tangirala   FROMLIST: Update ...
172
173
174
175
176
  unsigned int blk_ksm_get_slot_idx(struct blk_ksm_keyslot *slot)
  {
  	return slot - slot->ksm->slots;
  }
  EXPORT_SYMBOL_GPL(blk_ksm_get_slot_idx);
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
177
  /**
c2b86b727   Satya Tangirala   FROMLIST: Update ...
178
   * blk_ksm_get_slot_for_key() - Program a key into a keyslot.
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
179
   * @ksm: The keyslot manager to program the key into.
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
180
181
   * @key: Pointer to the key object to program, including the raw key, crypto
   *	 mode, and data unit size.
c2b86b727   Satya Tangirala   FROMLIST: Update ...
182
   * @slot_ptr: A pointer to return the pointer of the allocated keyslot.
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
183
   *
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
184
185
186
   * Get a keyslot that's been programmed with the specified key.  If one already
   * exists, return it with incremented refcount.  Otherwise, wait for a keyslot
   * to become idle and program it.
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
187
188
   *
   * Context: Process context. Takes and releases ksm->lock.
c2b86b727   Satya Tangirala   FROMLIST: Update ...
189
190
191
   * Return: BLK_STS_OK on success (and keyslot is set to the pointer of the
   *	   allocated keyslot), or some other blk_status_t otherwise (and
   *	   keyslot is set to NULL).
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
192
   */
c2b86b727   Satya Tangirala   FROMLIST: Update ...
193
194
195
  blk_status_t blk_ksm_get_slot_for_key(struct blk_keyslot_manager *ksm,
  				      const struct blk_crypto_key *key,
  				      struct blk_ksm_keyslot **slot_ptr)
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
196
  {
c2b86b727   Satya Tangirala   FROMLIST: Update ...
197
198
  	struct blk_ksm_keyslot *slot;
  	int slot_idx;
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
199
  	int err;
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
200

c2b86b727   Satya Tangirala   FROMLIST: Update ...
201
202
203
204
  	*slot_ptr = NULL;
  
  	if (blk_ksm_is_passthrough(ksm))
  		return BLK_STS_OK;
c7da3f4f2   Satya Tangirala   ANDROID: block: I...
205

aac6c3dec   Satya Tangirala   FROMLIST: block: ...
206
  	down_read(&ksm->lock);
c2b86b727   Satya Tangirala   FROMLIST: Update ...
207
  	slot = blk_ksm_find_and_grab_keyslot(ksm, key);
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
208
  	up_read(&ksm->lock);
c2b86b727   Satya Tangirala   FROMLIST: Update ...
209
210
  	if (slot)
  		goto success;
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
211
212
  
  	for (;;) {
c2b86b727   Satya Tangirala   FROMLIST: Update ...
213
214
215
216
217
  		blk_ksm_hw_enter(ksm);
  		slot = blk_ksm_find_and_grab_keyslot(ksm, key);
  		if (slot) {
  			blk_ksm_hw_exit(ksm);
  			goto success;
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
218
219
220
221
222
223
  		}
  
  		/*
  		 * If we're here, that means there wasn't a slot that was
  		 * already programmed with the key. So try to program it.
  		 */
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
224
  		if (!list_empty(&ksm->idle_slots))
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
225
  			break;
c2b86b727   Satya Tangirala   FROMLIST: Update ...
226
  		blk_ksm_hw_exit(ksm);
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
227
  		wait_event(ksm->idle_slots_wait_queue,
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
228
  			   !list_empty(&ksm->idle_slots));
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
229
  	}
c2b86b727   Satya Tangirala   FROMLIST: Update ...
230
231
232
  	slot = list_first_entry(&ksm->idle_slots, struct blk_ksm_keyslot,
  				idle_slot_node);
  	slot_idx = blk_ksm_get_slot_idx(slot);
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
233

c2b86b727   Satya Tangirala   FROMLIST: Update ...
234
  	err = ksm->ksm_ll_ops.keyslot_program(ksm, key, slot_idx);
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
235
236
  	if (err) {
  		wake_up(&ksm->idle_slots_wait_queue);
c2b86b727   Satya Tangirala   FROMLIST: Update ...
237
238
  		blk_ksm_hw_exit(ksm);
  		return errno_to_blk_status(err);
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
239
  	}
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
240
  	/* Move this slot to the hash list for the new key. */
c2b86b727   Satya Tangirala   FROMLIST: Update ...
241
242
243
244
  	if (slot->key)
  		hlist_del(&slot->hash_node);
  	slot->key = key;
  	hlist_add_head(&slot->hash_node, blk_ksm_hash_bucket_for_key(ksm, key));
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
245

c2b86b727   Satya Tangirala   FROMLIST: Update ...
246
  	atomic_set(&slot->slot_refs, 1);
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
247

c2b86b727   Satya Tangirala   FROMLIST: Update ...
248
  	blk_ksm_remove_slot_from_lru_list(slot);
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
249

c2b86b727   Satya Tangirala   FROMLIST: Update ...
250
251
252
253
  	blk_ksm_hw_exit(ksm);
  success:
  	*slot_ptr = slot;
  	return BLK_STS_OK;
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
254
  }
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
255
256
  
  /**
c2b86b727   Satya Tangirala   FROMLIST: Update ...
257
258
   * blk_ksm_put_slot() - Release a reference to a slot
   * @slot: The keyslot to release the reference of.
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
259
260
261
   *
   * Context: Any context.
   */
c2b86b727   Satya Tangirala   FROMLIST: Update ...
262
  void blk_ksm_put_slot(struct blk_ksm_keyslot *slot)
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
263
  {
c2b86b727   Satya Tangirala   FROMLIST: Update ...
264
  	struct blk_keyslot_manager *ksm;
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
265
  	unsigned long flags;
c2b86b727   Satya Tangirala   FROMLIST: Update ...
266
  	if (!slot)
c7da3f4f2   Satya Tangirala   ANDROID: block: I...
267
  		return;
c2b86b727   Satya Tangirala   FROMLIST: Update ...
268
  	ksm = slot->ksm;
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
269

c2b86b727   Satya Tangirala   FROMLIST: Update ...
270
  	if (atomic_dec_and_lock_irqsave(&slot->slot_refs,
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
271
  					&ksm->idle_slots_lock, flags)) {
c2b86b727   Satya Tangirala   FROMLIST: Update ...
272
  		list_add_tail(&slot->idle_slot_node, &ksm->idle_slots);
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
273
  		spin_unlock_irqrestore(&ksm->idle_slots_lock, flags);
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
274
275
276
  		wake_up(&ksm->idle_slots_wait_queue);
  	}
  }
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
277
278
  
  /**
c2b86b727   Satya Tangirala   FROMLIST: Update ...
279
280
   * blk_ksm_crypto_cfg_supported() - Find out if a crypto configuration is
   *				    supported by a ksm.
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
281
   * @ksm: The keyslot manager to check
c2b86b727   Satya Tangirala   FROMLIST: Update ...
282
   * @cfg: The crypto configuration to check for.
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
283
   *
c2b86b727   Satya Tangirala   FROMLIST: Update ...
284
   * Checks for crypto_mode/data unit size/dun bytes support.
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
285
   *
c2b86b727   Satya Tangirala   FROMLIST: Update ...
286
   * Return: Whether or not this ksm supports the specified crypto config.
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
287
   */
c2b86b727   Satya Tangirala   FROMLIST: Update ...
288
289
  bool blk_ksm_crypto_cfg_supported(struct blk_keyslot_manager *ksm,
  				  const struct blk_crypto_config *cfg)
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
290
291
292
  {
  	if (!ksm)
  		return false;
c2b86b727   Satya Tangirala   FROMLIST: Update ...
293
294
  	if (!(ksm->crypto_modes_supported[cfg->crypto_mode] &
  	      cfg->data_unit_size))
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
295
  		return false;
c2b86b727   Satya Tangirala   FROMLIST: Update ...
296
  	if (ksm->max_dun_bytes_supported < cfg->dun_bytes)
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
297
  		return false;
c2b86b727   Satya Tangirala   FROMLIST: Update ...
298
  	if (cfg->is_hw_wrapped) {
935b0c41f   Eric Biggers   ANDROID: block: r...
299
300
301
302
303
304
  		if (!(ksm->features & BLK_CRYPTO_FEATURE_WRAPPED_KEYS))
  			return false;
  	} else {
  		if (!(ksm->features & BLK_CRYPTO_FEATURE_STANDARD_KEYS))
  			return false;
  	}
c2b86b727   Satya Tangirala   FROMLIST: Update ...
305
  	return true;
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
306
  }
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
307
308
  
  /**
c2b86b727   Satya Tangirala   FROMLIST: Update ...
309
   * blk_ksm_evict_key() - Evict a key from the lower layer device.
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
310
311
   * @ksm: The keyslot manager to evict from
   * @key: The key to evict
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
312
   *
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
313
   * Find the keyslot that the specified key was programmed into, and evict that
c2b86b727   Satya Tangirala   FROMLIST: Update ...
314
315
   * slot from the lower layer device. The slot must not be in use by any
   * in-flight IO when this function is called.
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
316
317
   *
   * Context: Process context. Takes and releases ksm->lock.
c2b86b727   Satya Tangirala   FROMLIST: Update ...
318
319
320
   * Return: 0 on success or if there's no keyslot with the specified key, -EBUSY
   *	   if the keyslot is still in use, or another -errno value on other
   *	   error.
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
321
   */
c2b86b727   Satya Tangirala   FROMLIST: Update ...
322
323
  int blk_ksm_evict_key(struct blk_keyslot_manager *ksm,
  		      const struct blk_crypto_key *key)
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
324
  {
c2b86b727   Satya Tangirala   FROMLIST: Update ...
325
326
  	struct blk_ksm_keyslot *slot;
  	int err = 0;
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
327

c2b86b727   Satya Tangirala   FROMLIST: Update ...
328
  	if (blk_ksm_is_passthrough(ksm)) {
c7da3f4f2   Satya Tangirala   ANDROID: block: I...
329
  		if (ksm->ksm_ll_ops.keyslot_evict) {
c2b86b727   Satya Tangirala   FROMLIST: Update ...
330
  			blk_ksm_hw_enter(ksm);
c7da3f4f2   Satya Tangirala   ANDROID: block: I...
331
  			err = ksm->ksm_ll_ops.keyslot_evict(ksm, key, -1);
c2b86b727   Satya Tangirala   FROMLIST: Update ...
332
  			blk_ksm_hw_exit(ksm);
c7da3f4f2   Satya Tangirala   ANDROID: block: I...
333
334
335
336
  			return err;
  		}
  		return 0;
  	}
c2b86b727   Satya Tangirala   FROMLIST: Update ...
337
338
339
  	blk_ksm_hw_enter(ksm);
  	slot = blk_ksm_find_keyslot(ksm, key);
  	if (!slot)
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
340
  		goto out_unlock;
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
341

c2b86b727   Satya Tangirala   FROMLIST: Update ...
342
  	if (WARN_ON_ONCE(atomic_read(&slot->slot_refs) != 0)) {
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
343
  		err = -EBUSY;
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
344
  		goto out_unlock;
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
345
  	}
c2b86b727   Satya Tangirala   FROMLIST: Update ...
346
347
  	err = ksm->ksm_ll_ops.keyslot_evict(ksm, key,
  					    blk_ksm_get_slot_idx(slot));
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
348
349
  	if (err)
  		goto out_unlock;
c2b86b727   Satya Tangirala   FROMLIST: Update ...
350
351
  	hlist_del(&slot->hash_node);
  	slot->key = NULL;
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
352
353
  	err = 0;
  out_unlock:
c2b86b727   Satya Tangirala   FROMLIST: Update ...
354
  	blk_ksm_hw_exit(ksm);
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
355
356
  	return err;
  }
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
357
358
  
  /**
c2b86b727   Satya Tangirala   FROMLIST: Update ...
359
   * blk_ksm_reprogram_all_keys() - Re-program all keyslots.
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
360
361
362
363
364
365
366
   * @ksm: The keyslot manager
   *
   * Re-program all keyslots that are supposed to have a key programmed.  This is
   * intended only for use by drivers for hardware that loses its keys on reset.
   *
   * Context: Process context. Takes and releases ksm->lock.
   */
c2b86b727   Satya Tangirala   FROMLIST: Update ...
367
  void blk_ksm_reprogram_all_keys(struct blk_keyslot_manager *ksm)
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
368
369
  {
  	unsigned int slot;
c2b86b727   Satya Tangirala   FROMLIST: Update ...
370
  	if (WARN_ON(blk_ksm_is_passthrough(ksm)))
c7da3f4f2   Satya Tangirala   ANDROID: block: I...
371
  		return;
a59152c40   Eric Biggers   ANDROID: ufs, blo...
372
  	/* This is for device initialization, so don't resume the device */
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
373
374
  	down_write(&ksm->lock);
  	for (slot = 0; slot < ksm->num_slots; slot++) {
c2b86b727   Satya Tangirala   FROMLIST: Update ...
375
  		const struct blk_crypto_key *key = ksm->slots[slot].key;
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
376
  		int err;
c2b86b727   Satya Tangirala   FROMLIST: Update ...
377
  		if (!key)
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
378
  			continue;
c2b86b727   Satya Tangirala   FROMLIST: Update ...
379
  		err = ksm->ksm_ll_ops.keyslot_program(ksm, key, slot);
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
380
381
382
383
  		WARN_ON(err);
  	}
  	up_write(&ksm->lock);
  }
c2b86b727   Satya Tangirala   FROMLIST: Update ...
384
  EXPORT_SYMBOL_GPL(blk_ksm_reprogram_all_keys);
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
385

c2b86b727   Satya Tangirala   FROMLIST: Update ...
386
  void blk_ksm_destroy(struct blk_keyslot_manager *ksm)
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
387
  {
c2b86b727   Satya Tangirala   FROMLIST: Update ...
388
389
390
  	if (!ksm)
  		return;
  	kvfree(ksm->slot_hashtable);
3e20aa963   Eric Biggers   block/keyslot-man...
391
  	kvfree_sensitive(ksm->slots, sizeof(ksm->slots[0]) * ksm->num_slots);
c2b86b727   Satya Tangirala   FROMLIST: Update ...
392
  	memzero_explicit(ksm, sizeof(*ksm));
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
393
  }
c2b86b727   Satya Tangirala   FROMLIST: Update ...
394
  EXPORT_SYMBOL_GPL(blk_ksm_destroy);
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
395

c2b86b727   Satya Tangirala   FROMLIST: Update ...
396
  bool blk_ksm_register(struct blk_keyslot_manager *ksm, struct request_queue *q)
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
397
  {
c2b86b727   Satya Tangirala   FROMLIST: Update ...
398
399
400
401
  	if (blk_integrity_queue_supports_integrity(q)) {
  		pr_warn("Integrity and hardware inline encryption are not supported together. Disabling hardware inline encryption.
  ");
  		return false;
cfd7e6c13   Satya Tangirala   FROMLIST: Update ...
402
  	}
c2b86b727   Satya Tangirala   FROMLIST: Update ...
403
404
  	q->ksm = ksm;
  	return true;
aac6c3dec   Satya Tangirala   FROMLIST: block: ...
405
  }
c2b86b727   Satya Tangirala   FROMLIST: Update ...
406
407
408
409
410
411
412
  EXPORT_SYMBOL_GPL(blk_ksm_register);
  
  void blk_ksm_unregister(struct request_queue *q)
  {
  	q->ksm = NULL;
  }
  EXPORT_SYMBOL_GPL(blk_ksm_unregister);
1daa058cc   Barani Muthukumaran   ANDROID: block: a...
413
414
  
  /**
c2b86b727   Satya Tangirala   FROMLIST: Update ...
415
416
417
418
419
420
   * blk_ksm_derive_raw_secret() - Derive software secret from wrapped key
   * @ksm: The keyslot manager
   * @wrapped_key: The wrapped key
   * @wrapped_key_size: Size of the wrapped key in bytes
   * @secret: (output) the software secret
   * @secret_size: (output) the number of secret bytes to derive
c7da3f4f2   Satya Tangirala   ANDROID: block: I...
421
   *
c2b86b727   Satya Tangirala   FROMLIST: Update ...
422
423
424
425
426
   * Given a hardware-wrapped key, ask the hardware to derive a secret which
   * software can use for cryptographic tasks other than inline encryption.  The
   * derived secret is guaranteed to be cryptographically isolated from the key
   * with which any inline encryption with this wrapped key would actually be
   * done.  I.e., both will be derived from the unwrapped key.
c7da3f4f2   Satya Tangirala   ANDROID: block: I...
427
   *
c2b86b727   Satya Tangirala   FROMLIST: Update ...
428
429
   * Return: 0 on success, -EOPNOTSUPP if hardware-wrapped keys are unsupported,
   *	   or another -errno code.
c7da3f4f2   Satya Tangirala   ANDROID: block: I...
430
   */
c2b86b727   Satya Tangirala   FROMLIST: Update ...
431
432
433
434
  int blk_ksm_derive_raw_secret(struct blk_keyslot_manager *ksm,
  			      const u8 *wrapped_key,
  			      unsigned int wrapped_key_size,
  			      u8 *secret, unsigned int secret_size)
c7da3f4f2   Satya Tangirala   ANDROID: block: I...
435
  {
c2b86b727   Satya Tangirala   FROMLIST: Update ...
436
  	int err;
c7da3f4f2   Satya Tangirala   ANDROID: block: I...
437

c2b86b727   Satya Tangirala   FROMLIST: Update ...
438
439
440
441
442
443
444
445
446
  	if (ksm->ksm_ll_ops.derive_raw_secret) {
  		blk_ksm_hw_enter(ksm);
  		err = ksm->ksm_ll_ops.derive_raw_secret(ksm, wrapped_key,
  							wrapped_key_size,
  							secret, secret_size);
  		blk_ksm_hw_exit(ksm);
  	} else {
  		err = -EOPNOTSUPP;
  	}
c7da3f4f2   Satya Tangirala   ANDROID: block: I...
447

c2b86b727   Satya Tangirala   FROMLIST: Update ...
448
  	return err;
c7da3f4f2   Satya Tangirala   ANDROID: block: I...
449
  }
c2b86b727   Satya Tangirala   FROMLIST: Update ...
450
  EXPORT_SYMBOL_GPL(blk_ksm_derive_raw_secret);
c7da3f4f2   Satya Tangirala   ANDROID: block: I...
451
452
  
  /**
c2b86b727   Satya Tangirala   FROMLIST: Update ...
453
   * blk_ksm_intersect_modes() - restrict supported modes by child device
bea2b9641   Eric Biggers   ANDROID: dm: add ...
454
455
456
457
458
459
460
461
462
   * @parent: The keyslot manager for parent device
   * @child: The keyslot manager for child device, or NULL
   *
   * Clear any crypto mode support bits in @parent that aren't set in @child.
   * If @child is NULL, then all parent bits are cleared.
   *
   * Only use this when setting up the keyslot manager for a layered device,
   * before it's been exposed yet.
   */
c2b86b727   Satya Tangirala   FROMLIST: Update ...
463
464
  void blk_ksm_intersect_modes(struct blk_keyslot_manager *parent,
  			     const struct blk_keyslot_manager *child)
bea2b9641   Eric Biggers   ANDROID: dm: add ...
465
466
467
  {
  	if (child) {
  		unsigned int i;
770581355   Eric Biggers   ANDROID: block: b...
468
469
470
  		parent->max_dun_bytes_supported =
  			min(parent->max_dun_bytes_supported,
  			    child->max_dun_bytes_supported);
c2b86b727   Satya Tangirala   FROMLIST: Update ...
471
  		parent->features &= child->features;
6b78d00f7   Eric Biggers   ANDROID: block/ke...
472
473
  		for (i = 0; i < ARRAY_SIZE(child->crypto_modes_supported);
  		     i++) {
c2b86b727   Satya Tangirala   FROMLIST: Update ...
474
475
  			parent->crypto_modes_supported[i] &=
  				child->crypto_modes_supported[i];
bea2b9641   Eric Biggers   ANDROID: dm: add ...
476
477
  		}
  	} else {
770581355   Eric Biggers   ANDROID: block: b...
478
  		parent->max_dun_bytes_supported = 0;
c2b86b727   Satya Tangirala   FROMLIST: Update ...
479
480
481
  		parent->features = 0;
  		memset(parent->crypto_modes_supported, 0,
  		       sizeof(parent->crypto_modes_supported));
bea2b9641   Eric Biggers   ANDROID: dm: add ...
482
483
  	}
  }
c2b86b727   Satya Tangirala   FROMLIST: Update ...
484
  EXPORT_SYMBOL_GPL(blk_ksm_intersect_modes);
bea2b9641   Eric Biggers   ANDROID: dm: add ...
485
486
  
  /**
c2b86b727   Satya Tangirala   FROMLIST: Update ...
487
488
   * blk_ksm_init_passthrough() - Init a passthrough keyslot manager
   * @ksm: The keyslot manager to init
1daa058cc   Barani Muthukumaran   ANDROID: block: a...
489
   *
c2b86b727   Satya Tangirala   FROMLIST: Update ...
490
491
492
493
494
   * Initialize a passthrough keyslot manager.
   * Called by e.g. storage drivers to set up a keyslot manager in their
   * request_queue, when the storage driver wants to manage its keys by itself.
   * This is useful for inline encryption hardware that don't have a small fixed
   * number of keyslots, and for layered devices.
1daa058cc   Barani Muthukumaran   ANDROID: block: a...
495
   *
c2b86b727   Satya Tangirala   FROMLIST: Update ...
496
   * See blk_ksm_init() for more details about the parameters.
1daa058cc   Barani Muthukumaran   ANDROID: block: a...
497
   */
c2b86b727   Satya Tangirala   FROMLIST: Update ...
498
  void blk_ksm_init_passthrough(struct blk_keyslot_manager *ksm)
1daa058cc   Barani Muthukumaran   ANDROID: block: a...
499
  {
c2b86b727   Satya Tangirala   FROMLIST: Update ...
500
501
  	memset(ksm, 0, sizeof(*ksm));
  	init_rwsem(&ksm->lock);
1daa058cc   Barani Muthukumaran   ANDROID: block: a...
502
  }
c2b86b727   Satya Tangirala   FROMLIST: Update ...
503
  EXPORT_SYMBOL_GPL(blk_ksm_init_passthrough);