cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

mdev_sysfs.c (6537B)


      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
     21static 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(type, attr, buf);
     30	return ret;
     31}
     32
     33static 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, attr, buf, count);
     43	return ret;
     44}
     45
     46static const struct sysfs_ops mdev_type_sysfs_ops = {
     47	.show = mdev_type_attr_show,
     48	.store = mdev_type_attr_store,
     49};
     50
     51static ssize_t create_store(struct mdev_type *mtype,
     52			    struct mdev_type_attribute *attr, const char *buf,
     53			    size_t count)
     54{
     55	char *str;
     56	guid_t uuid;
     57	int ret;
     58
     59	if ((count < UUID_STRING_LEN) || (count > UUID_STRING_LEN + 1))
     60		return -EINVAL;
     61
     62	str = kstrndup(buf, count, GFP_KERNEL);
     63	if (!str)
     64		return -ENOMEM;
     65
     66	ret = guid_parse(str, &uuid);
     67	kfree(str);
     68	if (ret)
     69		return ret;
     70
     71	ret = mdev_device_create(mtype, &uuid);
     72	if (ret)
     73		return ret;
     74
     75	return count;
     76}
     77
     78static MDEV_TYPE_ATTR_WO(create);
     79
     80static void mdev_type_release(struct kobject *kobj)
     81{
     82	struct mdev_type *type = to_mdev_type(kobj);
     83
     84	pr_debug("Releasing group %s\n", kobj->name);
     85	/* Pairs with the get in add_mdev_supported_type() */
     86	mdev_put_parent(type->parent);
     87	kfree(type);
     88}
     89
     90static struct kobj_type mdev_type_ktype = {
     91	.sysfs_ops = &mdev_type_sysfs_ops,
     92	.release = mdev_type_release,
     93};
     94
     95static struct mdev_type *add_mdev_supported_type(struct mdev_parent *parent,
     96						 unsigned int type_group_id)
     97{
     98	struct mdev_type *type;
     99	struct attribute_group *group =
    100		parent->mdev_driver->supported_type_groups[type_group_id];
    101	int ret;
    102
    103	if (!group->name) {
    104		pr_err("%s: Type name empty!\n", __func__);
    105		return ERR_PTR(-EINVAL);
    106	}
    107
    108	type = kzalloc(sizeof(*type), GFP_KERNEL);
    109	if (!type)
    110		return ERR_PTR(-ENOMEM);
    111
    112	type->kobj.kset = parent->mdev_types_kset;
    113	type->parent = parent;
    114	/* Pairs with the put in mdev_type_release() */
    115	mdev_get_parent(parent);
    116	type->type_group_id = type_group_id;
    117
    118	ret = kobject_init_and_add(&type->kobj, &mdev_type_ktype, NULL,
    119				   "%s-%s", dev_driver_string(parent->dev),
    120				   group->name);
    121	if (ret) {
    122		kobject_put(&type->kobj);
    123		return ERR_PTR(ret);
    124	}
    125
    126	ret = sysfs_create_file(&type->kobj, &mdev_type_attr_create.attr);
    127	if (ret)
    128		goto attr_create_failed;
    129
    130	type->devices_kobj = kobject_create_and_add("devices", &type->kobj);
    131	if (!type->devices_kobj) {
    132		ret = -ENOMEM;
    133		goto attr_devices_failed;
    134	}
    135
    136	ret = sysfs_create_files(&type->kobj,
    137				 (const struct attribute **)group->attrs);
    138	if (ret) {
    139		ret = -ENOMEM;
    140		goto attrs_failed;
    141	}
    142	return type;
    143
    144attrs_failed:
    145	kobject_put(type->devices_kobj);
    146attr_devices_failed:
    147	sysfs_remove_file(&type->kobj, &mdev_type_attr_create.attr);
    148attr_create_failed:
    149	kobject_del(&type->kobj);
    150	kobject_put(&type->kobj);
    151	return ERR_PTR(ret);
    152}
    153
    154static void remove_mdev_supported_type(struct mdev_type *type)
    155{
    156	struct attribute_group *group =
    157		type->parent->mdev_driver->supported_type_groups[type->type_group_id];
    158
    159	sysfs_remove_files(&type->kobj,
    160			   (const struct attribute **)group->attrs);
    161	kobject_put(type->devices_kobj);
    162	sysfs_remove_file(&type->kobj, &mdev_type_attr_create.attr);
    163	kobject_del(&type->kobj);
    164	kobject_put(&type->kobj);
    165}
    166
    167static int add_mdev_supported_type_groups(struct mdev_parent *parent)
    168{
    169	int i;
    170
    171	for (i = 0; parent->mdev_driver->supported_type_groups[i]; i++) {
    172		struct mdev_type *type;
    173
    174		type = add_mdev_supported_type(parent, i);
    175		if (IS_ERR(type)) {
    176			struct mdev_type *ltype, *tmp;
    177
    178			list_for_each_entry_safe(ltype, tmp, &parent->type_list,
    179						  next) {
    180				list_del(&ltype->next);
    181				remove_mdev_supported_type(ltype);
    182			}
    183			return PTR_ERR(type);
    184		}
    185		list_add(&type->next, &parent->type_list);
    186	}
    187	return 0;
    188}
    189
    190/* mdev sysfs functions */
    191void parent_remove_sysfs_files(struct mdev_parent *parent)
    192{
    193	struct mdev_type *type, *tmp;
    194
    195	list_for_each_entry_safe(type, tmp, &parent->type_list, next) {
    196		list_del(&type->next);
    197		remove_mdev_supported_type(type);
    198	}
    199
    200	kset_unregister(parent->mdev_types_kset);
    201}
    202
    203int parent_create_sysfs_files(struct mdev_parent *parent)
    204{
    205	int ret;
    206
    207	parent->mdev_types_kset = kset_create_and_add("mdev_supported_types",
    208					       NULL, &parent->dev->kobj);
    209
    210	if (!parent->mdev_types_kset)
    211		return -ENOMEM;
    212
    213	INIT_LIST_HEAD(&parent->type_list);
    214
    215	ret = add_mdev_supported_type_groups(parent);
    216	if (ret)
    217		goto create_err;
    218	return 0;
    219
    220create_err:
    221	kset_unregister(parent->mdev_types_kset);
    222	return ret;
    223}
    224
    225static ssize_t remove_store(struct device *dev, struct device_attribute *attr,
    226			    const char *buf, size_t count)
    227{
    228	struct mdev_device *mdev = to_mdev_device(dev);
    229	unsigned long val;
    230
    231	if (kstrtoul(buf, 0, &val) < 0)
    232		return -EINVAL;
    233
    234	if (val && device_remove_file_self(dev, attr)) {
    235		int ret;
    236
    237		ret = mdev_device_remove(mdev);
    238		if (ret)
    239			return ret;
    240	}
    241
    242	return count;
    243}
    244
    245static DEVICE_ATTR_WO(remove);
    246
    247static struct attribute *mdev_device_attrs[] = {
    248	&dev_attr_remove.attr,
    249	NULL,
    250};
    251
    252static const struct attribute_group mdev_device_group = {
    253	.attrs = mdev_device_attrs,
    254};
    255
    256const struct attribute_group *mdev_device_groups[] = {
    257	&mdev_device_group,
    258	NULL
    259};
    260
    261int mdev_create_sysfs_files(struct mdev_device *mdev)
    262{
    263	struct mdev_type *type = mdev->type;
    264	struct kobject *kobj = &mdev->dev.kobj;
    265	int ret;
    266
    267	ret = sysfs_create_link(type->devices_kobj, kobj, dev_name(&mdev->dev));
    268	if (ret)
    269		return ret;
    270
    271	ret = sysfs_create_link(kobj, &type->kobj, "mdev_type");
    272	if (ret)
    273		goto type_link_failed;
    274	return ret;
    275
    276type_link_failed:
    277	sysfs_remove_link(mdev->type->devices_kobj, dev_name(&mdev->dev));
    278	return ret;
    279}
    280
    281void mdev_remove_sysfs_files(struct mdev_device *mdev)
    282{
    283	struct kobject *kobj = &mdev->dev.kobj;
    284
    285	sysfs_remove_link(kobj, "mdev_type");
    286	sysfs_remove_link(mdev->type->devices_kobj, dev_name(&mdev->dev));
    287}