Skip to content

Commit d3b17a2

Browse files
Satya Tangiralasnitm
authored andcommitted
block/keyslot-manager: Introduce functions for device mapper support
Introduce blk_ksm_update_capabilities() to update the capabilities of a keyslot manager (ksm) in-place. The pointer to a ksm in a device's request queue may not be easily replaced, because upper layers like the filesystem might access it (e.g. for programming keys/checking capabilities) at the same time the device wants to replace that request queue's ksm (and free the old ksm's memory). This function allows the device to update the capabilities of the ksm in its request queue directly. Devices can safely update the ksm this way without any synchronization with upper layers *only* if the updated (new) ksm continues to support all the crypto capabilities that the old ksm did (see description below for blk_ksm_is_superset() for why this is so). Also introduce blk_ksm_is_superset() which checks whether one ksm's capabilities are a (not necessarily strict) superset of another ksm's. The blk-crypto framework requires that crypto capabilities that were advertised when a bio was created continue to be supported by the device until that bio is ended - in practice this probably means that a device's advertised crypto capabilities can *never* "shrink" (since there's no synchronization between bio creation and when a device may want to change its advertised capabilities) - so a previously advertised crypto capability must always continue to be supported. This function can be used to check that a new ksm is a valid replacement for an old ksm. Signed-off-by: Satya Tangirala <[email protected]> Reviewed-by: Eric Biggers <[email protected]> Acked-by: Jens Axboe <[email protected]> Signed-off-by: Mike Snitzer <[email protected]>
1 parent 7bdcc48 commit d3b17a2

File tree

2 files changed

+116
-0
lines changed

2 files changed

+116
-0
lines changed

block/keyslot-manager.c

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,113 @@ void blk_ksm_unregister(struct request_queue *q)
424424
q->ksm = NULL;
425425
}
426426

427+
/**
428+
* blk_ksm_intersect_modes() - restrict supported modes by child device
429+
* @parent: The keyslot manager for parent device
430+
* @child: The keyslot manager for child device, or NULL
431+
*
432+
* Clear any crypto mode support bits in @parent that aren't set in @child.
433+
* If @child is NULL, then all parent bits are cleared.
434+
*
435+
* Only use this when setting up the keyslot manager for a layered device,
436+
* before it's been exposed yet.
437+
*/
438+
void blk_ksm_intersect_modes(struct blk_keyslot_manager *parent,
439+
const struct blk_keyslot_manager *child)
440+
{
441+
if (child) {
442+
unsigned int i;
443+
444+
parent->max_dun_bytes_supported =
445+
min(parent->max_dun_bytes_supported,
446+
child->max_dun_bytes_supported);
447+
for (i = 0; i < ARRAY_SIZE(child->crypto_modes_supported);
448+
i++) {
449+
parent->crypto_modes_supported[i] &=
450+
child->crypto_modes_supported[i];
451+
}
452+
} else {
453+
parent->max_dun_bytes_supported = 0;
454+
memset(parent->crypto_modes_supported, 0,
455+
sizeof(parent->crypto_modes_supported));
456+
}
457+
}
458+
EXPORT_SYMBOL_GPL(blk_ksm_intersect_modes);
459+
460+
/**
461+
* blk_ksm_is_superset() - Check if a KSM supports a superset of crypto modes
462+
* and DUN bytes that another KSM supports. Here,
463+
* "superset" refers to the mathematical meaning of the
464+
* word - i.e. if two KSMs have the *same* capabilities,
465+
* they *are* considered supersets of each other.
466+
* @ksm_superset: The KSM that we want to verify is a superset
467+
* @ksm_subset: The KSM that we want to verify is a subset
468+
*
469+
* Return: True if @ksm_superset supports a superset of the crypto modes and DUN
470+
* bytes that @ksm_subset supports.
471+
*/
472+
bool blk_ksm_is_superset(struct blk_keyslot_manager *ksm_superset,
473+
struct blk_keyslot_manager *ksm_subset)
474+
{
475+
int i;
476+
477+
if (!ksm_subset)
478+
return true;
479+
480+
if (!ksm_superset)
481+
return false;
482+
483+
for (i = 0; i < ARRAY_SIZE(ksm_superset->crypto_modes_supported); i++) {
484+
if (ksm_subset->crypto_modes_supported[i] &
485+
(~ksm_superset->crypto_modes_supported[i])) {
486+
return false;
487+
}
488+
}
489+
490+
if (ksm_subset->max_dun_bytes_supported >
491+
ksm_superset->max_dun_bytes_supported) {
492+
return false;
493+
}
494+
495+
return true;
496+
}
497+
EXPORT_SYMBOL_GPL(blk_ksm_is_superset);
498+
499+
/**
500+
* blk_ksm_update_capabilities() - Update the restrictions of a KSM to those of
501+
* another KSM
502+
* @target_ksm: The KSM whose restrictions to update.
503+
* @reference_ksm: The KSM to whose restrictions this function will update
504+
* @target_ksm's restrictions to.
505+
*
506+
* Blk-crypto requires that crypto capabilities that were
507+
* advertised when a bio was created continue to be supported by the
508+
* device until that bio is ended. This is turn means that a device cannot
509+
* shrink its advertised crypto capabilities without any explicit
510+
* synchronization with upper layers. So if there's no such explicit
511+
* synchronization, @reference_ksm must support all the crypto capabilities that
512+
* @target_ksm does
513+
* (i.e. we need blk_ksm_is_superset(@reference_ksm, @target_ksm) == true).
514+
*
515+
* Note also that as long as the crypto capabilities are being expanded, the
516+
* order of updates becoming visible is not important because it's alright
517+
* for blk-crypto to see stale values - they only cause blk-crypto to
518+
* believe that a crypto capability isn't supported when it actually is (which
519+
* might result in blk-crypto-fallback being used if available, or the bio being
520+
* failed).
521+
*/
522+
void blk_ksm_update_capabilities(struct blk_keyslot_manager *target_ksm,
523+
struct blk_keyslot_manager *reference_ksm)
524+
{
525+
memcpy(target_ksm->crypto_modes_supported,
526+
reference_ksm->crypto_modes_supported,
527+
sizeof(target_ksm->crypto_modes_supported));
528+
529+
target_ksm->max_dun_bytes_supported =
530+
reference_ksm->max_dun_bytes_supported;
531+
}
532+
EXPORT_SYMBOL_GPL(blk_ksm_update_capabilities);
533+
427534
/**
428535
* blk_ksm_init_passthrough() - Init a passthrough keyslot manager
429536
* @ksm: The keyslot manager to init

include/linux/keyslot-manager.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,15 @@ void blk_ksm_reprogram_all_keys(struct blk_keyslot_manager *ksm);
103103

104104
void blk_ksm_destroy(struct blk_keyslot_manager *ksm);
105105

106+
void blk_ksm_intersect_modes(struct blk_keyslot_manager *parent,
107+
const struct blk_keyslot_manager *child);
108+
106109
void blk_ksm_init_passthrough(struct blk_keyslot_manager *ksm);
107110

111+
bool blk_ksm_is_superset(struct blk_keyslot_manager *ksm_superset,
112+
struct blk_keyslot_manager *ksm_subset);
113+
114+
void blk_ksm_update_capabilities(struct blk_keyslot_manager *target_ksm,
115+
struct blk_keyslot_manager *reference_ksm);
116+
108117
#endif /* __LINUX_KEYSLOT_MANAGER_H */

0 commit comments

Comments
 (0)