summaryrefslogtreecommitdiff
path: root/drivers/s390/cio
diff options
context:
space:
mode:
authorJulian Wiedmann <jwi@linux.ibm.com>2021-04-24 12:12:38 +0200
committerVasily Gorbik <gor@linux.ibm.com>2021-06-07 17:06:59 +0200
commit197cec2853cb112e7a5c2adeccf4d2b09e7a36e2 (patch)
treeb90bad5b4222e30f685091c2db7ee583a2692ef1 /drivers/s390/cio
parent95c09f0344f1dd9206f105b211c36476a7301b07 (diff)
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: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Diffstat (limited to 'drivers/s390/cio')
-rw-r--r--drivers/s390/cio/ccwgroup.c49
1 files changed, 17 insertions, 32 deletions
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index 444385da5792..49f816c78873 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -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
* @gdev: target ccwgroup device
@@ -175,7 +154,6 @@ static void ccwgroup_ungroup(struct ccwgroup_device *gdev)
if (device_is_registered(&gdev->dev)) {
__ccwgroup_remove_symlinks(gdev);
device_unregister(&gdev->dev);
- __ccwgroup_remove_cdev_refs(gdev);
}
mutex_unlock(&gdev->reg_mutex);
}
@@ -228,7 +206,23 @@ static void ccwgroup_ungroup_workfn(struct work_struct *work)
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)
@@ -396,15 +390,6 @@ int ccwgroup_create_dev(struct device *parent, struct ccwgroup_driver *gdrv,
mutex_unlock(&gdev->reg_mutex);
return 0;
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);
put_device(&gdev->dev);
return rc;