OSDN Git Service

smb3: Add defines for new information level, FileIdInformation
[tomoyo/tomoyo-test1.git] / drivers / vfio / mdev / mdev_sysfs.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * File attributes for Mediated devices
4  *
5  * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
6  *     Author: Neo Jia <cjia@nvidia.com>
7  *             Kirti Wankhede <kwankhede@nvidia.com>
8  */
9
10 #include <linux/sysfs.h>
11 #include <linux/ctype.h>
12 #include <linux/device.h>
13 #include <linux/slab.h>
14 #include <linux/uuid.h>
15 #include <linux/mdev.h>
16
17 #include "mdev_private.h"
18
19 /* Static functions */
20
21 static ssize_t mdev_type_attr_show(struct kobject *kobj,
22                                      struct attribute *__attr, char *buf)
23 {
24         struct mdev_type_attribute *attr = to_mdev_type_attr(__attr);
25         struct mdev_type *type = to_mdev_type(kobj);
26         ssize_t ret = -EIO;
27
28         if (attr->show)
29                 ret = attr->show(kobj, type->parent->dev, buf);
30         return ret;
31 }
32
33 static ssize_t mdev_type_attr_store(struct kobject *kobj,
34                                       struct attribute *__attr,
35                                       const char *buf, size_t count)
36 {
37         struct mdev_type_attribute *attr = to_mdev_type_attr(__attr);
38         struct mdev_type *type = to_mdev_type(kobj);
39         ssize_t ret = -EIO;
40
41         if (attr->store)
42                 ret = attr->store(&type->kobj, type->parent->dev, buf, count);
43         return ret;
44 }
45
46 static const struct sysfs_ops mdev_type_sysfs_ops = {
47         .show = mdev_type_attr_show,
48         .store = mdev_type_attr_store,
49 };
50
51 static ssize_t create_store(struct kobject *kobj, struct device *dev,
52                             const char *buf, size_t count)
53 {
54         char *str;
55         guid_t uuid;
56         int ret;
57
58         if ((count < UUID_STRING_LEN) || (count > UUID_STRING_LEN + 1))
59                 return -EINVAL;
60
61         str = kstrndup(buf, count, GFP_KERNEL);
62         if (!str)
63                 return -ENOMEM;
64
65         ret = guid_parse(str, &uuid);
66         kfree(str);
67         if (ret)
68                 return ret;
69
70         ret = mdev_device_create(kobj, dev, &uuid);
71         if (ret)
72                 return ret;
73
74         return count;
75 }
76
77 MDEV_TYPE_ATTR_WO(create);
78
79 static void mdev_type_release(struct kobject *kobj)
80 {
81         struct mdev_type *type = to_mdev_type(kobj);
82
83         pr_debug("Releasing group %s\n", kobj->name);
84         kfree(type);
85 }
86
87 static struct kobj_type mdev_type_ktype = {
88         .sysfs_ops = &mdev_type_sysfs_ops,
89         .release = mdev_type_release,
90 };
91
92 static struct mdev_type *add_mdev_supported_type(struct mdev_parent *parent,
93                                                  struct attribute_group *group)
94 {
95         struct mdev_type *type;
96         int ret;
97
98         if (!group->name) {
99                 pr_err("%s: Type name empty!\n", __func__);
100                 return ERR_PTR(-EINVAL);
101         }
102
103         type = kzalloc(sizeof(*type), GFP_KERNEL);
104         if (!type)
105                 return ERR_PTR(-ENOMEM);
106
107         type->kobj.kset = parent->mdev_types_kset;
108
109         ret = kobject_init_and_add(&type->kobj, &mdev_type_ktype, NULL,
110                                    "%s-%s", dev_driver_string(parent->dev),
111                                    group->name);
112         if (ret) {
113                 kfree(type);
114                 return ERR_PTR(ret);
115         }
116
117         ret = sysfs_create_file(&type->kobj, &mdev_type_attr_create.attr);
118         if (ret)
119                 goto attr_create_failed;
120
121         type->devices_kobj = kobject_create_and_add("devices", &type->kobj);
122         if (!type->devices_kobj) {
123                 ret = -ENOMEM;
124                 goto attr_devices_failed;
125         }
126
127         ret = sysfs_create_files(&type->kobj,
128                                  (const struct attribute **)group->attrs);
129         if (ret) {
130                 ret = -ENOMEM;
131                 goto attrs_failed;
132         }
133
134         type->group = group;
135         type->parent = parent;
136         return type;
137
138 attrs_failed:
139         kobject_put(type->devices_kobj);
140 attr_devices_failed:
141         sysfs_remove_file(&type->kobj, &mdev_type_attr_create.attr);
142 attr_create_failed:
143         kobject_del(&type->kobj);
144         kobject_put(&type->kobj);
145         return ERR_PTR(ret);
146 }
147
148 static void remove_mdev_supported_type(struct mdev_type *type)
149 {
150         sysfs_remove_files(&type->kobj,
151                            (const struct attribute **)type->group->attrs);
152         kobject_put(type->devices_kobj);
153         sysfs_remove_file(&type->kobj, &mdev_type_attr_create.attr);
154         kobject_del(&type->kobj);
155         kobject_put(&type->kobj);
156 }
157
158 static int add_mdev_supported_type_groups(struct mdev_parent *parent)
159 {
160         int i;
161
162         for (i = 0; parent->ops->supported_type_groups[i]; i++) {
163                 struct mdev_type *type;
164
165                 type = add_mdev_supported_type(parent,
166                                         parent->ops->supported_type_groups[i]);
167                 if (IS_ERR(type)) {
168                         struct mdev_type *ltype, *tmp;
169
170                         list_for_each_entry_safe(ltype, tmp, &parent->type_list,
171                                                   next) {
172                                 list_del(&ltype->next);
173                                 remove_mdev_supported_type(ltype);
174                         }
175                         return PTR_ERR(type);
176                 }
177                 list_add(&type->next, &parent->type_list);
178         }
179         return 0;
180 }
181
182 /* mdev sysfs functions */
183 void parent_remove_sysfs_files(struct mdev_parent *parent)
184 {
185         struct mdev_type *type, *tmp;
186
187         list_for_each_entry_safe(type, tmp, &parent->type_list, next) {
188                 list_del(&type->next);
189                 remove_mdev_supported_type(type);
190         }
191
192         sysfs_remove_groups(&parent->dev->kobj, parent->ops->dev_attr_groups);
193         kset_unregister(parent->mdev_types_kset);
194 }
195
196 int parent_create_sysfs_files(struct mdev_parent *parent)
197 {
198         int ret;
199
200         parent->mdev_types_kset = kset_create_and_add("mdev_supported_types",
201                                                NULL, &parent->dev->kobj);
202
203         if (!parent->mdev_types_kset)
204                 return -ENOMEM;
205
206         INIT_LIST_HEAD(&parent->type_list);
207
208         ret = sysfs_create_groups(&parent->dev->kobj,
209                                   parent->ops->dev_attr_groups);
210         if (ret)
211                 goto create_err;
212
213         ret = add_mdev_supported_type_groups(parent);
214         if (ret)
215                 sysfs_remove_groups(&parent->dev->kobj,
216                                     parent->ops->dev_attr_groups);
217         else
218                 return ret;
219
220 create_err:
221         kset_unregister(parent->mdev_types_kset);
222         return ret;
223 }
224
225 static ssize_t remove_store(struct device *dev, struct device_attribute *attr,
226                             const char *buf, size_t count)
227 {
228         unsigned long val;
229
230         if (kstrtoul(buf, 0, &val) < 0)
231                 return -EINVAL;
232
233         if (val && device_remove_file_self(dev, attr)) {
234                 int ret;
235
236                 ret = mdev_device_remove(dev);
237                 if (ret)
238                         return ret;
239         }
240
241         return count;
242 }
243
244 static DEVICE_ATTR_WO(remove);
245
246 static const struct attribute *mdev_device_attrs[] = {
247         &dev_attr_remove.attr,
248         NULL,
249 };
250
251 int  mdev_create_sysfs_files(struct device *dev, struct mdev_type *type)
252 {
253         int ret;
254
255         ret = sysfs_create_link(type->devices_kobj, &dev->kobj, dev_name(dev));
256         if (ret)
257                 return ret;
258
259         ret = sysfs_create_link(&dev->kobj, &type->kobj, "mdev_type");
260         if (ret)
261                 goto type_link_failed;
262
263         ret = sysfs_create_files(&dev->kobj, mdev_device_attrs);
264         if (ret)
265                 goto create_files_failed;
266
267         return ret;
268
269 create_files_failed:
270         sysfs_remove_link(&dev->kobj, "mdev_type");
271 type_link_failed:
272         sysfs_remove_link(type->devices_kobj, dev_name(dev));
273         return ret;
274 }
275
276 void mdev_remove_sysfs_files(struct device *dev, struct mdev_type *type)
277 {
278         sysfs_remove_files(&dev->kobj, mdev_device_attrs);
279         sysfs_remove_link(&dev->kobj, "mdev_type");
280         sysfs_remove_link(type->devices_kobj, dev_name(dev));
281 }