|
@@ -66,34 +66,6 @@ uuid_le mdev_uuid(struct mdev_device *mdev)
|
|
|
}
|
|
|
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)
|
|
|
{
|
|
@@ -221,7 +193,6 @@ int mdev_register_device(struct device *dev, const struct mdev_parent_ops *ops)
|
|
|
}
|
|
|
|
|
|
kref_init(&parent->ref);
|
|
|
- mutex_init(&parent->lock);
|
|
|
|
|
|
parent->dev = dev;
|
|
|
parent->ops = ops;
|
|
@@ -297,6 +268,10 @@ static void mdev_device_release(struct device *dev)
|
|
|
{
|
|
|
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);
|
|
|
}
|
|
@@ -304,7 +279,7 @@ static void mdev_device_release(struct device *dev)
|
|
|
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);
|
|
|
|
|
@@ -312,21 +287,28 @@ int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid)
|
|
|
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);
|
|
|
|
|
@@ -338,35 +320,28 @@ int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid)
|
|
|
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;
|
|
|
}
|
|
@@ -377,44 +352,39 @@ int mdev_device_remove(struct device *dev, bool force_remove)
|
|
|
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;
|