0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/sysfs.h>
0011 #include <linux/ctype.h>
0012 #include <linux/device.h>
0013 #include <linux/slab.h>
0014 #include <linux/uuid.h>
0015 #include <linux/mdev.h>
0016
0017 #include "mdev_private.h"
0018
0019
0020
0021 static ssize_t mdev_type_attr_show(struct kobject *kobj,
0022 struct attribute *__attr, char *buf)
0023 {
0024 struct mdev_type_attribute *attr = to_mdev_type_attr(__attr);
0025 struct mdev_type *type = to_mdev_type(kobj);
0026 ssize_t ret = -EIO;
0027
0028 if (attr->show)
0029 ret = attr->show(type, attr, buf);
0030 return ret;
0031 }
0032
0033 static ssize_t mdev_type_attr_store(struct kobject *kobj,
0034 struct attribute *__attr,
0035 const char *buf, size_t count)
0036 {
0037 struct mdev_type_attribute *attr = to_mdev_type_attr(__attr);
0038 struct mdev_type *type = to_mdev_type(kobj);
0039 ssize_t ret = -EIO;
0040
0041 if (attr->store)
0042 ret = attr->store(type, attr, buf, count);
0043 return ret;
0044 }
0045
0046 static const struct sysfs_ops mdev_type_sysfs_ops = {
0047 .show = mdev_type_attr_show,
0048 .store = mdev_type_attr_store,
0049 };
0050
0051 static ssize_t create_store(struct mdev_type *mtype,
0052 struct mdev_type_attribute *attr, const char *buf,
0053 size_t count)
0054 {
0055 char *str;
0056 guid_t uuid;
0057 int ret;
0058
0059 if ((count < UUID_STRING_LEN) || (count > UUID_STRING_LEN + 1))
0060 return -EINVAL;
0061
0062 str = kstrndup(buf, count, GFP_KERNEL);
0063 if (!str)
0064 return -ENOMEM;
0065
0066 ret = guid_parse(str, &uuid);
0067 kfree(str);
0068 if (ret)
0069 return ret;
0070
0071 ret = mdev_device_create(mtype, &uuid);
0072 if (ret)
0073 return ret;
0074
0075 return count;
0076 }
0077
0078 static MDEV_TYPE_ATTR_WO(create);
0079
0080 static void mdev_type_release(struct kobject *kobj)
0081 {
0082 struct mdev_type *type = to_mdev_type(kobj);
0083
0084 pr_debug("Releasing group %s\n", kobj->name);
0085
0086 mdev_put_parent(type->parent);
0087 kfree(type);
0088 }
0089
0090 static struct kobj_type mdev_type_ktype = {
0091 .sysfs_ops = &mdev_type_sysfs_ops,
0092 .release = mdev_type_release,
0093 };
0094
0095 static struct mdev_type *add_mdev_supported_type(struct mdev_parent *parent,
0096 unsigned int type_group_id)
0097 {
0098 struct mdev_type *type;
0099 struct attribute_group *group =
0100 parent->mdev_driver->supported_type_groups[type_group_id];
0101 int ret;
0102
0103 if (!group->name) {
0104 pr_err("%s: Type name empty!\n", __func__);
0105 return ERR_PTR(-EINVAL);
0106 }
0107
0108 type = kzalloc(sizeof(*type), GFP_KERNEL);
0109 if (!type)
0110 return ERR_PTR(-ENOMEM);
0111
0112 type->kobj.kset = parent->mdev_types_kset;
0113 type->parent = parent;
0114
0115 mdev_get_parent(parent);
0116 type->type_group_id = type_group_id;
0117
0118 ret = kobject_init_and_add(&type->kobj, &mdev_type_ktype, NULL,
0119 "%s-%s", dev_driver_string(parent->dev),
0120 group->name);
0121 if (ret) {
0122 kobject_put(&type->kobj);
0123 return ERR_PTR(ret);
0124 }
0125
0126 ret = sysfs_create_file(&type->kobj, &mdev_type_attr_create.attr);
0127 if (ret)
0128 goto attr_create_failed;
0129
0130 type->devices_kobj = kobject_create_and_add("devices", &type->kobj);
0131 if (!type->devices_kobj) {
0132 ret = -ENOMEM;
0133 goto attr_devices_failed;
0134 }
0135
0136 ret = sysfs_create_files(&type->kobj,
0137 (const struct attribute **)group->attrs);
0138 if (ret) {
0139 ret = -ENOMEM;
0140 goto attrs_failed;
0141 }
0142 return type;
0143
0144 attrs_failed:
0145 kobject_put(type->devices_kobj);
0146 attr_devices_failed:
0147 sysfs_remove_file(&type->kobj, &mdev_type_attr_create.attr);
0148 attr_create_failed:
0149 kobject_del(&type->kobj);
0150 kobject_put(&type->kobj);
0151 return ERR_PTR(ret);
0152 }
0153
0154 static void remove_mdev_supported_type(struct mdev_type *type)
0155 {
0156 struct attribute_group *group =
0157 type->parent->mdev_driver->supported_type_groups[type->type_group_id];
0158
0159 sysfs_remove_files(&type->kobj,
0160 (const struct attribute **)group->attrs);
0161 kobject_put(type->devices_kobj);
0162 sysfs_remove_file(&type->kobj, &mdev_type_attr_create.attr);
0163 kobject_del(&type->kobj);
0164 kobject_put(&type->kobj);
0165 }
0166
0167 static int add_mdev_supported_type_groups(struct mdev_parent *parent)
0168 {
0169 int i;
0170
0171 for (i = 0; parent->mdev_driver->supported_type_groups[i]; i++) {
0172 struct mdev_type *type;
0173
0174 type = add_mdev_supported_type(parent, i);
0175 if (IS_ERR(type)) {
0176 struct mdev_type *ltype, *tmp;
0177
0178 list_for_each_entry_safe(ltype, tmp, &parent->type_list,
0179 next) {
0180 list_del(<ype->next);
0181 remove_mdev_supported_type(ltype);
0182 }
0183 return PTR_ERR(type);
0184 }
0185 list_add(&type->next, &parent->type_list);
0186 }
0187 return 0;
0188 }
0189
0190
0191 void parent_remove_sysfs_files(struct mdev_parent *parent)
0192 {
0193 struct mdev_type *type, *tmp;
0194
0195 list_for_each_entry_safe(type, tmp, &parent->type_list, next) {
0196 list_del(&type->next);
0197 remove_mdev_supported_type(type);
0198 }
0199
0200 kset_unregister(parent->mdev_types_kset);
0201 }
0202
0203 int parent_create_sysfs_files(struct mdev_parent *parent)
0204 {
0205 int ret;
0206
0207 parent->mdev_types_kset = kset_create_and_add("mdev_supported_types",
0208 NULL, &parent->dev->kobj);
0209
0210 if (!parent->mdev_types_kset)
0211 return -ENOMEM;
0212
0213 INIT_LIST_HEAD(&parent->type_list);
0214
0215 ret = add_mdev_supported_type_groups(parent);
0216 if (ret)
0217 goto create_err;
0218 return 0;
0219
0220 create_err:
0221 kset_unregister(parent->mdev_types_kset);
0222 return ret;
0223 }
0224
0225 static ssize_t remove_store(struct device *dev, struct device_attribute *attr,
0226 const char *buf, size_t count)
0227 {
0228 struct mdev_device *mdev = to_mdev_device(dev);
0229 unsigned long val;
0230
0231 if (kstrtoul(buf, 0, &val) < 0)
0232 return -EINVAL;
0233
0234 if (val && device_remove_file_self(dev, attr)) {
0235 int ret;
0236
0237 ret = mdev_device_remove(mdev);
0238 if (ret)
0239 return ret;
0240 }
0241
0242 return count;
0243 }
0244
0245 static DEVICE_ATTR_WO(remove);
0246
0247 static struct attribute *mdev_device_attrs[] = {
0248 &dev_attr_remove.attr,
0249 NULL,
0250 };
0251
0252 static const struct attribute_group mdev_device_group = {
0253 .attrs = mdev_device_attrs,
0254 };
0255
0256 const struct attribute_group *mdev_device_groups[] = {
0257 &mdev_device_group,
0258 NULL
0259 };
0260
0261 int mdev_create_sysfs_files(struct mdev_device *mdev)
0262 {
0263 struct mdev_type *type = mdev->type;
0264 struct kobject *kobj = &mdev->dev.kobj;
0265 int ret;
0266
0267 ret = sysfs_create_link(type->devices_kobj, kobj, dev_name(&mdev->dev));
0268 if (ret)
0269 return ret;
0270
0271 ret = sysfs_create_link(kobj, &type->kobj, "mdev_type");
0272 if (ret)
0273 goto type_link_failed;
0274 return ret;
0275
0276 type_link_failed:
0277 sysfs_remove_link(mdev->type->devices_kobj, dev_name(&mdev->dev));
0278 return ret;
0279 }
0280
0281 void mdev_remove_sysfs_files(struct mdev_device *mdev)
0282 {
0283 struct kobject *kobj = &mdev->dev.kobj;
0284
0285 sysfs_remove_link(kobj, "mdev_type");
0286 sysfs_remove_link(mdev->type->devices_kobj, dev_name(&mdev->dev));
0287 }