[S390] cio: ccwgroup register vs. unregister.
Introduce a mutex for struct ccwgroup to prevent simuntaneous register/unregister on the same ccwgroup device. Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
parent
82b7ac058f
commit
d76123eb35
|
@ -75,8 +75,10 @@ static void ccwgroup_ungroup_callback(struct device *dev)
|
||||||
{
|
{
|
||||||
struct ccwgroup_device *gdev = to_ccwgroupdev(dev);
|
struct ccwgroup_device *gdev = to_ccwgroupdev(dev);
|
||||||
|
|
||||||
|
mutex_lock(&gdev->reg_mutex);
|
||||||
__ccwgroup_remove_symlinks(gdev);
|
__ccwgroup_remove_symlinks(gdev);
|
||||||
device_unregister(dev);
|
device_unregister(dev);
|
||||||
|
mutex_unlock(&gdev->reg_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t
|
static ssize_t
|
||||||
|
@ -173,7 +175,8 @@ ccwgroup_create(struct device *root,
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
atomic_set(&gdev->onoff, 0);
|
atomic_set(&gdev->onoff, 0);
|
||||||
|
mutex_init(&gdev->reg_mutex);
|
||||||
|
mutex_lock(&gdev->reg_mutex);
|
||||||
for (i = 0; i < argc; i++) {
|
for (i = 0; i < argc; i++) {
|
||||||
gdev->cdev[i] = get_ccwdev_by_busid(cdrv, argv[i]);
|
gdev->cdev[i] = get_ccwdev_by_busid(cdrv, argv[i]);
|
||||||
|
|
||||||
|
@ -183,12 +186,12 @@ ccwgroup_create(struct device *root,
|
||||||
|| gdev->cdev[i]->id.driver_info !=
|
|| gdev->cdev[i]->id.driver_info !=
|
||||||
gdev->cdev[0]->id.driver_info) {
|
gdev->cdev[0]->id.driver_info) {
|
||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
goto free_dev;
|
goto error;
|
||||||
}
|
}
|
||||||
/* Don't allow a device to belong to more than one group. */
|
/* Don't allow a device to belong to more than one group. */
|
||||||
if (gdev->cdev[i]->dev.driver_data) {
|
if (gdev->cdev[i]->dev.driver_data) {
|
||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
goto free_dev;
|
goto error;
|
||||||
}
|
}
|
||||||
gdev->cdev[i]->dev.driver_data = gdev;
|
gdev->cdev[i]->dev.driver_data = gdev;
|
||||||
}
|
}
|
||||||
|
@ -203,9 +206,8 @@ ccwgroup_create(struct device *root,
|
||||||
gdev->cdev[0]->dev.bus_id);
|
gdev->cdev[0]->dev.bus_id);
|
||||||
|
|
||||||
rc = device_register(&gdev->dev);
|
rc = device_register(&gdev->dev);
|
||||||
|
|
||||||
if (rc)
|
if (rc)
|
||||||
goto free_dev;
|
goto error;
|
||||||
get_device(&gdev->dev);
|
get_device(&gdev->dev);
|
||||||
rc = device_create_file(&gdev->dev, &dev_attr_ungroup);
|
rc = device_create_file(&gdev->dev, &dev_attr_ungroup);
|
||||||
|
|
||||||
|
@ -216,27 +218,21 @@ ccwgroup_create(struct device *root,
|
||||||
|
|
||||||
rc = __ccwgroup_create_symlinks(gdev);
|
rc = __ccwgroup_create_symlinks(gdev);
|
||||||
if (!rc) {
|
if (!rc) {
|
||||||
|
mutex_unlock(&gdev->reg_mutex);
|
||||||
put_device(&gdev->dev);
|
put_device(&gdev->dev);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
device_remove_file(&gdev->dev, &dev_attr_ungroup);
|
device_remove_file(&gdev->dev, &dev_attr_ungroup);
|
||||||
device_unregister(&gdev->dev);
|
device_unregister(&gdev->dev);
|
||||||
error:
|
error:
|
||||||
for (i = 0; i < argc; i++)
|
|
||||||
if (gdev->cdev[i]) {
|
|
||||||
put_device(&gdev->cdev[i]->dev);
|
|
||||||
gdev->cdev[i]->dev.driver_data = NULL;
|
|
||||||
}
|
|
||||||
put_device(&gdev->dev);
|
|
||||||
return rc;
|
|
||||||
free_dev:
|
|
||||||
for (i = 0; i < argc; i++)
|
for (i = 0; i < argc; i++)
|
||||||
if (gdev->cdev[i]) {
|
if (gdev->cdev[i]) {
|
||||||
if (gdev->cdev[i]->dev.driver_data == gdev)
|
if (gdev->cdev[i]->dev.driver_data == gdev)
|
||||||
gdev->cdev[i]->dev.driver_data = NULL;
|
gdev->cdev[i]->dev.driver_data = NULL;
|
||||||
put_device(&gdev->cdev[i]->dev);
|
put_device(&gdev->cdev[i]->dev);
|
||||||
}
|
}
|
||||||
kfree(gdev);
|
mutex_unlock(&gdev->reg_mutex);
|
||||||
|
put_device(&gdev->dev);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -422,8 +418,12 @@ ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver)
|
||||||
get_driver(&cdriver->driver);
|
get_driver(&cdriver->driver);
|
||||||
while ((dev = driver_find_device(&cdriver->driver, NULL, NULL,
|
while ((dev = driver_find_device(&cdriver->driver, NULL, NULL,
|
||||||
__ccwgroup_match_all))) {
|
__ccwgroup_match_all))) {
|
||||||
__ccwgroup_remove_symlinks(to_ccwgroupdev(dev));
|
struct ccwgroup_device *gdev = to_ccwgroupdev(dev);
|
||||||
|
|
||||||
|
mutex_lock(&gdev->reg_mutex);
|
||||||
|
__ccwgroup_remove_symlinks(gdev);
|
||||||
device_unregister(dev);
|
device_unregister(dev);
|
||||||
|
mutex_unlock(&gdev->reg_mutex);
|
||||||
put_device(dev);
|
put_device(dev);
|
||||||
}
|
}
|
||||||
put_driver(&cdriver->driver);
|
put_driver(&cdriver->driver);
|
||||||
|
@ -444,8 +444,10 @@ __ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev)
|
||||||
if (cdev->dev.driver_data) {
|
if (cdev->dev.driver_data) {
|
||||||
gdev = (struct ccwgroup_device *)cdev->dev.driver_data;
|
gdev = (struct ccwgroup_device *)cdev->dev.driver_data;
|
||||||
if (get_device(&gdev->dev)) {
|
if (get_device(&gdev->dev)) {
|
||||||
|
mutex_lock(&gdev->reg_mutex);
|
||||||
if (device_is_registered(&gdev->dev))
|
if (device_is_registered(&gdev->dev))
|
||||||
return gdev;
|
return gdev;
|
||||||
|
mutex_unlock(&gdev->reg_mutex);
|
||||||
put_device(&gdev->dev);
|
put_device(&gdev->dev);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -465,6 +467,7 @@ ccwgroup_remove_ccwdev(struct ccw_device *cdev)
|
||||||
if (gdev) {
|
if (gdev) {
|
||||||
__ccwgroup_remove_symlinks(gdev);
|
__ccwgroup_remove_symlinks(gdev);
|
||||||
device_unregister(&gdev->dev);
|
device_unregister(&gdev->dev);
|
||||||
|
mutex_unlock(&gdev->reg_mutex);
|
||||||
put_device(&gdev->dev);
|
put_device(&gdev->dev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ struct ccwgroup_device {
|
||||||
CCWGROUP_ONLINE,
|
CCWGROUP_ONLINE,
|
||||||
} state;
|
} state;
|
||||||
atomic_t onoff;
|
atomic_t onoff;
|
||||||
|
struct mutex reg_mutex;
|
||||||
unsigned int count; /* number of attached slave devices */
|
unsigned int count; /* number of attached slave devices */
|
||||||
struct device dev; /* master device */
|
struct device dev; /* master device */
|
||||||
struct ccw_device *cdev[0]; /* variable number, allocate as needed */
|
struct ccw_device *cdev[0]; /* variable number, allocate as needed */
|
||||||
|
|
Loading…
Reference in New Issue