Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/block/blk-crypto-profile.c
26242 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* Copyright 2019 Google LLC
4
*/
5
6
/**
7
* DOC: blk-crypto profiles
8
*
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.
15
*
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.
21
*
22
* For more information, see Documentation/block/inline-encryption.rst.
23
*/
24
25
#define pr_fmt(fmt) "blk-crypto: " fmt
26
27
#include <linux/blk-crypto-profile.h>
28
#include <linux/device.h>
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>
34
#include <linux/blk-integrity.h>
35
#include "blk-crypto-internal.h"
36
37
struct blk_crypto_keyslot {
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;
42
struct blk_crypto_profile *profile;
43
};
44
45
static inline void blk_crypto_hw_enter(struct blk_crypto_profile *profile)
46
{
47
/*
48
* Calling into the driver requires profile->lock held and the device
49
* resumed. But we must resume the device first, since that can acquire
50
* and release profile->lock via blk_crypto_reprogram_all_keys().
51
*/
52
if (profile->dev)
53
pm_runtime_get_sync(profile->dev);
54
down_write(&profile->lock);
55
}
56
57
static inline void blk_crypto_hw_exit(struct blk_crypto_profile *profile)
58
{
59
up_write(&profile->lock);
60
if (profile->dev)
61
pm_runtime_put_sync(profile->dev);
62
}
63
64
/**
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
68
*
69
* Storage drivers must call this when starting to set up a blk_crypto_profile,
70
* before filling in additional fields.
71
*
72
* Return: 0 on success, or else a negative error code.
73
*/
74
int blk_crypto_profile_init(struct blk_crypto_profile *profile,
75
unsigned int num_slots)
76
{
77
unsigned int slot;
78
unsigned int i;
79
unsigned int slot_hashtable_size;
80
81
memset(profile, 0, sizeof(*profile));
82
83
/*
84
* profile->lock of an underlying device can nest inside profile->lock
85
* of a device-mapper device, so use a dynamic lock class to avoid
86
* false-positive lockdep reports.
87
*/
88
lockdep_register_key(&profile->lockdep_key);
89
__init_rwsem(&profile->lock, "&profile->lock", &profile->lockdep_key);
90
91
if (num_slots == 0)
92
return 0;
93
94
/* Initialize keyslot management data. */
95
96
profile->slots = kvcalloc(num_slots, sizeof(profile->slots[0]),
97
GFP_KERNEL);
98
if (!profile->slots)
99
goto err_destroy;
100
101
profile->num_slots = num_slots;
102
103
init_waitqueue_head(&profile->idle_slots_wait_queue);
104
INIT_LIST_HEAD(&profile->idle_slots);
105
106
for (slot = 0; slot < num_slots; slot++) {
107
profile->slots[slot].profile = profile;
108
list_add_tail(&profile->slots[slot].idle_slot_node,
109
&profile->idle_slots);
110
}
111
112
spin_lock_init(&profile->idle_slots_lock);
113
114
slot_hashtable_size = roundup_pow_of_two(num_slots);
115
/*
116
* hash_ptr() assumes bits != 0, so ensure the hash table has at least 2
117
* buckets. This only makes a difference when there is only 1 keyslot.
118
*/
119
if (slot_hashtable_size < 2)
120
slot_hashtable_size = 2;
121
122
profile->log_slot_ht_size = ilog2(slot_hashtable_size);
123
profile->slot_hashtable =
124
kvmalloc_array(slot_hashtable_size,
125
sizeof(profile->slot_hashtable[0]), GFP_KERNEL);
126
if (!profile->slot_hashtable)
127
goto err_destroy;
128
for (i = 0; i < slot_hashtable_size; i++)
129
INIT_HLIST_HEAD(&profile->slot_hashtable[i]);
130
131
return 0;
132
133
err_destroy:
134
blk_crypto_profile_destroy(profile);
135
return -ENOMEM;
136
}
137
EXPORT_SYMBOL_GPL(blk_crypto_profile_init);
138
139
static void blk_crypto_profile_destroy_callback(void *profile)
140
{
141
blk_crypto_profile_destroy(profile);
142
}
143
144
/**
145
* devm_blk_crypto_profile_init() - Resource-managed blk_crypto_profile_init()
146
* @dev: the device which owns the blk_crypto_profile
147
* @profile: the blk_crypto_profile to initialize
148
* @num_slots: the number of keyslots
149
*
150
* Like blk_crypto_profile_init(), but causes blk_crypto_profile_destroy() to be
151
* called automatically on driver detach.
152
*
153
* Return: 0 on success, or else a negative error code.
154
*/
155
int devm_blk_crypto_profile_init(struct device *dev,
156
struct blk_crypto_profile *profile,
157
unsigned int num_slots)
158
{
159
int err = blk_crypto_profile_init(profile, num_slots);
160
161
if (err)
162
return err;
163
164
return devm_add_action_or_reset(dev,
165
blk_crypto_profile_destroy_callback,
166
profile);
167
}
168
EXPORT_SYMBOL_GPL(devm_blk_crypto_profile_init);
169
170
static inline struct hlist_head *
171
blk_crypto_hash_bucket_for_key(struct blk_crypto_profile *profile,
172
const struct blk_crypto_key *key)
173
{
174
return &profile->slot_hashtable[
175
hash_ptr(key, profile->log_slot_ht_size)];
176
}
177
178
static void
179
blk_crypto_remove_slot_from_lru_list(struct blk_crypto_keyslot *slot)
180
{
181
struct blk_crypto_profile *profile = slot->profile;
182
unsigned long flags;
183
184
spin_lock_irqsave(&profile->idle_slots_lock, flags);
185
list_del(&slot->idle_slot_node);
186
spin_unlock_irqrestore(&profile->idle_slots_lock, flags);
187
}
188
189
static struct blk_crypto_keyslot *
190
blk_crypto_find_keyslot(struct blk_crypto_profile *profile,
191
const struct blk_crypto_key *key)
192
{
193
const struct hlist_head *head =
194
blk_crypto_hash_bucket_for_key(profile, key);
195
struct blk_crypto_keyslot *slotp;
196
197
hlist_for_each_entry(slotp, head, hash_node) {
198
if (slotp->key == key)
199
return slotp;
200
}
201
return NULL;
202
}
203
204
static struct blk_crypto_keyslot *
205
blk_crypto_find_and_grab_keyslot(struct blk_crypto_profile *profile,
206
const struct blk_crypto_key *key)
207
{
208
struct blk_crypto_keyslot *slot;
209
210
slot = blk_crypto_find_keyslot(profile, key);
211
if (!slot)
212
return NULL;
213
if (atomic_inc_return(&slot->slot_refs) == 1) {
214
/* Took first reference to this slot; remove it from LRU list */
215
blk_crypto_remove_slot_from_lru_list(slot);
216
}
217
return slot;
218
}
219
220
/**
221
* blk_crypto_keyslot_index() - Get the index of a keyslot
222
* @slot: a keyslot that blk_crypto_get_keyslot() returned
223
*
224
* Return: the 0-based index of the keyslot within the device's keyslots.
225
*/
226
unsigned int blk_crypto_keyslot_index(struct blk_crypto_keyslot *slot)
227
{
228
return slot - slot->profile->slots;
229
}
230
EXPORT_SYMBOL_GPL(blk_crypto_keyslot_index);
231
232
/**
233
* blk_crypto_get_keyslot() - Get a keyslot for a key, if needed.
234
* @profile: the crypto profile of the device the key will be used on
235
* @key: the key that will be used
236
* @slot_ptr: If a keyslot is allocated, an opaque pointer to the keyslot struct
237
* will be stored here. blk_crypto_put_keyslot() must be called
238
* later to release it. Otherwise, NULL will be stored here.
239
*
240
* If the device has keyslots, this gets a keyslot that's been programmed with
241
* the specified key. If the key is already in a slot, this reuses it;
242
* otherwise this waits for a slot to become idle and programs the key into it.
243
*
244
* Context: Process context. Takes and releases profile->lock.
245
* Return: BLK_STS_OK on success, meaning that either a keyslot was allocated or
246
* one wasn't needed; or a blk_status_t error on failure.
247
*/
248
blk_status_t blk_crypto_get_keyslot(struct blk_crypto_profile *profile,
249
const struct blk_crypto_key *key,
250
struct blk_crypto_keyslot **slot_ptr)
251
{
252
struct blk_crypto_keyslot *slot;
253
int slot_idx;
254
int err;
255
256
*slot_ptr = NULL;
257
258
/*
259
* If the device has no concept of "keyslots", then there is no need to
260
* get one.
261
*/
262
if (profile->num_slots == 0)
263
return BLK_STS_OK;
264
265
down_read(&profile->lock);
266
slot = blk_crypto_find_and_grab_keyslot(profile, key);
267
up_read(&profile->lock);
268
if (slot)
269
goto success;
270
271
for (;;) {
272
blk_crypto_hw_enter(profile);
273
slot = blk_crypto_find_and_grab_keyslot(profile, key);
274
if (slot) {
275
blk_crypto_hw_exit(profile);
276
goto success;
277
}
278
279
/*
280
* If we're here, that means there wasn't a slot that was
281
* already programmed with the key. So try to program it.
282
*/
283
if (!list_empty(&profile->idle_slots))
284
break;
285
286
blk_crypto_hw_exit(profile);
287
wait_event(profile->idle_slots_wait_queue,
288
!list_empty(&profile->idle_slots));
289
}
290
291
slot = list_first_entry(&profile->idle_slots, struct blk_crypto_keyslot,
292
idle_slot_node);
293
slot_idx = blk_crypto_keyslot_index(slot);
294
295
err = profile->ll_ops.keyslot_program(profile, key, slot_idx);
296
if (err) {
297
wake_up(&profile->idle_slots_wait_queue);
298
blk_crypto_hw_exit(profile);
299
return errno_to_blk_status(err);
300
}
301
302
/* Move this slot to the hash list for the new key. */
303
if (slot->key)
304
hlist_del(&slot->hash_node);
305
slot->key = key;
306
hlist_add_head(&slot->hash_node,
307
blk_crypto_hash_bucket_for_key(profile, key));
308
309
atomic_set(&slot->slot_refs, 1);
310
311
blk_crypto_remove_slot_from_lru_list(slot);
312
313
blk_crypto_hw_exit(profile);
314
success:
315
*slot_ptr = slot;
316
return BLK_STS_OK;
317
}
318
319
/**
320
* blk_crypto_put_keyslot() - Release a reference to a keyslot
321
* @slot: The keyslot to release the reference of
322
*
323
* Context: Any context.
324
*/
325
void blk_crypto_put_keyslot(struct blk_crypto_keyslot *slot)
326
{
327
struct blk_crypto_profile *profile = slot->profile;
328
unsigned long flags;
329
330
if (atomic_dec_and_lock_irqsave(&slot->slot_refs,
331
&profile->idle_slots_lock, flags)) {
332
list_add_tail(&slot->idle_slot_node, &profile->idle_slots);
333
spin_unlock_irqrestore(&profile->idle_slots_lock, flags);
334
wake_up(&profile->idle_slots_wait_queue);
335
}
336
}
337
338
/**
339
* __blk_crypto_cfg_supported() - Check whether the given crypto profile
340
* supports the given crypto configuration.
341
* @profile: the crypto profile to check
342
* @cfg: the crypto configuration to check for
343
*
344
* Return: %true if @profile supports the given @cfg.
345
*/
346
bool __blk_crypto_cfg_supported(struct blk_crypto_profile *profile,
347
const struct blk_crypto_config *cfg)
348
{
349
if (!profile)
350
return false;
351
if (!(profile->modes_supported[cfg->crypto_mode] & cfg->data_unit_size))
352
return false;
353
if (profile->max_dun_bytes_supported < cfg->dun_bytes)
354
return false;
355
if (!(profile->key_types_supported & cfg->key_type))
356
return false;
357
return true;
358
}
359
360
/*
361
* This is an internal function that evicts a key from an inline encryption
362
* device that can be either a real device or the blk-crypto-fallback "device".
363
* It is used only by blk_crypto_evict_key(); see that function for details.
364
*/
365
int __blk_crypto_evict_key(struct blk_crypto_profile *profile,
366
const struct blk_crypto_key *key)
367
{
368
struct blk_crypto_keyslot *slot;
369
int err;
370
371
if (profile->num_slots == 0) {
372
if (profile->ll_ops.keyslot_evict) {
373
blk_crypto_hw_enter(profile);
374
err = profile->ll_ops.keyslot_evict(profile, key, -1);
375
blk_crypto_hw_exit(profile);
376
return err;
377
}
378
return 0;
379
}
380
381
blk_crypto_hw_enter(profile);
382
slot = blk_crypto_find_keyslot(profile, key);
383
if (!slot) {
384
/*
385
* Not an error, since a key not in use by I/O is not guaranteed
386
* to be in a keyslot. There can be more keys than keyslots.
387
*/
388
err = 0;
389
goto out;
390
}
391
392
if (WARN_ON_ONCE(atomic_read(&slot->slot_refs) != 0)) {
393
/* BUG: key is still in use by I/O */
394
err = -EBUSY;
395
goto out_remove;
396
}
397
err = profile->ll_ops.keyslot_evict(profile, key,
398
blk_crypto_keyslot_index(slot));
399
out_remove:
400
/*
401
* Callers free the key even on error, so unlink the key from the hash
402
* table and clear slot->key even on error.
403
*/
404
hlist_del(&slot->hash_node);
405
slot->key = NULL;
406
out:
407
blk_crypto_hw_exit(profile);
408
return err;
409
}
410
411
/**
412
* blk_crypto_reprogram_all_keys() - Re-program all keyslots.
413
* @profile: The crypto profile
414
*
415
* Re-program all keyslots that are supposed to have a key programmed. This is
416
* intended only for use by drivers for hardware that loses its keys on reset.
417
*
418
* Context: Process context. Takes and releases profile->lock.
419
*/
420
void blk_crypto_reprogram_all_keys(struct blk_crypto_profile *profile)
421
{
422
unsigned int slot;
423
424
if (profile->num_slots == 0)
425
return;
426
427
/* This is for device initialization, so don't resume the device */
428
down_write(&profile->lock);
429
for (slot = 0; slot < profile->num_slots; slot++) {
430
const struct blk_crypto_key *key = profile->slots[slot].key;
431
int err;
432
433
if (!key)
434
continue;
435
436
err = profile->ll_ops.keyslot_program(profile, key, slot);
437
WARN_ON(err);
438
}
439
up_write(&profile->lock);
440
}
441
EXPORT_SYMBOL_GPL(blk_crypto_reprogram_all_keys);
442
443
void blk_crypto_profile_destroy(struct blk_crypto_profile *profile)
444
{
445
if (!profile)
446
return;
447
lockdep_unregister_key(&profile->lockdep_key);
448
kvfree(profile->slot_hashtable);
449
kvfree_sensitive(profile->slots,
450
sizeof(profile->slots[0]) * profile->num_slots);
451
memzero_explicit(profile, sizeof(*profile));
452
}
453
EXPORT_SYMBOL_GPL(blk_crypto_profile_destroy);
454
455
bool blk_crypto_register(struct blk_crypto_profile *profile,
456
struct request_queue *q)
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
}
462
q->crypto_profile = profile;
463
return true;
464
}
465
EXPORT_SYMBOL_GPL(blk_crypto_register);
466
467
/**
468
* blk_crypto_derive_sw_secret() - Derive software secret from wrapped key
469
* @bdev: a block device that supports hardware-wrapped keys
470
* @eph_key: a hardware-wrapped key in ephemerally-wrapped form
471
* @eph_key_size: size of @eph_key in bytes
472
* @sw_secret: (output) the software secret
473
*
474
* Given a hardware-wrapped key in ephemerally-wrapped form (the same form that
475
* it is used for I/O), ask the hardware to derive the secret which software can
476
* use for cryptographic tasks other than inline encryption. This secret is
477
* guaranteed to be cryptographically isolated from the inline encryption key,
478
* i.e. derived with a different KDF context.
479
*
480
* Return: 0 on success, -EOPNOTSUPP if the block device doesn't support
481
* hardware-wrapped keys, -EBADMSG if the key isn't a valid
482
* ephemerally-wrapped key, or another -errno code.
483
*/
484
int blk_crypto_derive_sw_secret(struct block_device *bdev,
485
const u8 *eph_key, size_t eph_key_size,
486
u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE])
487
{
488
struct blk_crypto_profile *profile =
489
bdev_get_queue(bdev)->crypto_profile;
490
int err;
491
492
if (!profile)
493
return -EOPNOTSUPP;
494
if (!(profile->key_types_supported & BLK_CRYPTO_KEY_TYPE_HW_WRAPPED))
495
return -EOPNOTSUPP;
496
if (!profile->ll_ops.derive_sw_secret)
497
return -EOPNOTSUPP;
498
blk_crypto_hw_enter(profile);
499
err = profile->ll_ops.derive_sw_secret(profile, eph_key, eph_key_size,
500
sw_secret);
501
blk_crypto_hw_exit(profile);
502
return err;
503
}
504
EXPORT_SYMBOL_GPL(blk_crypto_derive_sw_secret);
505
506
int blk_crypto_import_key(struct blk_crypto_profile *profile,
507
const u8 *raw_key, size_t raw_key_size,
508
u8 lt_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE])
509
{
510
int ret;
511
512
if (!profile)
513
return -EOPNOTSUPP;
514
if (!(profile->key_types_supported & BLK_CRYPTO_KEY_TYPE_HW_WRAPPED))
515
return -EOPNOTSUPP;
516
if (!profile->ll_ops.import_key)
517
return -EOPNOTSUPP;
518
blk_crypto_hw_enter(profile);
519
ret = profile->ll_ops.import_key(profile, raw_key, raw_key_size,
520
lt_key);
521
blk_crypto_hw_exit(profile);
522
return ret;
523
}
524
EXPORT_SYMBOL_GPL(blk_crypto_import_key);
525
526
int blk_crypto_generate_key(struct blk_crypto_profile *profile,
527
u8 lt_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE])
528
{
529
int ret;
530
531
if (!profile)
532
return -EOPNOTSUPP;
533
if (!(profile->key_types_supported & BLK_CRYPTO_KEY_TYPE_HW_WRAPPED))
534
return -EOPNOTSUPP;
535
if (!profile->ll_ops.generate_key)
536
return -EOPNOTSUPP;
537
blk_crypto_hw_enter(profile);
538
ret = profile->ll_ops.generate_key(profile, lt_key);
539
blk_crypto_hw_exit(profile);
540
return ret;
541
}
542
EXPORT_SYMBOL_GPL(blk_crypto_generate_key);
543
544
int blk_crypto_prepare_key(struct blk_crypto_profile *profile,
545
const u8 *lt_key, size_t lt_key_size,
546
u8 eph_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE])
547
{
548
int ret;
549
550
if (!profile)
551
return -EOPNOTSUPP;
552
if (!(profile->key_types_supported & BLK_CRYPTO_KEY_TYPE_HW_WRAPPED))
553
return -EOPNOTSUPP;
554
if (!profile->ll_ops.prepare_key)
555
return -EOPNOTSUPP;
556
blk_crypto_hw_enter(profile);
557
ret = profile->ll_ops.prepare_key(profile, lt_key, lt_key_size,
558
eph_key);
559
blk_crypto_hw_exit(profile);
560
return ret;
561
}
562
EXPORT_SYMBOL_GPL(blk_crypto_prepare_key);
563
564
/**
565
* blk_crypto_intersect_capabilities() - restrict supported crypto capabilities
566
* by child device
567
* @parent: the crypto profile for the parent device
568
* @child: the crypto profile for the child device, or NULL
569
*
570
* This clears all crypto capabilities in @parent that aren't set in @child. If
571
* @child is NULL, then this clears all parent capabilities.
572
*
573
* Only use this when setting up the crypto profile for a layered device, before
574
* it's been exposed yet.
575
*/
576
void blk_crypto_intersect_capabilities(struct blk_crypto_profile *parent,
577
const struct blk_crypto_profile *child)
578
{
579
if (child) {
580
unsigned int i;
581
582
parent->max_dun_bytes_supported =
583
min(parent->max_dun_bytes_supported,
584
child->max_dun_bytes_supported);
585
for (i = 0; i < ARRAY_SIZE(child->modes_supported); i++)
586
parent->modes_supported[i] &= child->modes_supported[i];
587
parent->key_types_supported &= child->key_types_supported;
588
} else {
589
parent->max_dun_bytes_supported = 0;
590
memset(parent->modes_supported, 0,
591
sizeof(parent->modes_supported));
592
parent->key_types_supported = 0;
593
}
594
}
595
EXPORT_SYMBOL_GPL(blk_crypto_intersect_capabilities);
596
597
/**
598
* blk_crypto_has_capabilities() - Check whether @target supports at least all
599
* the crypto capabilities that @reference does.
600
* @target: the target profile
601
* @reference: the reference profile
602
*
603
* Return: %true if @target supports all the crypto capabilities of @reference.
604
*/
605
bool blk_crypto_has_capabilities(const struct blk_crypto_profile *target,
606
const struct blk_crypto_profile *reference)
607
{
608
int i;
609
610
if (!reference)
611
return true;
612
613
if (!target)
614
return false;
615
616
for (i = 0; i < ARRAY_SIZE(target->modes_supported); i++) {
617
if (reference->modes_supported[i] & ~target->modes_supported[i])
618
return false;
619
}
620
621
if (reference->max_dun_bytes_supported >
622
target->max_dun_bytes_supported)
623
return false;
624
625
if (reference->key_types_supported & ~target->key_types_supported)
626
return false;
627
628
return true;
629
}
630
EXPORT_SYMBOL_GPL(blk_crypto_has_capabilities);
631
632
/**
633
* blk_crypto_update_capabilities() - Update the capabilities of a crypto
634
* profile to match those of another crypto
635
* profile.
636
* @dst: The crypto profile whose capabilities to update.
637
* @src: The crypto profile whose capabilities this function will update @dst's
638
* capabilities to.
639
*
640
* Blk-crypto requires that crypto capabilities that were
641
* advertised when a bio was created continue to be supported by the
642
* device until that bio is ended. This is turn means that a device cannot
643
* shrink its advertised crypto capabilities without any explicit
644
* synchronization with upper layers. So if there's no such explicit
645
* synchronization, @src must support all the crypto capabilities that
646
* @dst does (i.e. we need blk_crypto_has_capabilities(@src, @dst)).
647
*
648
* Note also that as long as the crypto capabilities are being expanded, the
649
* order of updates becoming visible is not important because it's alright
650
* for blk-crypto to see stale values - they only cause blk-crypto to
651
* believe that a crypto capability isn't supported when it actually is (which
652
* might result in blk-crypto-fallback being used if available, or the bio being
653
* failed).
654
*/
655
void blk_crypto_update_capabilities(struct blk_crypto_profile *dst,
656
const struct blk_crypto_profile *src)
657
{
658
memcpy(dst->modes_supported, src->modes_supported,
659
sizeof(dst->modes_supported));
660
661
dst->max_dun_bytes_supported = src->max_dun_bytes_supported;
662
dst->key_types_supported = src->key_types_supported;
663
}
664
EXPORT_SYMBOL_GPL(blk_crypto_update_capabilities);
665
666