Commit 197cec28 authored by Julian Wiedmann's avatar Julian Wiedmann Committed by Vasily Gorbik

s390/ccwgroup: release the cdevs from within dev->release()

Wiring up the cdevs is an essential part of the gdev creation. So
release them during the gdev destruction, ie. on the last put_device().
This could cause us to hold on to the cdevs a tiny bit longer, but
that's not a real concern.

As we have much less certainty of what context this put_device() is
executed from, switch to irqsave locking.
Signed-off-by: default avatarJulian Wiedmann <jwi@linux.ibm.com>
Signed-off-by: default avatarVasily Gorbik <gor@linux.ibm.com>
parent 95c09f03
...@@ -45,27 +45,6 @@ static void __ccwgroup_remove_symlinks(struct ccwgroup_device *gdev) ...@@ -45,27 +45,6 @@ static void __ccwgroup_remove_symlinks(struct ccwgroup_device *gdev)
} }
} }
/*
* Remove references from ccw devices to ccw group device and from
* ccw group device to ccw devices.
*/
static void __ccwgroup_remove_cdev_refs(struct ccwgroup_device *gdev)
{
struct ccw_device *cdev;
int i;
for (i = 0; i < gdev->count; i++) {
cdev = gdev->cdev[i];
if (!cdev)
continue;
spin_lock_irq(cdev->ccwlock);
dev_set_drvdata(&cdev->dev, NULL);
spin_unlock_irq(cdev->ccwlock);
gdev->cdev[i] = NULL;
put_device(&cdev->dev);
}
}
/** /**
* ccwgroup_set_online() - enable a ccwgroup device * ccwgroup_set_online() - enable a ccwgroup device
* @gdev: target ccwgroup device * @gdev: target ccwgroup device
...@@ -175,7 +154,6 @@ static void ccwgroup_ungroup(struct ccwgroup_device *gdev) ...@@ -175,7 +154,6 @@ static void ccwgroup_ungroup(struct ccwgroup_device *gdev)
if (device_is_registered(&gdev->dev)) { if (device_is_registered(&gdev->dev)) {
__ccwgroup_remove_symlinks(gdev); __ccwgroup_remove_symlinks(gdev);
device_unregister(&gdev->dev); device_unregister(&gdev->dev);
__ccwgroup_remove_cdev_refs(gdev);
} }
mutex_unlock(&gdev->reg_mutex); mutex_unlock(&gdev->reg_mutex);
} }
...@@ -228,7 +206,23 @@ static void ccwgroup_ungroup_workfn(struct work_struct *work) ...@@ -228,7 +206,23 @@ static void ccwgroup_ungroup_workfn(struct work_struct *work)
static void ccwgroup_release(struct device *dev) static void ccwgroup_release(struct device *dev)
{ {
kfree(to_ccwgroupdev(dev)); struct ccwgroup_device *gdev = to_ccwgroupdev(dev);
unsigned int i;
for (i = 0; i < gdev->count; i++) {
struct ccw_device *cdev = gdev->cdev[i];
unsigned long flags;
if (cdev) {
spin_lock_irqsave(cdev->ccwlock, flags);
if (dev_get_drvdata(&cdev->dev) == gdev)
dev_set_drvdata(&cdev->dev, NULL);
spin_unlock_irqrestore(cdev->ccwlock, flags);
put_device(&cdev->dev);
}
}
kfree(gdev);
} }
static int __ccwgroup_create_symlinks(struct ccwgroup_device *gdev) static int __ccwgroup_create_symlinks(struct ccwgroup_device *gdev)
...@@ -396,15 +390,6 @@ int ccwgroup_create_dev(struct device *parent, struct ccwgroup_driver *gdrv, ...@@ -396,15 +390,6 @@ int ccwgroup_create_dev(struct device *parent, struct ccwgroup_driver *gdrv,
mutex_unlock(&gdev->reg_mutex); mutex_unlock(&gdev->reg_mutex);
return 0; return 0;
error: error:
for (i = 0; i < num_devices; i++)
if (gdev->cdev[i]) {
spin_lock_irq(gdev->cdev[i]->ccwlock);
if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev)
dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
spin_unlock_irq(gdev->cdev[i]->ccwlock);
put_device(&gdev->cdev[i]->dev);
gdev->cdev[i] = NULL;
}
mutex_unlock(&gdev->reg_mutex); mutex_unlock(&gdev->reg_mutex);
put_device(&gdev->dev); put_device(&gdev->dev);
return rc; return rc;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment