aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
authorSebastian Ott <sebott@linux.vnet.ibm.com>2014-06-13 11:02:24 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2014-06-16 04:32:24 -0400
commit9280ddb19489fa24e2d4f6f492d185ae1172bec2 (patch)
tree7146a4e9891ae8d38f3741664e387bdd03e35ea3 /drivers/s390
parent613c4e0459603cc04384723b08fd62103b5eaaaf (diff)
s390/ccwgroup: obtain extra reference for asynchronous processing
Commit 0b60f9ead5d4816e7e3d6e28f4a0d22d4a1b2513 "s390: use device_remove_file_self() instead of device_schedule_callback()" changed ccwgroup to use an extra work queue instead of device_schedule_callback. This function obtained an extra device reference for its async work which is missing in the new implementation and results in a "freeing memory with a lock still held" BUG. Fix this by obtaining an extra reference for the async work. Reported-by: Stefan Raspl <raspl@linux.vnet.ibm.com> Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/cio/ccwgroup.c5
1 files changed, 4 insertions, 1 deletions
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index dfd7bc681c25..040e643746aa 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -227,6 +227,7 @@ static void ccwgroup_ungroup_workfn(struct work_struct *work)
227 container_of(work, struct ccwgroup_device, ungroup_work); 227 container_of(work, struct ccwgroup_device, ungroup_work);
228 228
229 ccwgroup_ungroup(gdev); 229 ccwgroup_ungroup(gdev);
230 put_device(&gdev->dev);
230} 231}
231 232
232static void ccwgroup_release(struct device *dev) 233static void ccwgroup_release(struct device *dev)
@@ -412,8 +413,10 @@ static int ccwgroup_notifier(struct notifier_block *nb, unsigned long action,
412{ 413{
413 struct ccwgroup_device *gdev = to_ccwgroupdev(data); 414 struct ccwgroup_device *gdev = to_ccwgroupdev(data);
414 415
415 if (action == BUS_NOTIFY_UNBIND_DRIVER) 416 if (action == BUS_NOTIFY_UNBIND_DRIVER) {
417 get_device(&gdev->dev);
416 schedule_work(&gdev->ungroup_work); 418 schedule_work(&gdev->ungroup_work);
419 }
417 420
418 return NOTIFY_OK; 421 return NOTIFY_OK;
419} 422}