root/drivers/vfio/mdev/mdev_sysfs.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mdev_type_attr_show
  2. mdev_type_attr_store
  3. create_store
  4. mdev_type_release
  5. add_mdev_supported_type
  6. remove_mdev_supported_type
  7. add_mdev_supported_type_groups
  8. parent_remove_sysfs_files
  9. parent_create_sysfs_files
  10. remove_store
  11. mdev_create_sysfs_files
  12. mdev_remove_sysfs_files

   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 }

/* [<][>][^][v][top][bottom][index][help] */