Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * File attributes for Mediated devices
0004  *
0005  * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
0006  *     Author: Neo Jia <cjia@nvidia.com>
0007  *             Kirti Wankhede <kwankhede@nvidia.com>
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 /* Static functions */
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     /* Pairs with the get in add_mdev_supported_type() */
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     /* Pairs with the put in mdev_type_release() */
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(&ltype->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 /* mdev sysfs functions */
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 }