Commit | Line | Data |
---|---|---|
1b262839 ST |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Copyright 2019 Google LLC | |
4 | */ | |
5 | ||
6 | /** | |
cb77cb5a | 7 | * DOC: blk-crypto profiles |
1b262839 | 8 | * |
cb77cb5a EB |
9 | * 'struct blk_crypto_profile' contains all generic inline encryption-related |
10 | * state for a particular inline encryption device. blk_crypto_profile serves | |
11 | * as the way that drivers for inline encryption hardware expose their crypto | |
12 | * capabilities and certain functions (e.g., functions to program and evict | |
13 | * keys) to upper layers. Device drivers that want to support inline encryption | |
14 | * construct a crypto profile, then associate it with the disk's request_queue. | |
1b262839 | 15 | * |
cb77cb5a EB |
16 | * If the device has keyslots, then its blk_crypto_profile also handles managing |
17 | * these keyslots in a device-independent way, using the driver-provided | |
18 | * functions to program and evict keys as needed. This includes keeping track | |
19 | * of which key and how many I/O requests are using each keyslot, getting | |
20 | * keyslots for I/O requests, and handling key eviction requests. | |
1b262839 | 21 | * |
cb77cb5a | 22 | * For more information, see Documentation/block/inline-encryption.rst. |
1b262839 | 23 | */ |
d145dc23 ST |
24 | |
25 | #define pr_fmt(fmt) "blk-crypto: " fmt | |
26 | ||
1e8d44bd | 27 | #include <linux/blk-crypto-profile.h> |
5851d3b0 | 28 | #include <linux/device.h> |
1b262839 ST |
29 | #include <linux/atomic.h> |
30 | #include <linux/mutex.h> | |
31 | #include <linux/pm_runtime.h> | |
32 | #include <linux/wait.h> | |
33 | #include <linux/blkdev.h> | |
fe45e630 | 34 | #include <linux/blk-integrity.h> |
85168d41 | 35 | #include "blk-crypto-internal.h" |
1b262839 | 36 | |
cb77cb5a | 37 | struct blk_crypto_keyslot { |
1b262839 ST |
38 | atomic_t slot_refs; |
39 | struct list_head idle_slot_node; | |
40 | struct hlist_node hash_node; | |
41 | const struct blk_crypto_key *key; | |
cb77cb5a | 42 | struct blk_crypto_profile *profile; |
1b262839 ST |
43 | }; |
44 | ||
cb77cb5a | 45 | static inline void blk_crypto_hw_enter(struct blk_crypto_profile *profile) |
1b262839 ST |
46 | { |
47 | /* | |
cb77cb5a | 48 | * Calling into the driver requires profile->lock held and the device |
1b262839 | 49 | * resumed. But we must resume the device first, since that can acquire |
cb77cb5a | 50 | * and release profile->lock via blk_crypto_reprogram_all_keys(). |
1b262839 | 51 | */ |
cb77cb5a EB |
52 | if (profile->dev) |
53 | pm_runtime_get_sync(profile->dev); | |
54 | down_write(&profile->lock); | |
1b262839 ST |
55 | } |
56 | ||
cb77cb5a | 57 | static inline void blk_crypto_hw_exit(struct blk_crypto_profile *profile) |
1b262839 | 58 | { |
cb77cb5a EB |
59 | up_write(&profile->lock); |
60 | if (profile->dev) | |
61 | pm_runtime_put_sync(profile->dev); | |
7bdcc48f ST |
62 | } |
63 | ||
1b262839 | 64 | /** |
cb77cb5a EB |
65 | * blk_crypto_profile_init() - Initialize a blk_crypto_profile |
66 | * @profile: the blk_crypto_profile to initialize | |
67 | * @num_slots: the number of keyslots | |
1b262839 | 68 | * |
cb77cb5a EB |
69 | * Storage drivers must call this when starting to set up a blk_crypto_profile, |
70 | * before filling in additional fields. | |
1b262839 ST |
71 | * |
72 | * Return: 0 on success, or else a negative error code. | |
73 | */ | |
cb77cb5a EB |
74 | int blk_crypto_profile_init(struct blk_crypto_profile *profile, |
75 | unsigned int num_slots) | |
1b262839 ST |
76 | { |
77 | unsigned int slot; | |
78 | unsigned int i; | |
79 | unsigned int slot_hashtable_size; | |
80 | ||
cb77cb5a EB |
81 | memset(profile, 0, sizeof(*profile)); |
82 | init_rwsem(&profile->lock); | |
1b262839 ST |
83 | |
84 | if (num_slots == 0) | |
cb77cb5a | 85 | return 0; |
1b262839 | 86 | |
cb77cb5a | 87 | /* Initialize keyslot management data. */ |
1b262839 | 88 | |
cb77cb5a EB |
89 | profile->slots = kvcalloc(num_slots, sizeof(profile->slots[0]), |
90 | GFP_KERNEL); | |
91 | if (!profile->slots) | |
92 | return -ENOMEM; | |
1b262839 | 93 | |
cb77cb5a | 94 | profile->num_slots = num_slots; |
1b262839 | 95 | |
cb77cb5a EB |
96 | init_waitqueue_head(&profile->idle_slots_wait_queue); |
97 | INIT_LIST_HEAD(&profile->idle_slots); | |
1b262839 ST |
98 | |
99 | for (slot = 0; slot < num_slots; slot++) { | |
cb77cb5a EB |
100 | profile->slots[slot].profile = profile; |
101 | list_add_tail(&profile->slots[slot].idle_slot_node, | |
102 | &profile->idle_slots); | |
1b262839 ST |
103 | } |
104 | ||
cb77cb5a | 105 | spin_lock_init(&profile->idle_slots_lock); |
1b262839 ST |
106 | |
107 | slot_hashtable_size = roundup_pow_of_two(num_slots); | |
47a84653 EB |
108 | /* |
109 | * hash_ptr() assumes bits != 0, so ensure the hash table has at least 2 | |
110 | * buckets. This only makes a difference when there is only 1 keyslot. | |
111 | */ | |
112 | if (slot_hashtable_size < 2) | |
113 | slot_hashtable_size = 2; | |
114 | ||
cb77cb5a EB |
115 | profile->log_slot_ht_size = ilog2(slot_hashtable_size); |
116 | profile->slot_hashtable = | |
117 | kvmalloc_array(slot_hashtable_size, | |
118 | sizeof(profile->slot_hashtable[0]), GFP_KERNEL); | |
119 | if (!profile->slot_hashtable) | |
120 | goto err_destroy; | |
1b262839 | 121 | for (i = 0; i < slot_hashtable_size; i++) |
cb77cb5a | 122 | INIT_HLIST_HEAD(&profile->slot_hashtable[i]); |
1b262839 ST |
123 | |
124 | return 0; | |
125 | ||
cb77cb5a EB |
126 | err_destroy: |
127 | blk_crypto_profile_destroy(profile); | |
1b262839 ST |
128 | return -ENOMEM; |
129 | } | |
cb77cb5a | 130 | EXPORT_SYMBOL_GPL(blk_crypto_profile_init); |
1b262839 | 131 | |
cb77cb5a | 132 | static void blk_crypto_profile_destroy_callback(void *profile) |
5851d3b0 | 133 | { |
cb77cb5a | 134 | blk_crypto_profile_destroy(profile); |
5851d3b0 EB |
135 | } |
136 | ||
137 | /** | |
cb77cb5a EB |
138 | * devm_blk_crypto_profile_init() - Resource-managed blk_crypto_profile_init() |
139 | * @dev: the device which owns the blk_crypto_profile | |
140 | * @profile: the blk_crypto_profile to initialize | |
141 | * @num_slots: the number of keyslots | |
5851d3b0 | 142 | * |
cb77cb5a EB |
143 | * Like blk_crypto_profile_init(), but causes blk_crypto_profile_destroy() to be |
144 | * called automatically on driver detach. | |
5851d3b0 EB |
145 | * |
146 | * Return: 0 on success, or else a negative error code. | |
147 | */ | |
cb77cb5a EB |
148 | int devm_blk_crypto_profile_init(struct device *dev, |
149 | struct blk_crypto_profile *profile, | |
150 | unsigned int num_slots) | |
5851d3b0 | 151 | { |
cb77cb5a | 152 | int err = blk_crypto_profile_init(profile, num_slots); |
5851d3b0 EB |
153 | |
154 | if (err) | |
155 | return err; | |
156 | ||
cb77cb5a EB |
157 | return devm_add_action_or_reset(dev, |
158 | blk_crypto_profile_destroy_callback, | |
159 | profile); | |
5851d3b0 | 160 | } |
cb77cb5a | 161 | EXPORT_SYMBOL_GPL(devm_blk_crypto_profile_init); |
5851d3b0 | 162 | |
1b262839 | 163 | static inline struct hlist_head * |
cb77cb5a EB |
164 | blk_crypto_hash_bucket_for_key(struct blk_crypto_profile *profile, |
165 | const struct blk_crypto_key *key) | |
1b262839 | 166 | { |
cb77cb5a EB |
167 | return &profile->slot_hashtable[ |
168 | hash_ptr(key, profile->log_slot_ht_size)]; | |
1b262839 ST |
169 | } |
170 | ||
cb77cb5a EB |
171 | static void |
172 | blk_crypto_remove_slot_from_lru_list(struct blk_crypto_keyslot *slot) | |
1b262839 | 173 | { |
cb77cb5a | 174 | struct blk_crypto_profile *profile = slot->profile; |
1b262839 ST |
175 | unsigned long flags; |
176 | ||
cb77cb5a | 177 | spin_lock_irqsave(&profile->idle_slots_lock, flags); |
1b262839 | 178 | list_del(&slot->idle_slot_node); |
cb77cb5a | 179 | spin_unlock_irqrestore(&profile->idle_slots_lock, flags); |
1b262839 ST |
180 | } |
181 | ||
cb77cb5a EB |
182 | static struct blk_crypto_keyslot * |
183 | blk_crypto_find_keyslot(struct blk_crypto_profile *profile, | |
184 | const struct blk_crypto_key *key) | |
1b262839 | 185 | { |
cb77cb5a EB |
186 | const struct hlist_head *head = |
187 | blk_crypto_hash_bucket_for_key(profile, key); | |
188 | struct blk_crypto_keyslot *slotp; | |
1b262839 ST |
189 | |
190 | hlist_for_each_entry(slotp, head, hash_node) { | |
191 | if (slotp->key == key) | |
192 | return slotp; | |
193 | } | |
194 | return NULL; | |
195 | } | |
196 | ||
cb77cb5a EB |
197 | static struct blk_crypto_keyslot * |
198 | blk_crypto_find_and_grab_keyslot(struct blk_crypto_profile *profile, | |
199 | const struct blk_crypto_key *key) | |
1b262839 | 200 | { |
cb77cb5a | 201 | struct blk_crypto_keyslot *slot; |
1b262839 | 202 | |
cb77cb5a | 203 | slot = blk_crypto_find_keyslot(profile, key); |
1b262839 ST |
204 | if (!slot) |
205 | return NULL; | |
206 | if (atomic_inc_return(&slot->slot_refs) == 1) { | |
207 | /* Took first reference to this slot; remove it from LRU list */ | |
cb77cb5a | 208 | blk_crypto_remove_slot_from_lru_list(slot); |
1b262839 ST |
209 | } |
210 | return slot; | |
211 | } | |
212 | ||
cb77cb5a EB |
213 | /** |
214 | * blk_crypto_keyslot_index() - Get the index of a keyslot | |
215 | * @slot: a keyslot that blk_crypto_get_keyslot() returned | |
216 | * | |
217 | * Return: the 0-based index of the keyslot within the device's keyslots. | |
218 | */ | |
219 | unsigned int blk_crypto_keyslot_index(struct blk_crypto_keyslot *slot) | |
1b262839 | 220 | { |
cb77cb5a | 221 | return slot - slot->profile->slots; |
1b262839 | 222 | } |
cb77cb5a | 223 | EXPORT_SYMBOL_GPL(blk_crypto_keyslot_index); |
1b262839 ST |
224 | |
225 | /** | |
cb77cb5a EB |
226 | * blk_crypto_get_keyslot() - Get a keyslot for a key, if needed. |
227 | * @profile: the crypto profile of the device the key will be used on | |
228 | * @key: the key that will be used | |
229 | * @slot_ptr: If a keyslot is allocated, an opaque pointer to the keyslot struct | |
230 | * will be stored here; otherwise NULL will be stored here. | |
231 | * | |
232 | * If the device has keyslots, this gets a keyslot that's been programmed with | |
233 | * the specified key. If the key is already in a slot, this reuses it; | |
234 | * otherwise this waits for a slot to become idle and programs the key into it. | |
1b262839 | 235 | * |
cb77cb5a | 236 | * This must be paired with a call to blk_crypto_put_keyslot(). |
1b262839 | 237 | * |
cb77cb5a EB |
238 | * Context: Process context. Takes and releases profile->lock. |
239 | * Return: BLK_STS_OK on success, meaning that either a keyslot was allocated or | |
240 | * one wasn't needed; or a blk_status_t error on failure. | |
1b262839 | 241 | */ |
cb77cb5a EB |
242 | blk_status_t blk_crypto_get_keyslot(struct blk_crypto_profile *profile, |
243 | const struct blk_crypto_key *key, | |
244 | struct blk_crypto_keyslot **slot_ptr) | |
1b262839 | 245 | { |
cb77cb5a | 246 | struct blk_crypto_keyslot *slot; |
1b262839 ST |
247 | int slot_idx; |
248 | int err; | |
249 | ||
250 | *slot_ptr = NULL; | |
7bdcc48f | 251 | |
cb77cb5a EB |
252 | /* |
253 | * If the device has no concept of "keyslots", then there is no need to | |
254 | * get one. | |
255 | */ | |
256 | if (profile->num_slots == 0) | |
7bdcc48f ST |
257 | return BLK_STS_OK; |
258 | ||
cb77cb5a EB |
259 | down_read(&profile->lock); |
260 | slot = blk_crypto_find_and_grab_keyslot(profile, key); | |
261 | up_read(&profile->lock); | |
1b262839 ST |
262 | if (slot) |
263 | goto success; | |
264 | ||
265 | for (;;) { | |
cb77cb5a EB |
266 | blk_crypto_hw_enter(profile); |
267 | slot = blk_crypto_find_and_grab_keyslot(profile, key); | |
1b262839 | 268 | if (slot) { |
cb77cb5a | 269 | blk_crypto_hw_exit(profile); |
1b262839 ST |
270 | goto success; |
271 | } | |
272 | ||
273 | /* | |
274 | * If we're here, that means there wasn't a slot that was | |
275 | * already programmed with the key. So try to program it. | |
276 | */ | |
cb77cb5a | 277 | if (!list_empty(&profile->idle_slots)) |
1b262839 ST |
278 | break; |
279 | ||
cb77cb5a EB |
280 | blk_crypto_hw_exit(profile); |
281 | wait_event(profile->idle_slots_wait_queue, | |
282 | !list_empty(&profile->idle_slots)); | |
1b262839 ST |
283 | } |
284 | ||
cb77cb5a | 285 | slot = list_first_entry(&profile->idle_slots, struct blk_crypto_keyslot, |
1b262839 | 286 | idle_slot_node); |
cb77cb5a | 287 | slot_idx = blk_crypto_keyslot_index(slot); |
1b262839 | 288 | |
cb77cb5a | 289 | err = profile->ll_ops.keyslot_program(profile, key, slot_idx); |
1b262839 | 290 | if (err) { |
cb77cb5a EB |
291 | wake_up(&profile->idle_slots_wait_queue); |
292 | blk_crypto_hw_exit(profile); | |
1b262839 ST |
293 | return errno_to_blk_status(err); |
294 | } | |
295 | ||
296 | /* Move this slot to the hash list for the new key. */ | |
297 | if (slot->key) | |
298 | hlist_del(&slot->hash_node); | |
299 | slot->key = key; | |
cb77cb5a EB |
300 | hlist_add_head(&slot->hash_node, |
301 | blk_crypto_hash_bucket_for_key(profile, key)); | |
1b262839 ST |
302 | |
303 | atomic_set(&slot->slot_refs, 1); | |
304 | ||
cb77cb5a | 305 | blk_crypto_remove_slot_from_lru_list(slot); |
1b262839 | 306 | |
cb77cb5a | 307 | blk_crypto_hw_exit(profile); |
1b262839 ST |
308 | success: |
309 | *slot_ptr = slot; | |
310 | return BLK_STS_OK; | |
311 | } | |
312 | ||
313 | /** | |
cb77cb5a EB |
314 | * blk_crypto_put_keyslot() - Release a reference to a keyslot |
315 | * @slot: The keyslot to release the reference of (may be NULL). | |
1b262839 ST |
316 | * |
317 | * Context: Any context. | |
318 | */ | |
cb77cb5a | 319 | void blk_crypto_put_keyslot(struct blk_crypto_keyslot *slot) |
1b262839 | 320 | { |
cb77cb5a | 321 | struct blk_crypto_profile *profile; |
1b262839 ST |
322 | unsigned long flags; |
323 | ||
324 | if (!slot) | |
325 | return; | |
326 | ||
cb77cb5a | 327 | profile = slot->profile; |
1b262839 ST |
328 | |
329 | if (atomic_dec_and_lock_irqsave(&slot->slot_refs, | |
cb77cb5a EB |
330 | &profile->idle_slots_lock, flags)) { |
331 | list_add_tail(&slot->idle_slot_node, &profile->idle_slots); | |
332 | spin_unlock_irqrestore(&profile->idle_slots_lock, flags); | |
333 | wake_up(&profile->idle_slots_wait_queue); | |
1b262839 ST |
334 | } |
335 | } | |
336 | ||
337 | /** | |
cb77cb5a EB |
338 | * __blk_crypto_cfg_supported() - Check whether the given crypto profile |
339 | * supports the given crypto configuration. | |
340 | * @profile: the crypto profile to check | |
341 | * @cfg: the crypto configuration to check for | |
1b262839 | 342 | * |
cb77cb5a | 343 | * Return: %true if @profile supports the given @cfg. |
1b262839 | 344 | */ |
cb77cb5a EB |
345 | bool __blk_crypto_cfg_supported(struct blk_crypto_profile *profile, |
346 | const struct blk_crypto_config *cfg) | |
1b262839 | 347 | { |
cb77cb5a | 348 | if (!profile) |
1b262839 | 349 | return false; |
cb77cb5a | 350 | if (!(profile->modes_supported[cfg->crypto_mode] & cfg->data_unit_size)) |
1b262839 | 351 | return false; |
cb77cb5a | 352 | if (profile->max_dun_bytes_supported < cfg->dun_bytes) |
1b262839 ST |
353 | return false; |
354 | return true; | |
355 | } | |
356 | ||
357 | /** | |
cb77cb5a EB |
358 | * __blk_crypto_evict_key() - Evict a key from a device. |
359 | * @profile: the crypto profile of the device | |
360 | * @key: the key to evict. It must not still be used in any I/O. | |
361 | * | |
362 | * If the device has keyslots, this finds the keyslot (if any) that contains the | |
363 | * specified key and calls the driver's keyslot_evict function to evict it. | |
1b262839 | 364 | * |
cb77cb5a EB |
365 | * Otherwise, this just calls the driver's keyslot_evict function if it is |
366 | * implemented, passing just the key (without any particular keyslot). This | |
367 | * allows layered devices to evict the key from their underlying devices. | |
1b262839 | 368 | * |
cb77cb5a | 369 | * Context: Process context. Takes and releases profile->lock. |
1b262839 ST |
370 | * Return: 0 on success or if there's no keyslot with the specified key, -EBUSY |
371 | * if the keyslot is still in use, or another -errno value on other | |
372 | * error. | |
373 | */ | |
cb77cb5a EB |
374 | int __blk_crypto_evict_key(struct blk_crypto_profile *profile, |
375 | const struct blk_crypto_key *key) | |
1b262839 | 376 | { |
cb77cb5a | 377 | struct blk_crypto_keyslot *slot; |
1b262839 ST |
378 | int err = 0; |
379 | ||
cb77cb5a EB |
380 | if (profile->num_slots == 0) { |
381 | if (profile->ll_ops.keyslot_evict) { | |
382 | blk_crypto_hw_enter(profile); | |
383 | err = profile->ll_ops.keyslot_evict(profile, key, -1); | |
384 | blk_crypto_hw_exit(profile); | |
7bdcc48f ST |
385 | return err; |
386 | } | |
387 | return 0; | |
388 | } | |
389 | ||
cb77cb5a EB |
390 | blk_crypto_hw_enter(profile); |
391 | slot = blk_crypto_find_keyslot(profile, key); | |
1b262839 ST |
392 | if (!slot) |
393 | goto out_unlock; | |
394 | ||
395 | if (WARN_ON_ONCE(atomic_read(&slot->slot_refs) != 0)) { | |
396 | err = -EBUSY; | |
397 | goto out_unlock; | |
398 | } | |
cb77cb5a EB |
399 | err = profile->ll_ops.keyslot_evict(profile, key, |
400 | blk_crypto_keyslot_index(slot)); | |
1b262839 ST |
401 | if (err) |
402 | goto out_unlock; | |
403 | ||
404 | hlist_del(&slot->hash_node); | |
405 | slot->key = NULL; | |
406 | err = 0; | |
407 | out_unlock: | |
cb77cb5a | 408 | blk_crypto_hw_exit(profile); |
1b262839 ST |
409 | return err; |
410 | } | |
411 | ||
412 | /** | |
cb77cb5a EB |
413 | * blk_crypto_reprogram_all_keys() - Re-program all keyslots. |
414 | * @profile: The crypto profile | |
1b262839 ST |
415 | * |
416 | * Re-program all keyslots that are supposed to have a key programmed. This is | |
417 | * intended only for use by drivers for hardware that loses its keys on reset. | |
418 | * | |
cb77cb5a | 419 | * Context: Process context. Takes and releases profile->lock. |
1b262839 | 420 | */ |
cb77cb5a | 421 | void blk_crypto_reprogram_all_keys(struct blk_crypto_profile *profile) |
1b262839 ST |
422 | { |
423 | unsigned int slot; | |
424 | ||
cb77cb5a | 425 | if (profile->num_slots == 0) |
7bdcc48f ST |
426 | return; |
427 | ||
1b262839 | 428 | /* This is for device initialization, so don't resume the device */ |
cb77cb5a EB |
429 | down_write(&profile->lock); |
430 | for (slot = 0; slot < profile->num_slots; slot++) { | |
431 | const struct blk_crypto_key *key = profile->slots[slot].key; | |
1b262839 ST |
432 | int err; |
433 | ||
434 | if (!key) | |
435 | continue; | |
436 | ||
cb77cb5a | 437 | err = profile->ll_ops.keyslot_program(profile, key, slot); |
1b262839 ST |
438 | WARN_ON(err); |
439 | } | |
cb77cb5a | 440 | up_write(&profile->lock); |
1b262839 | 441 | } |
cb77cb5a | 442 | EXPORT_SYMBOL_GPL(blk_crypto_reprogram_all_keys); |
1b262839 | 443 | |
cb77cb5a | 444 | void blk_crypto_profile_destroy(struct blk_crypto_profile *profile) |
1b262839 | 445 | { |
cb77cb5a | 446 | if (!profile) |
1b262839 | 447 | return; |
cb77cb5a EB |
448 | kvfree(profile->slot_hashtable); |
449 | kvfree_sensitive(profile->slots, | |
450 | sizeof(profile->slots[0]) * profile->num_slots); | |
451 | memzero_explicit(profile, sizeof(*profile)); | |
1b262839 | 452 | } |
cb77cb5a | 453 | EXPORT_SYMBOL_GPL(blk_crypto_profile_destroy); |
d145dc23 | 454 | |
cb77cb5a EB |
455 | bool blk_crypto_register(struct blk_crypto_profile *profile, |
456 | struct request_queue *q) | |
d145dc23 ST |
457 | { |
458 | if (blk_integrity_queue_supports_integrity(q)) { | |
459 | pr_warn("Integrity and hardware inline encryption are not supported together. Disabling hardware inline encryption.\n"); | |
460 | return false; | |
461 | } | |
cb77cb5a | 462 | q->crypto_profile = profile; |
d145dc23 ST |
463 | return true; |
464 | } | |
cb77cb5a | 465 | EXPORT_SYMBOL_GPL(blk_crypto_register); |
d145dc23 | 466 | |
d3b17a24 | 467 | /** |
cb77cb5a EB |
468 | * blk_crypto_intersect_capabilities() - restrict supported crypto capabilities |
469 | * by child device | |
470 | * @parent: the crypto profile for the parent device | |
471 | * @child: the crypto profile for the child device, or NULL | |
d3b17a24 | 472 | * |
cb77cb5a EB |
473 | * This clears all crypto capabilities in @parent that aren't set in @child. If |
474 | * @child is NULL, then this clears all parent capabilities. | |
d3b17a24 | 475 | * |
cb77cb5a EB |
476 | * Only use this when setting up the crypto profile for a layered device, before |
477 | * it's been exposed yet. | |
d3b17a24 | 478 | */ |
cb77cb5a EB |
479 | void blk_crypto_intersect_capabilities(struct blk_crypto_profile *parent, |
480 | const struct blk_crypto_profile *child) | |
d3b17a24 ST |
481 | { |
482 | if (child) { | |
483 | unsigned int i; | |
484 | ||
485 | parent->max_dun_bytes_supported = | |
486 | min(parent->max_dun_bytes_supported, | |
487 | child->max_dun_bytes_supported); | |
cb77cb5a EB |
488 | for (i = 0; i < ARRAY_SIZE(child->modes_supported); i++) |
489 | parent->modes_supported[i] &= child->modes_supported[i]; | |
d3b17a24 ST |
490 | } else { |
491 | parent->max_dun_bytes_supported = 0; | |
cb77cb5a EB |
492 | memset(parent->modes_supported, 0, |
493 | sizeof(parent->modes_supported)); | |
d3b17a24 ST |
494 | } |
495 | } | |
cb77cb5a | 496 | EXPORT_SYMBOL_GPL(blk_crypto_intersect_capabilities); |
d3b17a24 ST |
497 | |
498 | /** | |
cb77cb5a EB |
499 | * blk_crypto_has_capabilities() - Check whether @target supports at least all |
500 | * the crypto capabilities that @reference does. | |
501 | * @target: the target profile | |
502 | * @reference: the reference profile | |
d3b17a24 | 503 | * |
cb77cb5a | 504 | * Return: %true if @target supports all the crypto capabilities of @reference. |
d3b17a24 | 505 | */ |
cb77cb5a EB |
506 | bool blk_crypto_has_capabilities(const struct blk_crypto_profile *target, |
507 | const struct blk_crypto_profile *reference) | |
d3b17a24 ST |
508 | { |
509 | int i; | |
510 | ||
cb77cb5a | 511 | if (!reference) |
d3b17a24 ST |
512 | return true; |
513 | ||
cb77cb5a | 514 | if (!target) |
d3b17a24 ST |
515 | return false; |
516 | ||
cb77cb5a EB |
517 | for (i = 0; i < ARRAY_SIZE(target->modes_supported); i++) { |
518 | if (reference->modes_supported[i] & ~target->modes_supported[i]) | |
d3b17a24 | 519 | return false; |
d3b17a24 ST |
520 | } |
521 | ||
cb77cb5a EB |
522 | if (reference->max_dun_bytes_supported > |
523 | target->max_dun_bytes_supported) | |
d3b17a24 | 524 | return false; |
d3b17a24 ST |
525 | |
526 | return true; | |
527 | } | |
cb77cb5a | 528 | EXPORT_SYMBOL_GPL(blk_crypto_has_capabilities); |
d3b17a24 ST |
529 | |
530 | /** | |
cb77cb5a EB |
531 | * blk_crypto_update_capabilities() - Update the capabilities of a crypto |
532 | * profile to match those of another crypto | |
533 | * profile. | |
534 | * @dst: The crypto profile whose capabilities to update. | |
535 | * @src: The crypto profile whose capabilities this function will update @dst's | |
536 | * capabilities to. | |
d3b17a24 ST |
537 | * |
538 | * Blk-crypto requires that crypto capabilities that were | |
539 | * advertised when a bio was created continue to be supported by the | |
540 | * device until that bio is ended. This is turn means that a device cannot | |
541 | * shrink its advertised crypto capabilities without any explicit | |
542 | * synchronization with upper layers. So if there's no such explicit | |
cb77cb5a EB |
543 | * synchronization, @src must support all the crypto capabilities that |
544 | * @dst does (i.e. we need blk_crypto_has_capabilities(@src, @dst)). | |
d3b17a24 ST |
545 | * |
546 | * Note also that as long as the crypto capabilities are being expanded, the | |
547 | * order of updates becoming visible is not important because it's alright | |
548 | * for blk-crypto to see stale values - they only cause blk-crypto to | |
549 | * believe that a crypto capability isn't supported when it actually is (which | |
550 | * might result in blk-crypto-fallback being used if available, or the bio being | |
551 | * failed). | |
552 | */ | |
cb77cb5a EB |
553 | void blk_crypto_update_capabilities(struct blk_crypto_profile *dst, |
554 | const struct blk_crypto_profile *src) | |
d3b17a24 | 555 | { |
cb77cb5a EB |
556 | memcpy(dst->modes_supported, src->modes_supported, |
557 | sizeof(dst->modes_supported)); | |
d3b17a24 | 558 | |
cb77cb5a | 559 | dst->max_dun_bytes_supported = src->max_dun_bytes_supported; |
7bdcc48f | 560 | } |
cb77cb5a | 561 | EXPORT_SYMBOL_GPL(blk_crypto_update_capabilities); |