| 1 | |
| 2 | |
| 3 | * Copyright 2021 Google LLC
|
| 4 | *
|
| 5 | * sysfs support for blk-crypto. This file contains the code which exports the
|
| 6 | * crypto capabilities of devices via /sys/block/$disk/queue/crypto/.
|
| 7 |
|
| 8 |
|
| 9 | #include <linux/blk-crypto-profile.h>
|
| 10 |
|
| 11 | #include "blk-crypto-internal.h"
|
| 12 |
|
| 13 | struct blk_crypto_kobj {
|
| 14 | struct kobject kobj;
|
| 15 | struct blk_crypto_profile *profile;
|
| 16 | };
|
| 17 |
|
| 18 | struct blk_crypto_attr {
|
| 19 | struct attribute attr;
|
| 20 | ssize_t (*show)(struct blk_crypto_profile *profile,
|
| 21 | const struct blk_crypto_attr *attr, char *page);
|
| 22 | };
|
| 23 |
|
| 24 | static struct blk_crypto_profile *kobj_to_crypto_profile(struct kobject *kobj)
|
| 25 | {
|
| 26 | return container_of(kobj, struct blk_crypto_kobj, kobj)->profile;
|
| 27 | }
|
| 28 |
|
| 29 | static const struct blk_crypto_attr *attr_to_crypto_attr(const struct attribute *attr)
|
| 30 | {
|
| 31 | return container_of_const(attr, struct blk_crypto_attr, attr);
|
| 32 | }
|
| 33 |
|
| 34 | static ssize_t hw_wrapped_keys_show(struct blk_crypto_profile *profile,
|
| 35 | const struct blk_crypto_attr *attr, char *page)
|
| 36 | {
|
| 37 |
|
| 38 | return sysfs_emit(page, "supported\n");
|
| 39 | }
|
| 40 |
|
| 41 | static ssize_t max_dun_bits_show(struct blk_crypto_profile *profile,
|
| 42 | const struct blk_crypto_attr *attr, char *page)
|
| 43 | {
|
| 44 | return sysfs_emit(page, "%u\n", 8 * profile->max_dun_bytes_supported);
|
| 45 | }
|
| 46 |
|
| 47 | static ssize_t num_keyslots_show(struct blk_crypto_profile *profile,
|
| 48 | const struct blk_crypto_attr *attr, char *page)
|
| 49 | {
|
| 50 | return sysfs_emit(page, "%u\n", profile->num_slots);
|
| 51 | }
|
| 52 |
|
| 53 | static ssize_t raw_keys_show(struct blk_crypto_profile *profile,
|
| 54 | const struct blk_crypto_attr *attr, char *page)
|
| 55 | {
|
| 56 |
|
| 57 | return sysfs_emit(page, "supported\n");
|
| 58 | }
|
| 59 |
|
| 60 | #define BLK_CRYPTO_RO_ATTR(_name) \
|
| 61 | static const struct blk_crypto_attr _name##_attr = __ATTR_RO(_name)
|
| 62 |
|
| 63 | BLK_CRYPTO_RO_ATTR(hw_wrapped_keys);
|
| 64 | BLK_CRYPTO_RO_ATTR(max_dun_bits);
|
| 65 | BLK_CRYPTO_RO_ATTR(num_keyslots);
|
| 66 | BLK_CRYPTO_RO_ATTR(raw_keys);
|
| 67 |
|
| 68 | static umode_t blk_crypto_is_visible(struct kobject *kobj,
|
| 69 | const struct attribute *attr, int n)
|
| 70 | {
|
| 71 | struct blk_crypto_profile *profile = kobj_to_crypto_profile(kobj);
|
| 72 | const struct blk_crypto_attr *a = attr_to_crypto_attr(attr);
|
| 73 |
|
| 74 | if (a == &hw_wrapped_keys_attr &&
|
| 75 | !(profile->key_types_supported & BLK_CRYPTO_KEY_TYPE_HW_WRAPPED))
|
| 76 | return 0;
|
| 77 | if (a == &raw_keys_attr &&
|
| 78 | !(profile->key_types_supported & BLK_CRYPTO_KEY_TYPE_RAW))
|
| 79 | return 0;
|
| 80 |
|
| 81 | return 0444;
|
| 82 | }
|
| 83 |
|
| 84 | static const struct attribute *const blk_crypto_attrs[] = {
|
| 85 | &hw_wrapped_keys_attr.attr,
|
| 86 | &max_dun_bits_attr.attr,
|
| 87 | &num_keyslots_attr.attr,
|
| 88 | &raw_keys_attr.attr,
|
| 89 | NULL,
|
| 90 | };
|
| 91 |
|
| 92 | static const struct attribute_group blk_crypto_attr_group = {
|
| 93 | .attrs_const = blk_crypto_attrs,
|
| 94 | .is_visible_const = blk_crypto_is_visible,
|
| 95 | };
|
| 96 |
|
| 97 | |
| 98 | * The encryption mode attributes. To avoid hard-coding the list of encryption
|
| 99 | * modes, these are initialized at boot time by blk_crypto_sysfs_init().
|
| 100 |
|
| 101 | static struct blk_crypto_attr __blk_crypto_mode_attrs[BLK_ENCRYPTION_MODE_MAX];
|
| 102 | static const struct attribute *blk_crypto_mode_attrs[BLK_ENCRYPTION_MODE_MAX + 1];
|
| 103 |
|
| 104 | static umode_t blk_crypto_mode_is_visible(struct kobject *kobj,
|
| 105 | const struct attribute *attr, int n)
|
| 106 | {
|
| 107 | struct blk_crypto_profile *profile = kobj_to_crypto_profile(kobj);
|
| 108 | const struct blk_crypto_attr *a = attr_to_crypto_attr(attr);
|
| 109 | int mode_num = a - __blk_crypto_mode_attrs;
|
| 110 |
|
| 111 | if (profile->modes_supported[mode_num])
|
| 112 | return 0444;
|
| 113 | return 0;
|
| 114 | }
|
| 115 |
|
| 116 | static ssize_t blk_crypto_mode_show(struct blk_crypto_profile *profile,
|
| 117 | const struct blk_crypto_attr *attr, char *page)
|
| 118 | {
|
| 119 | int mode_num = attr - __blk_crypto_mode_attrs;
|
| 120 |
|
| 121 | return sysfs_emit(page, "0x%x\n", profile->modes_supported[mode_num]);
|
| 122 | }
|
| 123 |
|
| 124 | static const struct attribute_group blk_crypto_modes_attr_group = {
|
| 125 | .name = "modes",
|
| 126 | .attrs_const = blk_crypto_mode_attrs,
|
| 127 | .is_visible_const = blk_crypto_mode_is_visible,
|
| 128 | };
|
| 129 |
|
| 130 | static const struct attribute_group *blk_crypto_attr_groups[] = {
|
| 131 | &blk_crypto_attr_group,
|
| 132 | &blk_crypto_modes_attr_group,
|
| 133 | NULL,
|
| 134 | };
|
| 135 |
|
| 136 | static ssize_t blk_crypto_attr_show(struct kobject *kobj,
|
| 137 | struct attribute *attr, char *page)
|
| 138 | {
|
| 139 | struct blk_crypto_profile *profile = kobj_to_crypto_profile(kobj);
|
| 140 | const struct blk_crypto_attr *a = attr_to_crypto_attr(attr);
|
| 141 |
|
| 142 | return a->show(profile, a, page);
|
| 143 | }
|
| 144 |
|
| 145 | static const struct sysfs_ops blk_crypto_attr_ops = {
|
| 146 | .show = blk_crypto_attr_show,
|
| 147 | };
|
| 148 |
|
| 149 | static void blk_crypto_release(struct kobject *kobj)
|
| 150 | {
|
| 151 | kfree(container_of(kobj, struct blk_crypto_kobj, kobj));
|
| 152 | }
|
| 153 |
|
| 154 | static const struct kobj_type blk_crypto_ktype = {
|
| 155 | .default_groups = blk_crypto_attr_groups,
|
| 156 | .sysfs_ops = &blk_crypto_attr_ops,
|
| 157 | .release = blk_crypto_release,
|
| 158 | };
|
| 159 |
|
| 160 | |
| 161 | * If the request_queue has a blk_crypto_profile, create the "crypto"
|
| 162 | * subdirectory in sysfs (/sys/block/$disk/queue/crypto/).
|
| 163 |
|
| 164 | int blk_crypto_sysfs_register(struct gendisk *disk)
|
| 165 | {
|
| 166 | struct request_queue *q = disk->queue;
|
| 167 | struct blk_crypto_kobj *obj;
|
| 168 | int err;
|
| 169 |
|
| 170 | if (!q->crypto_profile)
|
| 171 | return 0;
|
| 172 |
|
| 173 | obj = kzalloc_obj(*obj);
|
| 174 | if (!obj)
|
| 175 | return -ENOMEM;
|
| 176 | obj->profile = q->crypto_profile;
|
| 177 |
|
| 178 | err = kobject_init_and_add(&obj->kobj, &blk_crypto_ktype,
|
| 179 | &disk->queue_kobj, "crypto");
|
| 180 | if (err) {
|
| 181 | kobject_put(&obj->kobj);
|
| 182 | return err;
|
| 183 | }
|
| 184 | q->crypto_kobject = &obj->kobj;
|
| 185 | return 0;
|
| 186 | }
|
| 187 |
|
| 188 | void blk_crypto_sysfs_unregister(struct gendisk *disk)
|
| 189 | {
|
| 190 | kobject_put(disk->queue->crypto_kobject);
|
| 191 | }
|
| 192 |
|
| 193 | static int __init blk_crypto_sysfs_init(void)
|
| 194 | {
|
| 195 | int i;
|
| 196 |
|
| 197 | BUILD_BUG_ON(BLK_ENCRYPTION_MODE_INVALID != 0);
|
| 198 | for (i = 1; i < BLK_ENCRYPTION_MODE_MAX; i++) {
|
| 199 | struct blk_crypto_attr *attr = &__blk_crypto_mode_attrs[i];
|
| 200 |
|
| 201 | attr->attr.name = blk_crypto_modes[i].name;
|
| 202 | attr->attr.mode = 0444;
|
| 203 | attr->show = blk_crypto_mode_show;
|
| 204 | blk_crypto_mode_attrs[i - 1] = &attr->attr;
|
| 205 | }
|
| 206 | return 0;
|
| 207 | }
|
| 208 | subsys_initcall(blk_crypto_sysfs_init);
|