Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0
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
13struct blk_crypto_kobj {
14 struct kobject kobj;
15 struct blk_crypto_profile *profile;
16};
17
18struct blk_crypto_attr {
19 struct attribute attr;
20 ssize_t (*show)(struct blk_crypto_profile *profile,
21 struct blk_crypto_attr *attr, char *page);
22};
23
24static 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
29static struct blk_crypto_attr *attr_to_crypto_attr(struct attribute *attr)
30{
31 return container_of(attr, struct blk_crypto_attr, attr);
32}
33
34static ssize_t hw_wrapped_keys_show(struct blk_crypto_profile *profile,
35 struct blk_crypto_attr *attr, char *page)
36{
37 /* Always show supported, since the file doesn't exist otherwise. */
38 return sysfs_emit(page, "supported\n");
39}
40
41static ssize_t max_dun_bits_show(struct blk_crypto_profile *profile,
42 struct blk_crypto_attr *attr, char *page)
43{
44 return sysfs_emit(page, "%u\n", 8 * profile->max_dun_bytes_supported);
45}
46
47static ssize_t num_keyslots_show(struct blk_crypto_profile *profile,
48 struct blk_crypto_attr *attr, char *page)
49{
50 return sysfs_emit(page, "%u\n", profile->num_slots);
51}
52
53static ssize_t raw_keys_show(struct blk_crypto_profile *profile,
54 struct blk_crypto_attr *attr, char *page)
55{
56 /* Always show supported, since the file doesn't exist otherwise. */
57 return sysfs_emit(page, "supported\n");
58}
59
60#define BLK_CRYPTO_RO_ATTR(_name) \
61 static struct blk_crypto_attr _name##_attr = __ATTR_RO(_name)
62
63BLK_CRYPTO_RO_ATTR(hw_wrapped_keys);
64BLK_CRYPTO_RO_ATTR(max_dun_bits);
65BLK_CRYPTO_RO_ATTR(num_keyslots);
66BLK_CRYPTO_RO_ATTR(raw_keys);
67
68static umode_t blk_crypto_is_visible(struct kobject *kobj,
69 struct attribute *attr, int n)
70{
71 struct blk_crypto_profile *profile = kobj_to_crypto_profile(kobj);
72 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
84static struct attribute *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
92static const struct attribute_group blk_crypto_attr_group = {
93 .attrs = blk_crypto_attrs,
94 .is_visible = 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 */
101static struct blk_crypto_attr __blk_crypto_mode_attrs[BLK_ENCRYPTION_MODE_MAX];
102static struct attribute *blk_crypto_mode_attrs[BLK_ENCRYPTION_MODE_MAX + 1];
103
104static umode_t blk_crypto_mode_is_visible(struct kobject *kobj,
105 struct attribute *attr, int n)
106{
107 struct blk_crypto_profile *profile = kobj_to_crypto_profile(kobj);
108 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
116static ssize_t blk_crypto_mode_show(struct blk_crypto_profile *profile,
117 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
124static const struct attribute_group blk_crypto_modes_attr_group = {
125 .name = "modes",
126 .attrs = blk_crypto_mode_attrs,
127 .is_visible = blk_crypto_mode_is_visible,
128};
129
130static const struct attribute_group *blk_crypto_attr_groups[] = {
131 &blk_crypto_attr_group,
132 &blk_crypto_modes_attr_group,
133 NULL,
134};
135
136static 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 struct blk_crypto_attr *a = attr_to_crypto_attr(attr);
141
142 return a->show(profile, a, page);
143}
144
145static const struct sysfs_ops blk_crypto_attr_ops = {
146 .show = blk_crypto_attr_show,
147};
148
149static void blk_crypto_release(struct kobject *kobj)
150{
151 kfree(container_of(kobj, struct blk_crypto_kobj, kobj));
152}
153
154static 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 */
164int 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(sizeof(*obj), GFP_KERNEL);
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
188void blk_crypto_sysfs_unregister(struct gendisk *disk)
189{
190 kobject_put(disk->queue->crypto_kobject);
191}
192
193static 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}
208subsys_initcall(blk_crypto_sysfs_init);