|
|
|
/*
|
|
|
|
* Mediated device interal definitions
|
|
|
|
*
|
|
|
|
* Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
|
|
|
|
* Author: Neo Jia <cjia@nvidia.com>
|
|
|
|
* Kirti Wankhede <kwankhede@nvidia.com>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
|
|
* published by the Free Software Foundation.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef MDEV_PRIVATE_H
|
|
|
|
#define MDEV_PRIVATE_H
|
|
|
|
|
|
|
|
int mdev_bus_register(void);
|
|
|
|
void mdev_bus_unregister(void);
|
|
|
|
|
|
|
|
struct mdev_parent {
|
|
|
|
struct device *dev;
|
|
|
|
const struct mdev_parent_ops *ops;
|
|
|
|
struct kref ref;
|
|
|
|
struct list_head next;
|
|
|
|
struct kset *mdev_types_kset;
|
|
|
|
struct list_head type_list;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct mdev_device {
|
|
|
|
struct device dev;
|
|
|
|
struct mdev_parent *parent;
|
|
|
|
uuid_le uuid;
|
|
|
|
void *driver_data;
|
|
|
|
struct kref ref;
|
|
|
|
struct list_head next;
|
|
|
|
struct kobject *type_kobj;
|
vfio/mdev: Check globally for duplicate devices
[ Upstream commit 002fe996f67f4f46d8917b14cfb6e4313c20685a ]
When we create an mdev device, we check for duplicates against the
parent device and return -EEXIST if found, but the mdev device
namespace is global since we'll link all devices from the bus. We do
catch this later in sysfs_do_create_link_sd() to return -EEXIST, but
with it comes a kernel warning and stack trace for trying to create
duplicate sysfs links, which makes it an undesirable response.
Therefore we should really be looking for duplicates across all mdev
parent devices, or as implemented here, against our mdev device list.
Using mdev_list to prevent duplicates means that we can remove
mdev_parent.lock, but in order not to serialize mdev device creation
and removal globally, we add mdev_device.active which allows UUIDs to
be reserved such that we can drop the mdev_list_lock before the mdev
device is fully in place.
Two behavioral notes; first, mdev_parent.lock had the side-effect of
serializing mdev create and remove ops per parent device. This was
an implementation detail, not an intentional guarantee provided to
the mdev vendor drivers. Vendor drivers can trivially provide this
serialization internally if necessary. Second, review comments note
the new -EAGAIN behavior when the device, and in particular the remove
attribute, becomes visible in sysfs. If a remove is triggered prior
to completion of mdev_device_create() the user will see a -EAGAIN
error. While the errno is different, receiving an error during this
period is not, the previous implementation returned -ENODEV for the
same condition. Furthermore, the consistency to the user is improved
in the case where mdev_device_remove_ops() returns error. Previously
concurrent calls to mdev_device_remove() could see the device
disappear with -ENODEV and return in the case of error. Now a user
would see -EAGAIN while the device is in this transitory state.
Reviewed-by: Kirti Wankhede <kwankhede@nvidia.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Acked-by: Halil Pasic <pasic@linux.ibm.com>
Acked-by: Zhenyu Wang <zhenyuw@linux.intel.com>
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
7 years ago
|
|
|
bool active;
|
|
|
|
};
|
|
|
|
|
|
|
|
#define to_mdev_device(dev) container_of(dev, struct mdev_device, dev)
|
|
|
|
#define dev_is_mdev(d) ((d)->bus == &mdev_bus_type)
|
|
|
|
|
|
|
|
struct mdev_type {
|
|
|
|
struct kobject kobj;
|
|
|
|
struct kobject *devices_kobj;
|
|
|
|
struct mdev_parent *parent;
|
|
|
|
struct list_head next;
|
|
|
|
struct attribute_group *group;
|
|
|
|
};
|
|
|
|
|
|
|
|
#define to_mdev_type_attr(_attr) \
|
|
|
|
container_of(_attr, struct mdev_type_attribute, attr)
|
|
|
|
#define to_mdev_type(_kobj) \
|
|
|
|
container_of(_kobj, struct mdev_type, kobj)
|
|
|
|
|
|
|
|
int parent_create_sysfs_files(struct mdev_parent *parent);
|
|
|
|
void parent_remove_sysfs_files(struct mdev_parent *parent);
|
|
|
|
|
|
|
|
int mdev_create_sysfs_files(struct device *dev, struct mdev_type *type);
|
|
|
|
void mdev_remove_sysfs_files(struct device *dev, struct mdev_type *type);
|
|
|
|
|
|
|
|
int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid);
|
|
|
|
int mdev_device_remove(struct device *dev, bool force_remove);
|
|
|
|
|
|
|
|
#endif /* MDEV_PRIVATE_H */
|