}
EXPORT_SYMBOL(mdev_uuid);
-static int _find_mdev_device(struct device *dev, void *data)
-{
- struct mdev_device *mdev;
-
- if (!dev_is_mdev(dev))
- return 0;
-
- mdev = to_mdev_device(dev);
-
- if (uuid_le_cmp(mdev->uuid, *(uuid_le *)data) == 0)
- return 1;
-
- return 0;
-}
-
-static bool mdev_device_exist(struct mdev_parent *parent, uuid_le uuid)
-{
- struct device *dev;
-
- dev = device_find_child(parent->dev, &uuid, _find_mdev_device);
- if (dev) {
- put_device(dev);
- return true;
- }
-
- return false;
-}
-
/* Should be called holding parent_list_lock */
static struct mdev_parent *__find_parent_device(struct device *dev)
{
}
kref_init(&parent->ref);
- mutex_init(&parent->lock);
parent->dev = dev;
parent->ops = ops;
{
struct mdev_device *mdev = to_mdev_device(dev);
+ mutex_lock(&mdev_list_lock);
+ list_del(&mdev->next);
+ mutex_unlock(&mdev_list_lock);
+
dev_dbg(&mdev->dev, "MDEV: destroying\n");
kfree(mdev);
}
int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid)
{
int ret;
- struct mdev_device *mdev;
+ struct mdev_device *mdev, *tmp;
struct mdev_parent *parent;
struct mdev_type *type = to_mdev_type(kobj);
if (!parent)
return -EINVAL;
- mutex_lock(&parent->lock);
+ mutex_lock(&mdev_list_lock);
/* Check for duplicate */
- if (mdev_device_exist(parent, uuid)) {
- ret = -EEXIST;
- goto create_err;
+ list_for_each_entry(tmp, &mdev_list, next) {
+ if (!uuid_le_cmp(tmp->uuid, uuid)) {
+ mutex_unlock(&mdev_list_lock);
+ ret = -EEXIST;
+ goto mdev_fail;
+ }
}
mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
if (!mdev) {
+ mutex_unlock(&mdev_list_lock);
ret = -ENOMEM;
- goto create_err;
+ goto mdev_fail;
}
memcpy(&mdev->uuid, &uuid, sizeof(uuid_le));
+ list_add(&mdev->next, &mdev_list);
+ mutex_unlock(&mdev_list_lock);
+
mdev->parent = parent;
kref_init(&mdev->ref);
ret = device_register(&mdev->dev);
if (ret) {
put_device(&mdev->dev);
- goto create_err;
+ goto mdev_fail;
}
ret = mdev_device_create_ops(kobj, mdev);
if (ret)
- goto create_failed;
+ goto create_fail;
ret = mdev_create_sysfs_files(&mdev->dev, type);
if (ret) {
mdev_device_remove_ops(mdev, true);
- goto create_failed;
+ goto create_fail;
}
mdev->type_kobj = kobj;
+ mdev->active = true;
dev_dbg(&mdev->dev, "MDEV: created\n");
- mutex_unlock(&parent->lock);
-
- mutex_lock(&mdev_list_lock);
- list_add(&mdev->next, &mdev_list);
- mutex_unlock(&mdev_list_lock);
-
- return ret;
+ return 0;
-create_failed:
+create_fail:
device_unregister(&mdev->dev);
-
-create_err:
- mutex_unlock(&parent->lock);
+mdev_fail:
mdev_put_parent(parent);
return ret;
}
struct mdev_parent *parent;
struct mdev_type *type;
int ret;
- bool found = false;
mdev = to_mdev_device(dev);
mutex_lock(&mdev_list_lock);
list_for_each_entry(tmp, &mdev_list, next) {
- if (tmp == mdev) {
- found = true;
+ if (tmp == mdev)
break;
- }
}
- if (found)
- list_del(&mdev->next);
+ if (tmp != mdev) {
+ mutex_unlock(&mdev_list_lock);
+ return -ENODEV;
+ }
- mutex_unlock(&mdev_list_lock);
+ if (!mdev->active) {
+ mutex_unlock(&mdev_list_lock);
+ return -EAGAIN;
+ }
- if (!found)
- return -ENODEV;
+ mdev->active = false;
+ mutex_unlock(&mdev_list_lock);
type = to_mdev_type(mdev->type_kobj);
parent = mdev->parent;
- mutex_lock(&parent->lock);
ret = mdev_device_remove_ops(mdev, force_remove);
if (ret) {
- mutex_unlock(&parent->lock);
-
- mutex_lock(&mdev_list_lock);
- list_add(&mdev->next, &mdev_list);
- mutex_unlock(&mdev_list_lock);
-
+ mdev->active = true;
return ret;
}
mdev_remove_sysfs_files(dev, type);
device_unregister(dev);
- mutex_unlock(&parent->lock);
mdev_put_parent(parent);
return 0;