aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Biggers <ebiggers@google.com>2021-11-24 15:41:26 -0800
committerEric Biggers <ebiggers@google.com>2021-11-26 00:26:43 -0800
commit8e447ca8fd53486033e2bebe4222474dfebb85b4 (patch)
treee55516d11141e6869f1f216a35040b0a9350bd6c
parentde5de0813b7dbbb71fb5d677ed823505a0e685c5 (diff)
downloadlinux-old/wip-blk-crypto-sysfs-symlink.tar.gz
blk-crypto: show crypto capabilities in sysfsold/wip-blk-crypto-sysfs-symlink
TODO Signed-off-by: Eric Biggers <ebiggers@google.com>
-rw-r--r--Documentation/block/inline-encryption.rst72
-rw-r--r--Documentation/block/queue-sysfs.rst7
-rw-r--r--block/Makefile3
-rw-r--r--block/blk-crypto-fallback.c25
-rw-r--r--block/blk-crypto-internal.h14
-rw-r--r--block/blk-crypto-profile.c104
-rw-r--r--block/blk-crypto-sysfs.c169
-rw-r--r--block/blk-crypto.c3
-rw-r--r--block/blk-sysfs.c8
-rw-r--r--drivers/md/dm-table.c45
-rw-r--r--drivers/md/dm.c2
-rw-r--r--drivers/mmc/core/crypto.c5
-rw-r--r--drivers/mmc/host/cqhci-crypto.c19
-rw-r--r--drivers/mmc/host/cqhci-crypto.h1
-rw-r--r--drivers/scsi/ufs/ufshcd-crypto.c40
-rw-r--r--drivers/scsi/ufs/ufshcd-crypto.h2
-rw-r--r--drivers/scsi/ufs/ufshcd.h3
-rw-r--r--include/linux/blk-crypto-profile.h27
-rw-r--r--include/linux/device-mapper.h5
-rw-r--r--include/linux/mmc/host.h3
20 files changed, 411 insertions, 146 deletions
diff --git a/Documentation/block/inline-encryption.rst b/Documentation/block/inline-encryption.rst
index 4d151fbe205831..04220310a51c1d 100644
--- a/Documentation/block/inline-encryption.rst
+++ b/Documentation/block/inline-encryption.rst
@@ -229,9 +229,9 @@ API presented to device drivers
===============================
A device driver that wants to support inline encryption must set up a
-blk_crypto_profile in the request_queue of its device. To do this, it first
-must call ``blk_crypto_profile_init()`` (or its resource-managed variant
-``devm_blk_crypto_profile_init()``), providing the number of keyslots.
+blk_crypto_profile. To do this, it must first call
+``devm_blk_crypto_profile_alloc()``, providing the number of keyslots. (The
+non-resource managed variant ``blk_crypto_profile_alloc()`` may also be used.)
Next, it must advertise its crypto capabilities by setting fields in the
blk_crypto_profile, e.g. ``modes_supported`` and ``max_dun_bytes_supported``.
@@ -242,6 +242,12 @@ hardware, e.g. how to program and evict keyslots. Most drivers will need to
implement ``keyslot_program`` and ``keyslot_evict``. For details, see the
comments for ``struct blk_crypto_ll_ops``.
+Next, it must add the blk_crypto_profile to sysfs underneath the device to which
+it belongs, using ``kobject_add()``.
+
+Finally, for each of its request_queue(s), the driver must call
+``blk_crypto_register()`` to register the crypto_profile with the request_queue.
+
Once the driver registers a blk_crypto_profile with a request_queue, I/O
requests the driver receives via that queue may have an encryption context. All
encryption contexts will be compatible with the crypto capabilities declared in
@@ -259,9 +265,63 @@ If there are situations where the inline encryption hardware loses the contents
of its keyslots, e.g. device resets, the driver must handle reprogramming the
keyslots. To do this, the driver may call ``blk_crypto_reprogram_all_keys()``.
-Finally, if the driver used ``blk_crypto_profile_init()`` instead of
-``devm_blk_crypto_profile_init()``, then it is responsible for calling
-``blk_crypto_profile_destroy()`` when the crypto profile is no longer needed.
+Finally, if the driver used ``blk_crypto_profile_alloc()`` instead of
+``devm_blk_crypto_profile_alloc()``, then it is responsible for calling
+``blk_crypto_profile_put()`` when the crypto profile is no longer needed.
+
+.. _inline_encryption_sysfs:
+
+sysfs support
+=============
+
+Since Linux v5.17, inline encryption capabilities are exposed to userspace via
+sysfs. This allows userspace to decide whether to use inline encryption or not,
+and if so with what settings, depending on the hardware's capabilities.
+
+The inline encryption capabilities are represented as a subdirectory "crypto" of
+the directory for the device to which the inline encryption hardware belongs.
+This could be a UFS or eMMC host controller, for example.
+
+The "queue" directory of disks (see Documentation/block/queue-sysfs.rst) that
+support inline encryption will also contain a symlink "crypto", i.e.
+/sys/class/block/$disk/queue/crypto, which points to the appropriate place.
+This allows the crypto capabilities to be looked up by disk or block device.
+
+Note that multiple queues will link to the same crypto directory if the inline
+encryption hardware is shared between disks. In this case, the crypto
+capabilities as well as the keyslots will be shared.
+
+Note: the sysfs files don't consider blk-crypto-fallback; they report the actual
+device capabilities only.
+
+The following files and subdirectories will be present in "crypto":
+
+max_dun_bits
+------------
+
+The maximum length, in bits, of data unit numbers (DUNs) accepted by the device.
+Read-only.
+
+modes
+-----
+
+This subdirectory contains one read-only file per crypto mode the device
+supports. Each such file contains a hexadecimal number that is a bitmask of the
+supported data unit sizes, in bytes, for the crypto mode.
+
+The crypto modes that may be supported are:
+
+* AES-256-XTS
+* AES-128-CBC-ESSIV
+* Adiantum
+
+For example, if a device supports AES-256-XTS with data unit sizes of 512 and
+4096 bytes, the file "AES-256-XTS" will be present and will contain "0x1200".
+
+num_keyslots
+------------
+
+The number of keyslots the device has. Read-only.
Layered Devices
===============
diff --git a/Documentation/block/queue-sysfs.rst b/Documentation/block/queue-sysfs.rst
index 3f569d53248573..353c5336be7523 100644
--- a/Documentation/block/queue-sysfs.rst
+++ b/Documentation/block/queue-sysfs.rst
@@ -24,6 +24,13 @@ or host-managed, chunk_sectors indicates the size in 512B sectors of the zones
of the device, with the eventual exception of the last zone of the device which
may be smaller.
+crypto
+------
+This symlink is present if the device supports inline encryption. It points to
+a directory which contains the device's inline encryption capabilities. For
+more information, refer to
+:ref:`Documentation/block/inline-encryption.rst <inline_encryption_sysfs>`.
+
dax (RO)
--------
This file indicates whether the device supports Direct Access (DAX),
diff --git a/block/Makefile b/block/Makefile
index f38eaa6129296a..3950ecbc5c263b 100644
--- a/block/Makefile
+++ b/block/Makefile
@@ -36,6 +36,7 @@ obj-$(CONFIG_BLK_DEBUG_FS) += blk-mq-debugfs.o
obj-$(CONFIG_BLK_DEBUG_FS_ZONED)+= blk-mq-debugfs-zoned.o
obj-$(CONFIG_BLK_SED_OPAL) += sed-opal.o
obj-$(CONFIG_BLK_PM) += blk-pm.o
-obj-$(CONFIG_BLK_INLINE_ENCRYPTION) += blk-crypto.o blk-crypto-profile.o
+obj-$(CONFIG_BLK_INLINE_ENCRYPTION) += blk-crypto.o blk-crypto-profile.o \
+ blk-crypto-sysfs.o
obj-$(CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK) += blk-crypto-fallback.o
obj-$(CONFIG_BLOCK_HOLDER_DEPRECATED) += holder.o
diff --git a/block/blk-crypto-fallback.c b/block/blk-crypto-fallback.c
index c87aba8584c646..bb8858aae6daff 100644
--- a/block/blk-crypto-fallback.c
+++ b/block/blk-crypto-fallback.c
@@ -78,7 +78,7 @@ static struct blk_crypto_fallback_keyslot {
struct crypto_skcipher *tfms[BLK_ENCRYPTION_MODE_MAX];
} *blk_crypto_keyslots;
-static struct blk_crypto_profile blk_crypto_fallback_profile;
+static struct blk_crypto_profile *blk_crypto_fallback_profile;
static struct workqueue_struct *blk_crypto_wq;
static mempool_t *blk_crypto_bounce_page_pool;
static struct bio_set crypto_bio_split;
@@ -292,7 +292,7 @@ static bool blk_crypto_fallback_encrypt_bio(struct bio **bio_ptr)
* Get a blk-crypto-fallback keyslot that contains a crypto_skcipher for
* this bio's algorithm and key.
*/
- blk_st = blk_crypto_get_keyslot(&blk_crypto_fallback_profile,
+ blk_st = blk_crypto_get_keyslot(blk_crypto_fallback_profile,
bc->bc_key, &slot);
if (blk_st != BLK_STS_OK) {
src_bio->bi_status = blk_st;
@@ -395,7 +395,7 @@ static void blk_crypto_fallback_decrypt_bio(struct work_struct *work)
* Get a blk-crypto-fallback keyslot that contains a crypto_skcipher for
* this bio's algorithm and key.
*/
- blk_st = blk_crypto_get_keyslot(&blk_crypto_fallback_profile,
+ blk_st = blk_crypto_get_keyslot(blk_crypto_fallback_profile,
bc->bc_key, &slot);
if (blk_st != BLK_STS_OK) {
bio->bi_status = blk_st;
@@ -499,7 +499,7 @@ bool blk_crypto_fallback_bio_prep(struct bio **bio_ptr)
return false;
}
- if (!__blk_crypto_cfg_supported(&blk_crypto_fallback_profile,
+ if (!__blk_crypto_cfg_supported(blk_crypto_fallback_profile,
&bc->bc_key->crypto_cfg)) {
bio->bi_status = BLK_STS_NOTSUPP;
return false;
@@ -526,7 +526,7 @@ bool blk_crypto_fallback_bio_prep(struct bio **bio_ptr)
int blk_crypto_fallback_evict_key(const struct blk_crypto_key *key)
{
- return __blk_crypto_evict_key(&blk_crypto_fallback_profile, key);
+ return __blk_crypto_evict_key(blk_crypto_fallback_profile, key);
}
static bool blk_crypto_fallback_inited;
@@ -534,7 +534,7 @@ static int blk_crypto_fallback_init(void)
{
int i;
int err;
- struct blk_crypto_profile *profile = &blk_crypto_fallback_profile;
+ struct blk_crypto_profile *profile;
if (blk_crypto_fallback_inited)
return 0;
@@ -545,9 +545,12 @@ static int blk_crypto_fallback_init(void)
if (err)
goto out;
- err = blk_crypto_profile_init(profile, blk_crypto_num_keyslots);
- if (err)
+ profile = blk_crypto_profile_alloc(blk_crypto_num_keyslots);
+ if (IS_ERR(profile)) {
+ err = PTR_ERR(profile);
goto fail_free_bioset;
+ }
+ blk_crypto_fallback_profile = profile;
err = -ENOMEM;
profile->ll_ops = blk_crypto_fallback_ll_ops;
@@ -562,7 +565,7 @@ static int blk_crypto_fallback_init(void)
WQ_UNBOUND | WQ_HIGHPRI |
WQ_MEM_RECLAIM, num_online_cpus());
if (!blk_crypto_wq)
- goto fail_destroy_profile;
+ goto fail_put_profile;
blk_crypto_keyslots = kcalloc(blk_crypto_num_keyslots,
sizeof(blk_crypto_keyslots[0]),
@@ -596,8 +599,8 @@ fail_free_keyslots:
kfree(blk_crypto_keyslots);
fail_free_wq:
destroy_workqueue(blk_crypto_wq);
-fail_destroy_profile:
- blk_crypto_profile_destroy(profile);
+fail_put_profile:
+ blk_crypto_profile_put(profile);
fail_free_bioset:
bioset_exit(&crypto_bio_split);
out:
diff --git a/block/blk-crypto-internal.h b/block/blk-crypto-internal.h
index 2fb0d65a464ca5..dc1b3a7af06889 100644
--- a/block/blk-crypto-internal.h
+++ b/block/blk-crypto-internal.h
@@ -11,6 +11,7 @@
/* Represents a crypto mode supported by blk-crypto */
struct blk_crypto_mode {
+ const char *name; /* name (shown in sysfs) */
const char *cipher_str; /* crypto API name (for fallback case) */
unsigned int keysize; /* key size in bytes */
unsigned int ivsize; /* iv size in bytes */
@@ -20,6 +21,12 @@ extern const struct blk_crypto_mode blk_crypto_modes[];
#ifdef CONFIG_BLK_INLINE_ENCRYPTION
+extern struct kobj_type blk_crypto_ktype;
+
+int blk_crypto_sysfs_link(struct request_queue *q);
+
+void blk_crypto_sysfs_unlink(struct request_queue *q);
+
void bio_crypt_dun_increment(u64 dun[BLK_CRYPTO_DUN_ARRAY_SIZE],
unsigned int inc);
@@ -62,6 +69,13 @@ static inline bool blk_crypto_rq_is_encrypted(struct request *rq)
#else /* CONFIG_BLK_INLINE_ENCRYPTION */
+static inline int blk_crypto_sysfs_link(struct request_queue *q)
+{
+ return 0;
+}
+
+static inline void blk_crypto_sysfs_unlink(struct request_queue *q) { }
+
static inline bool bio_crypt_rq_ctx_compatible(struct request *rq,
struct bio *bio)
{
diff --git a/block/blk-crypto-profile.c b/block/blk-crypto-profile.c
index 96c511967386d5..acc7fafc1b7554 100644
--- a/block/blk-crypto-profile.c
+++ b/block/blk-crypto-profile.c
@@ -33,13 +33,7 @@
#include <linux/blkdev.h>
#include <linux/blk-integrity.h>
-struct blk_crypto_keyslot {
- atomic_t slot_refs;
- struct list_head idle_slot_node;
- struct hlist_node hash_node;
- const struct blk_crypto_key *key;
- struct blk_crypto_profile *profile;
-};
+#include "blk-crypto-internal.h"
static inline void blk_crypto_hw_enter(struct blk_crypto_profile *profile)
{
@@ -61,35 +55,33 @@ static inline void blk_crypto_hw_exit(struct blk_crypto_profile *profile)
}
/**
- * blk_crypto_profile_init() - Initialize a blk_crypto_profile
- * @profile: the blk_crypto_profile to initialize
+ * blk_crypto_profile_alloc() - Allocate a blk_crypto_profile
* @num_slots: the number of keyslots
*
- * Storage drivers must call this when starting to set up a blk_crypto_profile,
- * before filling in additional fields.
+ * Storage drivers must call this to allocate a blk_crypto_profile, before
+ * filling in additional fields.
*
- * Return: 0 on success, or else a negative error code.
+ * Return: the new blk_crypto_profile on success; an ERR_PTR() on failure
*/
-int blk_crypto_profile_init(struct blk_crypto_profile *profile,
- unsigned int num_slots)
+struct blk_crypto_profile *blk_crypto_profile_alloc(unsigned int num_slots)
{
+ struct blk_crypto_profile *profile;
unsigned int slot;
unsigned int i;
unsigned int slot_hashtable_size;
- memset(profile, 0, sizeof(*profile));
+ profile = kvzalloc(struct_size(profile, slots, num_slots), GFP_KERNEL);
+ if (!profile)
+ return ERR_PTR(-ENOMEM);
+
init_rwsem(&profile->lock);
+ kobject_init(&profile->kobj, &blk_crypto_ktype);
if (num_slots == 0)
- return 0;
+ return profile;
/* Initialize keyslot management data. */
- profile->slots = kvcalloc(num_slots, sizeof(profile->slots[0]),
- GFP_KERNEL);
- if (!profile->slots)
- return -ENOMEM;
-
profile->num_slots = num_slots;
init_waitqueue_head(&profile->idle_slots_wait_queue);
@@ -116,48 +108,50 @@ int blk_crypto_profile_init(struct blk_crypto_profile *profile,
kvmalloc_array(slot_hashtable_size,
sizeof(profile->slot_hashtable[0]), GFP_KERNEL);
if (!profile->slot_hashtable)
- goto err_destroy;
+ goto err_put;
for (i = 0; i < slot_hashtable_size; i++)
INIT_HLIST_HEAD(&profile->slot_hashtable[i]);
- return 0;
+ return profile;
-err_destroy:
- blk_crypto_profile_destroy(profile);
- return -ENOMEM;
+err_put:
+ blk_crypto_profile_put(profile);
+ return ERR_PTR(-ENOMEM);
}
-EXPORT_SYMBOL_GPL(blk_crypto_profile_init);
+EXPORT_SYMBOL_GPL(blk_crypto_profile_alloc);
-static void blk_crypto_profile_destroy_callback(void *profile)
+static void blk_crypto_profile_put_callback(void *profile)
{
- blk_crypto_profile_destroy(profile);
+ blk_crypto_profile_put(profile);
}
/**
- * devm_blk_crypto_profile_init() - Resource-managed blk_crypto_profile_init()
- * @dev: the device which owns the blk_crypto_profile
- * @profile: the blk_crypto_profile to initialize
+ * devm_blk_crypto_profile_alloc() - Resource-managed blk_crypto_profile_alloc()
+ * @dev: the device which will own the blk_crypto_profile
* @num_slots: the number of keyslots
*
- * Like blk_crypto_profile_init(), but causes blk_crypto_profile_destroy() to be
+ * Like blk_crypto_profile_alloc(), but causes blk_crypto_profile_put() to be
* called automatically on driver detach.
*
- * Return: 0 on success, or else a negative error code.
+ * Return: the new blk_crypto_profile on success; an ERR_PTR() on failure
*/
-int devm_blk_crypto_profile_init(struct device *dev,
- struct blk_crypto_profile *profile,
- unsigned int num_slots)
+struct blk_crypto_profile *
+devm_blk_crypto_profile_alloc(struct device *dev, unsigned int num_slots)
{
- int err = blk_crypto_profile_init(profile, num_slots);
+ struct blk_crypto_profile *profile;
+ int err;
- if (err)
- return err;
+ profile = blk_crypto_profile_alloc(num_slots);
+ if (IS_ERR(profile))
+ return profile;
- return devm_add_action_or_reset(dev,
- blk_crypto_profile_destroy_callback,
- profile);
+ err = devm_add_action_or_reset(dev, blk_crypto_profile_put_callback,
+ profile);
+ if (err)
+ return ERR_PTR(err);
+ return profile;
}
-EXPORT_SYMBOL_GPL(devm_blk_crypto_profile_init);
+EXPORT_SYMBOL_GPL(devm_blk_crypto_profile_alloc);
static inline struct hlist_head *
blk_crypto_hash_bucket_for_key(struct blk_crypto_profile *profile,
@@ -440,16 +434,22 @@ void blk_crypto_reprogram_all_keys(struct blk_crypto_profile *profile)
}
EXPORT_SYMBOL_GPL(blk_crypto_reprogram_all_keys);
-void blk_crypto_profile_destroy(struct blk_crypto_profile *profile)
+void blk_crypto_profile_free(struct blk_crypto_profile *profile)
{
- if (!profile)
- return;
- kvfree(profile->slot_hashtable);
- kvfree_sensitive(profile->slots,
- sizeof(profile->slots[0]) * profile->num_slots);
- memzero_explicit(profile, sizeof(*profile));
+ if (profile) {
+ size_t size = struct_size(profile, slots, profile->num_slots);
+
+ kvfree(profile->slot_hashtable);
+ kvfree_sensitive(profile, size);
+ }
+}
+
+void blk_crypto_profile_put(struct blk_crypto_profile *profile)
+{
+ if (profile)
+ kobject_put(&profile->kobj);
}
-EXPORT_SYMBOL_GPL(blk_crypto_profile_destroy);
+EXPORT_SYMBOL_GPL(blk_crypto_profile_put);
bool blk_crypto_register(struct blk_crypto_profile *profile,
struct request_queue *q)
diff --git a/block/blk-crypto-sysfs.c b/block/blk-crypto-sysfs.c
new file mode 100644
index 00000000000000..461a79976f62d7
--- /dev/null
+++ b/block/blk-crypto-sysfs.c
@@ -0,0 +1,169 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2021 Google LLC
+ *
+ * Export the crypto capabilities of devices via sysfs.
+ */
+
+#include <linux/blk-crypto-profile.h>
+
+#include "blk-crypto-internal.h"
+
+struct blk_crypto_attr {
+ struct attribute attr;
+ ssize_t (*show)(struct blk_crypto_profile *profile,
+ struct blk_crypto_attr *attr, char *page);
+};
+
+static struct blk_crypto_profile *kobj_to_crypto_profile(struct kobject *kobj)
+{
+ return container_of(kobj, struct blk_crypto_profile, kobj);
+}
+
+static struct blk_crypto_attr *attr_to_crypto_attr(struct attribute *attr)
+{
+ return container_of(attr, struct blk_crypto_attr, attr);
+}
+
+static ssize_t blk_crypto_max_dun_bits_show(struct blk_crypto_profile *profile,
+ struct blk_crypto_attr *attr,
+ char *page)
+{
+ return sprintf(page, "%u\n", 8 * profile->max_dun_bytes_supported);
+}
+
+static ssize_t blk_crypto_num_keyslots_show(struct blk_crypto_profile *profile,
+ struct blk_crypto_attr *attr,
+ char *page)
+{
+ return sprintf(page, "%u\n", profile->num_slots);
+}
+
+#define BLK_CRYPTO_RO_ATTR(_name) \
+static struct blk_crypto_attr blk_crypto_##_name = { \
+ .attr = { .name = #_name, .mode = 0444 }, \
+ .show = blk_crypto_##_name##_show, \
+}
+
+BLK_CRYPTO_RO_ATTR(max_dun_bits);
+BLK_CRYPTO_RO_ATTR(num_keyslots);
+
+static struct attribute *blk_crypto_attrs[] = {
+ &blk_crypto_max_dun_bits.attr,
+ &blk_crypto_num_keyslots.attr,
+ NULL,
+};
+
+static const struct attribute_group blk_crypto_attr_group = {
+ .attrs = blk_crypto_attrs,
+};
+
+/*
+ * The encryption mode attributes. To avoid hard-coding the list of encryption
+ * modes, these are initialized at boot time by blk_crypto_sysfs_init().
+ */
+static struct blk_crypto_attr __blk_crypto_mode_attrs[BLK_ENCRYPTION_MODE_MAX];
+static struct attribute *blk_crypto_mode_attrs[BLK_ENCRYPTION_MODE_MAX + 1];
+
+static umode_t blk_crypto_mode_is_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
+{
+ struct blk_crypto_profile *profile = kobj_to_crypto_profile(kobj);
+ struct blk_crypto_attr *a = attr_to_crypto_attr(attr);
+ int mode_num = a - __blk_crypto_mode_attrs;
+
+ if (profile->modes_supported[mode_num])
+ return 0400;
+ return 0;
+}
+
+static ssize_t blk_crypto_mode_show(struct blk_crypto_profile *profile,
+ struct blk_crypto_attr *attr, char *page)
+{
+ int mode_num = attr - __blk_crypto_mode_attrs;
+
+ return sprintf(page, "0x%x\n", profile->modes_supported[mode_num]);
+}
+
+static const struct attribute_group blk_crypto_modes_attr_group = {
+ .name = "modes",
+ .attrs = blk_crypto_mode_attrs,
+ .is_visible = blk_crypto_mode_is_visible,
+};
+
+static const struct attribute_group *blk_crypto_attr_groups[] = {
+ &blk_crypto_attr_group,
+ &blk_crypto_modes_attr_group,
+ NULL,
+};
+
+static ssize_t blk_crypto_attr_show(struct kobject *kobj,
+ struct attribute *attr, char *page)
+{
+ struct blk_crypto_profile *profile = kobj_to_crypto_profile(kobj);
+ struct blk_crypto_attr *a = attr_to_crypto_attr(attr);
+
+ return a->show(profile, a, page);
+}
+
+static const struct sysfs_ops blk_crypto_attr_ops = {
+ .show = blk_crypto_attr_show,
+};
+
+static void blk_crypto_release(struct kobject *kobj)
+{
+ struct blk_crypto_profile *profile = kobj_to_crypto_profile(kobj);
+
+ blk_crypto_profile_put(profile);
+}
+
+struct kobj_type blk_crypto_ktype = {
+ .default_groups = blk_crypto_attr_groups,
+ .sysfs_ops = &blk_crypto_attr_ops,
+ .release = blk_crypto_release,
+};
+
+/*
+ * If the request_queue has a crypto profile, create the "crypto" symlink in the
+ * queue's sysfs directory, to expose the crypto capabilities to userspace.
+ *
+ * The reason we create a symlink rather than directly add the crypto profile is
+ * because it belongs to another device (e.g. a host controller), not to the
+ * request_queue. Multiple request_queues may share the same crypto profile.
+ */
+int blk_crypto_sysfs_link(struct request_queue *q)
+{
+ struct blk_crypto_profile *profile = q->crypto_profile;
+
+ if (!profile)
+ return 0;
+ /* The driver should have added the profile to sysfs already */
+ if (WARN_ON(!profile->kobj.parent))
+ return 0;
+ return sysfs_create_link(&q->kobj, &profile->kobj, "crypto");
+}
+
+void blk_crypto_sysfs_unlink(struct request_queue *q)
+{
+ struct blk_crypto_profile *profile = q->crypto_profile;
+
+ if (profile && profile->kobj.parent)
+ sysfs_remove_link(&q->kobj, "crypto");
+}
+
+static int __init blk_crypto_sysfs_init(void)
+{
+ int i;
+
+ BUILD_BUG_ON(BLK_ENCRYPTION_MODE_INVALID != 0);
+ for (i = 1; i < BLK_ENCRYPTION_MODE_MAX; i++) {
+ struct blk_crypto_attr *attr = &__blk_crypto_mode_attrs[i];
+
+ attr->attr.name = blk_crypto_modes[i].name;
+ attr->attr.mode = 0444;
+ attr->show = blk_crypto_mode_show;
+ blk_crypto_mode_attrs[i - 1] = &attr->attr;
+ }
+ return 0;
+}
+subsys_initcall(blk_crypto_sysfs_init);
diff --git a/block/blk-crypto.c b/block/blk-crypto.c
index ec9efeeeca9184..f8a36c723a987f 100644
--- a/block/blk-crypto.c
+++ b/block/blk-crypto.c
@@ -19,16 +19,19 @@
const struct blk_crypto_mode blk_crypto_modes[] = {
[BLK_ENCRYPTION_MODE_AES_256_XTS] = {
+ .name = "AES-256-XTS",
.cipher_str = "xts(aes)",
.keysize = 64,
.ivsize = 16,
},
[BLK_ENCRYPTION_MODE_AES_128_CBC_ESSIV] = {
+ .name = "AES-128-CBC-ESSIV",
.cipher_str = "essiv(cbc(aes),sha256)",
.keysize = 16,
.ivsize = 16,
},
[BLK_ENCRYPTION_MODE_ADIANTUM] = {
+ .name = "Adiantum",
.cipher_str = "adiantum(xchacha12,aes)",
.keysize = 32,
.ivsize = 32,
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index 4622da4bb99275..5718a2c2005465 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -876,6 +876,10 @@ int blk_register_queue(struct gendisk *disk)
goto put_dev;
}
+ ret = blk_crypto_sysfs_link(q);
+ if (ret)
+ goto unregister_elv;
+
blk_queue_flag_set(QUEUE_FLAG_REGISTERED, q);
wbt_enable_default(q);
blk_throtl_register_queue(q);
@@ -906,6 +910,9 @@ unlock:
return ret;
+unregister_elv:
+ if (q->elevator)
+ elv_unregister_queue(q);
put_dev:
disk_unregister_independent_access_ranges(disk);
mutex_unlock(&q->sysfs_lock);
@@ -957,6 +964,7 @@ void blk_unregister_queue(struct gendisk *disk)
blk_trace_remove_sysfs(disk_to_dev(disk));
mutex_lock(&q->sysfs_lock);
+ blk_crypto_sysfs_unlink(q);
if (q->elevator)
elv_unregister_queue(q);
disk_unregister_independent_access_ranges(disk);
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index aa173f5bdc3dd1..c2855af58fc51b 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -1186,11 +1186,6 @@ static int dm_table_register_integrity(struct dm_table *t)
#ifdef CONFIG_BLK_INLINE_ENCRYPTION
-struct dm_crypto_profile {
- struct blk_crypto_profile profile;
- struct mapped_device *md;
-};
-
struct dm_keyslot_evict_args {
const struct blk_crypto_key *key;
int err;
@@ -1216,8 +1211,7 @@ static int dm_keyslot_evict_callback(struct dm_target *ti, struct dm_dev *dev,
static int dm_keyslot_evict(struct blk_crypto_profile *profile,
const struct blk_crypto_key *key, unsigned int slot)
{
- struct mapped_device *md =
- container_of(profile, struct dm_crypto_profile, profile)->md;
+ struct mapped_device *md = profile->private;
struct dm_keyslot_evict_args args = { key };
struct dm_table *t;
int srcu_idx;
@@ -1249,22 +1243,9 @@ device_intersect_crypto_capabilities(struct dm_target *ti, struct dm_dev *dev,
return 0;
}
-void dm_destroy_crypto_profile(struct blk_crypto_profile *profile)
-{
- struct dm_crypto_profile *dmcp = container_of(profile,
- struct dm_crypto_profile,
- profile);
-
- if (!profile)
- return;
-
- blk_crypto_profile_destroy(profile);
- kfree(dmcp);
-}
-
static void dm_table_destroy_crypto_profile(struct dm_table *t)
{
- dm_destroy_crypto_profile(t->crypto_profile);
+ blk_crypto_profile_put(t->crypto_profile);
t->crypto_profile = NULL;
}
@@ -1279,19 +1260,15 @@ static void dm_table_destroy_crypto_profile(struct dm_table *t)
*/
static int dm_table_construct_crypto_profile(struct dm_table *t)
{
- struct dm_crypto_profile *dmcp;
struct blk_crypto_profile *profile;
struct dm_target *ti;
unsigned int i;
bool empty_profile = true;
- dmcp = kmalloc(sizeof(*dmcp), GFP_KERNEL);
- if (!dmcp)
- return -ENOMEM;
- dmcp->md = t->md;
-
- profile = &dmcp->profile;
- blk_crypto_profile_init(profile, 0);
+ profile = blk_crypto_profile_alloc(0);
+ if (IS_ERR(profile))
+ return PTR_ERR(profile);
+ profile->private = t->md;
profile->ll_ops.keyslot_evict = dm_keyslot_evict;
profile->max_dun_bytes_supported = UINT_MAX;
memset(profile->modes_supported, 0xFF,
@@ -1315,7 +1292,7 @@ static int dm_table_construct_crypto_profile(struct dm_table *t)
!blk_crypto_has_capabilities(profile,
t->md->queue->crypto_profile)) {
DMWARN("Inline encryption capabilities of new DM table were more restrictive than the old table's. This is not supported!");
- dm_destroy_crypto_profile(profile);
+ blk_crypto_profile_put(profile);
return -EINVAL;
}
@@ -1331,7 +1308,7 @@ static int dm_table_construct_crypto_profile(struct dm_table *t)
}
if (empty_profile) {
- dm_destroy_crypto_profile(profile);
+ blk_crypto_profile_put(profile);
profile = NULL;
}
@@ -1357,7 +1334,7 @@ static void dm_update_crypto_profile(struct request_queue *q,
} else {
blk_crypto_update_capabilities(q->crypto_profile,
t->crypto_profile);
- dm_destroy_crypto_profile(t->crypto_profile);
+ blk_crypto_profile_put(t->crypto_profile);
}
t->crypto_profile = NULL;
}
@@ -1369,10 +1346,6 @@ static int dm_table_construct_crypto_profile(struct dm_table *t)
return 0;
}
-void dm_destroy_crypto_profile(struct blk_crypto_profile *profile)
-{
-}
-
static void dm_table_destroy_crypto_profile(struct dm_table *t)
{
}
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 280918cdcabd30..a192bee5d63c43 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -1665,7 +1665,7 @@ static void dm_wq_work(struct work_struct *work);
#ifdef CONFIG_BLK_INLINE_ENCRYPTION
static void dm_queue_destroy_crypto_profile(struct request_queue *q)
{
- dm_destroy_crypto_profile(q->crypto_profile);
+ blk_crypto_profile_put(q->crypto_profile);
}
#else /* CONFIG_BLK_INLINE_ENCRYPTION */
diff --git a/drivers/mmc/core/crypto.c b/drivers/mmc/core/crypto.c
index fec4fbf16a5b64..efc1aa6d155794 100644
--- a/drivers/mmc/core/crypto.c
+++ b/drivers/mmc/core/crypto.c
@@ -6,6 +6,7 @@
*/
#include <linux/blk-crypto.h>
+#include <linux/blk-crypto-profile.h>
#include <linux/mmc/host.h>
#include "core.h"
@@ -16,13 +17,13 @@ void mmc_crypto_set_initial_state(struct mmc_host *host)
{
/* Reset might clear all keys, so reprogram all the keys. */
if (host->caps2 & MMC_CAP2_CRYPTO)
- blk_crypto_reprogram_all_keys(&host->crypto_profile);
+ blk_crypto_reprogram_all_keys(host->crypto_profile);
}
void mmc_crypto_setup_queue(struct request_queue *q, struct mmc_host *host)
{
if (host->caps2 & MMC_CAP2_CRYPTO)
- blk_crypto_register(&host->crypto_profile, q);
+ blk_crypto_register(host->crypto_profile, q);
}
EXPORT_SYMBOL_GPL(mmc_crypto_setup_queue);
diff --git a/drivers/mmc/host/cqhci-crypto.c b/drivers/mmc/host/cqhci-crypto.c
index d5f4b6972f63e8..d24856afa38968 100644
--- a/drivers/mmc/host/cqhci-crypto.c
+++ b/drivers/mmc/host/cqhci-crypto.c
@@ -25,10 +25,7 @@ static const struct cqhci_crypto_alg_entry {
static inline struct cqhci_host *
cqhci_host_from_crypto_profile(struct blk_crypto_profile *profile)
{
- struct mmc_host *mmc =
- container_of(profile, struct mmc_host, crypto_profile);
-
- return mmc->cqe_private;
+ return profile->private;
}
static int cqhci_crypto_program_key(struct cqhci_host *cq_host,
@@ -169,8 +166,8 @@ int cqhci_crypto_init(struct cqhci_host *cq_host)
{
struct mmc_host *mmc = cq_host->mmc;
struct device *dev = mmc_dev(mmc);
- struct blk_crypto_profile *profile = &mmc->crypto_profile;
unsigned int num_keyslots;
+ struct blk_crypto_profile *profile;
unsigned int cap_idx;
enum blk_crypto_mode_num blk_mode_num;
unsigned int slot;
@@ -200,10 +197,13 @@ int cqhci_crypto_init(struct cqhci_host *cq_host)
*/
num_keyslots = cq_host->crypto_capabilities.config_count + 1;
- err = devm_blk_crypto_profile_init(dev, profile, num_keyslots);
- if (err)
+ profile = devm_blk_crypto_profile_alloc(dev, num_keyslots);
+ if (IS_ERR(profile)) {
+ err = PTR_ERR(profile);
goto out;
+ }
+ profile->private = cq_host;
profile->ll_ops = cqhci_crypto_ops;
profile->dev = dev;
@@ -235,6 +235,11 @@ int cqhci_crypto_init(struct cqhci_host *cq_host)
/* CQHCI crypto requires the use of 128-bit task descriptors. */
cq_host->caps |= CQHCI_TASK_DESC_SZ_128;
+ err = kobject_add(&profile->kobj, &dev->kobj, "crypto");
+ if (err)
+ goto out;
+
+ mmc->crypto_profile = profile;
return 0;
out:
diff --git a/drivers/mmc/host/cqhci-crypto.h b/drivers/mmc/host/cqhci-crypto.h
index d7fb084f563b0e..d6ffd6e94e4cac 100644
--- a/drivers/mmc/host/cqhci-crypto.h
+++ b/drivers/mmc/host/cqhci-crypto.h
@@ -9,6 +9,7 @@
#define LINUX_MMC_CQHCI_CRYPTO_H
#include <linux/mmc/host.h>
+#include <linux/blk-crypto.h>
#include "cqhci.h"
diff --git a/drivers/scsi/ufs/ufshcd-crypto.c b/drivers/scsi/ufs/ufshcd-crypto.c
index 67402baf6faee8..b3c0e2890c7c1c 100644
--- a/drivers/scsi/ufs/ufshcd-crypto.c
+++ b/drivers/scsi/ufs/ufshcd-crypto.c
@@ -17,6 +17,12 @@ static const struct ufs_crypto_alg_entry {
},
};
+static inline struct ufs_hba *
+ufs_hba_from_crypto_profile(struct blk_crypto_profile *profile)
+{
+ return profile->private;
+}
+
static int ufshcd_program_key(struct ufs_hba *hba,
const union ufs_crypto_cfg_entry *cfg, int slot)
{
@@ -52,8 +58,7 @@ static int ufshcd_crypto_keyslot_program(struct blk_crypto_profile *profile,
const struct blk_crypto_key *key,
unsigned int slot)
{
- struct ufs_hba *hba =
- container_of(profile, struct ufs_hba, crypto_profile);
+ struct ufs_hba *hba = ufs_hba_from_crypto_profile(profile);
const union ufs_crypto_cap_entry *ccap_array = hba->crypto_cap_array;
const struct ufs_crypto_alg_entry *alg =
&ufs_crypto_algs[key->crypto_cfg.crypto_mode];
@@ -110,8 +115,7 @@ static int ufshcd_crypto_keyslot_evict(struct blk_crypto_profile *profile,
const struct blk_crypto_key *key,
unsigned int slot)
{
- struct ufs_hba *hba =
- container_of(profile, struct ufs_hba, crypto_profile);
+ struct ufs_hba *hba = ufs_hba_from_crypto_profile(profile);
return ufshcd_clear_keyslot(hba, slot);
}
@@ -122,7 +126,7 @@ bool ufshcd_crypto_enable(struct ufs_hba *hba)
return false;
/* Reset might clear all keys, so reprogram all the keys. */
- blk_crypto_reprogram_all_keys(&hba->crypto_profile);
+ blk_crypto_reprogram_all_keys(hba->crypto_profile);
return true;
}
@@ -155,6 +159,7 @@ ufshcd_find_blk_crypto_mode(union ufs_crypto_cap_entry cap)
*/
int ufshcd_hba_init_crypto_capabilities(struct ufs_hba *hba)
{
+ struct blk_crypto_profile *profile;
int cap_idx;
int err = 0;
enum blk_crypto_mode_num blk_mode_num;
@@ -181,16 +186,18 @@ int ufshcd_hba_init_crypto_capabilities(struct ufs_hba *hba)
}
/* The actual number of configurations supported is (CFGC+1) */
- err = devm_blk_crypto_profile_init(
- hba->dev, &hba->crypto_profile,
- hba->crypto_capabilities.config_count + 1);
- if (err)
+ profile = devm_blk_crypto_profile_alloc(
+ hba->dev, hba->crypto_capabilities.config_count + 1);
+ if (IS_ERR(profile)) {
+ err = PTR_ERR(profile);
goto out;
+ }
- hba->crypto_profile.ll_ops = ufshcd_crypto_ops;
+ profile->private = hba;
+ profile->ll_ops = ufshcd_crypto_ops;
/* UFS only supports 8 bytes for any DUN */
- hba->crypto_profile.max_dun_bytes_supported = 8;
- hba->crypto_profile.dev = hba->dev;
+ profile->max_dun_bytes_supported = 8;
+ profile->dev = hba->dev;
/*
* Cache all the UFS crypto capabilities and advertise the supported
@@ -205,10 +212,15 @@ int ufshcd_hba_init_crypto_capabilities(struct ufs_hba *hba)
blk_mode_num = ufshcd_find_blk_crypto_mode(
hba->crypto_cap_array[cap_idx]);
if (blk_mode_num != BLK_ENCRYPTION_MODE_INVALID)
- hba->crypto_profile.modes_supported[blk_mode_num] |=
+ profile->modes_supported[blk_mode_num] |=
hba->crypto_cap_array[cap_idx].sdus_mask * 512;
}
+ err = kobject_add(&profile->kobj, &hba->dev->kobj, "crypto");
+ if (err)
+ goto out;
+
+ hba->crypto_profile = profile;
return 0;
out:
@@ -236,5 +248,5 @@ void ufshcd_init_crypto(struct ufs_hba *hba)
void ufshcd_crypto_register(struct ufs_hba *hba, struct request_queue *q)
{
if (hba->caps & UFSHCD_CAP_CRYPTO)
- blk_crypto_register(&hba->crypto_profile, q);
+ blk_crypto_register(hba->crypto_profile, q);
}
diff --git a/drivers/scsi/ufs/ufshcd-crypto.h b/drivers/scsi/ufs/ufshcd-crypto.h
index e18c0127687320..6c6178ac6d4071 100644
--- a/drivers/scsi/ufs/ufshcd-crypto.h
+++ b/drivers/scsi/ufs/ufshcd-crypto.h
@@ -7,6 +7,8 @@
#define _UFSHCD_CRYPTO_H
#ifdef CONFIG_SCSI_UFS_CRYPTO
+#include <linux/blk-crypto-profile.h>
+
#include "ufshcd.h"
#include "ufshci.h"
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 54750d72c8fb09..b698b7bc2f9b55 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -32,7 +32,6 @@
#include <linux/regulator/consumer.h>
#include <linux/bitfield.h>
#include <linux/devfreq.h>
-#include <linux/blk-crypto-profile.h>
#include "unipro.h"
#include <asm/irq.h>
@@ -931,7 +930,7 @@ struct ufs_hba {
union ufs_crypto_capabilities crypto_capabilities;
union ufs_crypto_cap_entry *crypto_cap_array;
u32 crypto_cfg_register;
- struct blk_crypto_profile crypto_profile;
+ struct blk_crypto_profile *crypto_profile;
#endif
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_root;
diff --git a/include/linux/blk-crypto-profile.h b/include/linux/blk-crypto-profile.h
index bbab65bd54288d..42e6d1d0876924 100644
--- a/include/linux/blk-crypto-profile.h
+++ b/include/linux/blk-crypto-profile.h
@@ -59,6 +59,14 @@ struct blk_crypto_ll_ops {
unsigned int slot);
};
+struct blk_crypto_keyslot {
+ atomic_t slot_refs;
+ struct list_head idle_slot_node;
+ struct hlist_node hash_node;
+ const struct blk_crypto_key *key;
+ struct blk_crypto_profile *profile;
+};
+
/**
* struct blk_crypto_profile - inline encryption profile for a device
*
@@ -71,6 +79,9 @@ struct blk_crypto_profile {
/* public: Drivers must initialize the following fields. */
+ /** @private: Driver private data */
+ void *private;
+
/**
* @ll_ops: Driver-provided functions to control the inline encryption
* hardware, e.g. program and evict keys.
@@ -102,6 +113,8 @@ struct blk_crypto_profile {
/* private: The following fields shouldn't be accessed by drivers. */
+ struct kobject kobj;
+
/* Number of keyslots, or 0 if not applicable */
unsigned int num_slots;
@@ -126,15 +139,13 @@ struct blk_crypto_profile {
unsigned int log_slot_ht_size;
/* Per-keyslot data */
- struct blk_crypto_keyslot *slots;
+ struct blk_crypto_keyslot slots[];
};
-int blk_crypto_profile_init(struct blk_crypto_profile *profile,
- unsigned int num_slots);
+struct blk_crypto_profile *blk_crypto_profile_alloc(unsigned int num_slots);
-int devm_blk_crypto_profile_init(struct device *dev,
- struct blk_crypto_profile *profile,
- unsigned int num_slots);
+struct blk_crypto_profile *
+devm_blk_crypto_profile_alloc(struct device *dev, unsigned int num_slots);
unsigned int blk_crypto_keyslot_index(struct blk_crypto_keyslot *slot);
@@ -152,7 +163,9 @@ int __blk_crypto_evict_key(struct blk_crypto_profile *profile,
void blk_crypto_reprogram_all_keys(struct blk_crypto_profile *profile);
-void blk_crypto_profile_destroy(struct blk_crypto_profile *profile);
+void blk_crypto_profile_free(struct blk_crypto_profile *profile);
+
+void blk_crypto_profile_put(struct blk_crypto_profile *profile);
void blk_crypto_intersect_capabilities(struct blk_crypto_profile *parent,
const struct blk_crypto_profile *child);
diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h
index a7df155ea49b8c..d8c7de33e32738 100644
--- a/include/linux/device-mapper.h
+++ b/include/linux/device-mapper.h
@@ -575,11 +575,6 @@ void dm_table_run_md_queue_async(struct dm_table *t);
struct dm_table *dm_swap_table(struct mapped_device *md,
struct dm_table *t);
-/*
- * Table blk_crypto_profile functions
- */
-void dm_destroy_crypto_profile(struct blk_crypto_profile *profile);
-
/*-----------------------------------------------------------------
* Macros.
*---------------------------------------------------------------*/
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 7afb57cab00b79..15a17ececda02d 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -15,7 +15,6 @@
#include <linux/mmc/card.h>
#include <linux/mmc/pm.h>
#include <linux/dma-direction.h>
-#include <linux/blk-crypto-profile.h>
struct mmc_ios {
unsigned int clock; /* clock rate */
@@ -495,7 +494,7 @@ struct mmc_host {
/* Inline encryption support */
#ifdef CONFIG_MMC_CRYPTO
- struct blk_crypto_profile crypto_profile;
+ struct blk_crypto_profile *crypto_profile;
#endif
/* Host Software Queue support */