tools headers UAPI: Sync drm/i915_drm.h with the kernel sources
[linux-2.6-microblaze.git] / block / keyslot-manager.c
index 324bf42..2c4a55b 100644 (file)
@@ -63,6 +63,11 @@ static inline void blk_ksm_hw_exit(struct blk_keyslot_manager *ksm)
                pm_runtime_put_sync(ksm->dev);
 }
 
+static inline bool blk_ksm_is_passthrough(struct blk_keyslot_manager *ksm)
+{
+       return ksm->num_slots == 0;
+}
+
 /**
  * blk_ksm_init() - Initialize a keyslot manager
  * @ksm: The keyslot_manager to initialize.
@@ -234,6 +239,10 @@ blk_status_t blk_ksm_get_slot_for_key(struct blk_keyslot_manager *ksm,
        int err;
 
        *slot_ptr = NULL;
+
+       if (blk_ksm_is_passthrough(ksm))
+               return BLK_STS_OK;
+
        down_read(&ksm->lock);
        slot = blk_ksm_find_and_grab_keyslot(ksm, key);
        up_read(&ksm->lock);
@@ -354,6 +363,16 @@ int blk_ksm_evict_key(struct blk_keyslot_manager *ksm,
        struct blk_ksm_keyslot *slot;
        int err = 0;
 
+       if (blk_ksm_is_passthrough(ksm)) {
+               if (ksm->ksm_ll_ops.keyslot_evict) {
+                       blk_ksm_hw_enter(ksm);
+                       err = ksm->ksm_ll_ops.keyslot_evict(ksm, key, -1);
+                       blk_ksm_hw_exit(ksm);
+                       return err;
+               }
+               return 0;
+       }
+
        blk_ksm_hw_enter(ksm);
        slot = blk_ksm_find_keyslot(ksm, key);
        if (!slot)
@@ -389,6 +408,9 @@ void blk_ksm_reprogram_all_keys(struct blk_keyslot_manager *ksm)
 {
        unsigned int slot;
 
+       if (blk_ksm_is_passthrough(ksm))
+               return;
+
        /* This is for device initialization, so don't resume the device */
        down_write(&ksm->lock);
        for (slot = 0; slot < ksm->num_slots; slot++) {
@@ -430,3 +452,127 @@ void blk_ksm_unregister(struct request_queue *q)
 {
        q->ksm = NULL;
 }
+
+/**
+ * blk_ksm_intersect_modes() - restrict supported modes by child device
+ * @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.
+ */
+void blk_ksm_intersect_modes(struct blk_keyslot_manager *parent,
+                            const struct blk_keyslot_manager *child)
+{
+       if (child) {
+               unsigned int i;
+
+               parent->max_dun_bytes_supported =
+                       min(parent->max_dun_bytes_supported,
+                           child->max_dun_bytes_supported);
+               for (i = 0; i < ARRAY_SIZE(child->crypto_modes_supported);
+                    i++) {
+                       parent->crypto_modes_supported[i] &=
+                               child->crypto_modes_supported[i];
+               }
+       } else {
+               parent->max_dun_bytes_supported = 0;
+               memset(parent->crypto_modes_supported, 0,
+                      sizeof(parent->crypto_modes_supported));
+       }
+}
+EXPORT_SYMBOL_GPL(blk_ksm_intersect_modes);
+
+/**
+ * blk_ksm_is_superset() - Check if a KSM supports a superset of crypto modes
+ *                        and DUN bytes that another KSM supports. Here,
+ *                        "superset" refers to the mathematical meaning of the
+ *                        word - i.e. if two KSMs have the *same* capabilities,
+ *                        they *are* considered supersets of each other.
+ * @ksm_superset: The KSM that we want to verify is a superset
+ * @ksm_subset: The KSM that we want to verify is a subset
+ *
+ * Return: True if @ksm_superset supports a superset of the crypto modes and DUN
+ *        bytes that @ksm_subset supports.
+ */
+bool blk_ksm_is_superset(struct blk_keyslot_manager *ksm_superset,
+                        struct blk_keyslot_manager *ksm_subset)
+{
+       int i;
+
+       if (!ksm_subset)
+               return true;
+
+       if (!ksm_superset)
+               return false;
+
+       for (i = 0; i < ARRAY_SIZE(ksm_superset->crypto_modes_supported); i++) {
+               if (ksm_subset->crypto_modes_supported[i] &
+                   (~ksm_superset->crypto_modes_supported[i])) {
+                       return false;
+               }
+       }
+
+       if (ksm_subset->max_dun_bytes_supported >
+           ksm_superset->max_dun_bytes_supported) {
+               return false;
+       }
+
+       return true;
+}
+EXPORT_SYMBOL_GPL(blk_ksm_is_superset);
+
+/**
+ * blk_ksm_update_capabilities() - Update the restrictions of a KSM to those of
+ *                                another KSM
+ * @target_ksm: The KSM whose restrictions to update.
+ * @reference_ksm: The KSM to whose restrictions this function will update
+ *                @target_ksm's restrictions to.
+ *
+ * Blk-crypto requires that crypto capabilities that were
+ * advertised when a bio was created continue to be supported by the
+ * device until that bio is ended. This is turn means that a device cannot
+ * shrink its advertised crypto capabilities without any explicit
+ * synchronization with upper layers. So if there's no such explicit
+ * synchronization, @reference_ksm must support all the crypto capabilities that
+ * @target_ksm does
+ * (i.e. we need blk_ksm_is_superset(@reference_ksm, @target_ksm) == true).
+ *
+ * Note also that as long as the crypto capabilities are being expanded, the
+ * order of updates becoming visible is not important because it's alright
+ * for blk-crypto to see stale values - they only cause blk-crypto to
+ * believe that a crypto capability isn't supported when it actually is (which
+ * might result in blk-crypto-fallback being used if available, or the bio being
+ * failed).
+ */
+void blk_ksm_update_capabilities(struct blk_keyslot_manager *target_ksm,
+                                struct blk_keyslot_manager *reference_ksm)
+{
+       memcpy(target_ksm->crypto_modes_supported,
+              reference_ksm->crypto_modes_supported,
+              sizeof(target_ksm->crypto_modes_supported));
+
+       target_ksm->max_dun_bytes_supported =
+                               reference_ksm->max_dun_bytes_supported;
+}
+EXPORT_SYMBOL_GPL(blk_ksm_update_capabilities);
+
+/**
+ * blk_ksm_init_passthrough() - Init a passthrough keyslot manager
+ * @ksm: The keyslot manager to init
+ *
+ * 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 doesn't have the concept
+ * of keyslots, and for layered devices.
+ */
+void blk_ksm_init_passthrough(struct blk_keyslot_manager *ksm)
+{
+       memset(ksm, 0, sizeof(*ksm));
+       init_rwsem(&ksm->lock);
+}
+EXPORT_SYMBOL_GPL(blk_ksm_init_passthrough);