Commit 0b60f9ead5d4816e7e3d6e28f4a0d22d4a1b2513
s390: use device_remove_file_self() instead of device_schedule_callback()
driver-core now supports synchrnous self-deletion of attributes and the asynchrnous removal mechanism is scheduled for removal. Use it instead of device_schedule_callback(). * Conversions in arch/s390/pci/pci_sysfs.c and drivers/s390/block/dcssblk.c are straightforward. * drivers/s390/cio/ccwgroup.c is a bit more tricky because ccwgroup_notifier() was (ab)using device_schedule_callback() to purely obtain a process context to kick off ungroup operation which may block from a notifier callback. Rename ccwgroup_ungroup_callback() to ccwgroup_ungroup() and make it take ccwgroup_device * instead. The new function is now called directly from ccwgroup_ungroup_store(). ccwgroup_notifier() chain is updated to explicitly bounce through ccwgroup_device->ungroup_work. This also removes possible failure from memory pressure. Only compile-tested. Signed-off-by: Tejun Heo <tj@kernel.org> Cc: Martin Schwidefsky <schwidefsky@de.ibm.com> Cc: Heiko Carstens <heiko.carstens@de.ibm.com> Cc: linux390@de.ibm.com Cc: linux-s390@vger.kernel.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Showing 4 changed files with 32 additions and 27 deletions Side-by-side Diff
... | ... | @@ -48,29 +48,27 @@ |
48 | 48 | } |
49 | 49 | static DEVICE_ATTR(pfgid, S_IRUGO, show_pfgid, NULL); |
50 | 50 | |
51 | -static void recover_callback(struct device *dev) | |
51 | +static ssize_t store_recover(struct device *dev, struct device_attribute *attr, | |
52 | + const char *buf, size_t count) | |
52 | 53 | { |
53 | 54 | struct pci_dev *pdev = to_pci_dev(dev); |
54 | 55 | struct zpci_dev *zdev = get_zdev(pdev); |
55 | 56 | int ret; |
56 | 57 | |
58 | + if (!device_remove_file_self(dev, attr)) | |
59 | + return count; | |
60 | + | |
57 | 61 | pci_stop_and_remove_bus_device(pdev); |
58 | 62 | ret = zpci_disable_device(zdev); |
59 | 63 | if (ret) |
60 | - return; | |
64 | + return ret; | |
61 | 65 | |
62 | 66 | ret = zpci_enable_device(zdev); |
63 | 67 | if (ret) |
64 | - return; | |
68 | + return ret; | |
65 | 69 | |
66 | 70 | pci_rescan_bus(zdev->bus); |
67 | -} | |
68 | - | |
69 | -static ssize_t store_recover(struct device *dev, struct device_attribute *attr, | |
70 | - const char *buf, size_t count) | |
71 | -{ | |
72 | - int rc = device_schedule_callback(dev, recover_callback); | |
73 | - return rc ? rc : count; | |
71 | + return count; | |
74 | 72 | } |
75 | 73 | static DEVICE_ATTR(recover, S_IWUSR, NULL, store_recover); |
76 | 74 |
... | ... | @@ -304,12 +304,6 @@ |
304 | 304 | return rc; |
305 | 305 | } |
306 | 306 | |
307 | -static void dcssblk_unregister_callback(struct device *dev) | |
308 | -{ | |
309 | - device_unregister(dev); | |
310 | - put_device(dev); | |
311 | -} | |
312 | - | |
313 | 307 | /* |
314 | 308 | * device attribute for switching shared/nonshared (exclusive) |
315 | 309 | * operation (show + store) |
... | ... | @@ -397,7 +391,13 @@ |
397 | 391 | blk_cleanup_queue(dev_info->dcssblk_queue); |
398 | 392 | dev_info->gd->queue = NULL; |
399 | 393 | put_disk(dev_info->gd); |
400 | - rc = device_schedule_callback(dev, dcssblk_unregister_callback); | |
394 | + up_write(&dcssblk_devices_sem); | |
395 | + | |
396 | + if (device_remove_file_self(dev, attr)) { | |
397 | + device_unregister(dev); | |
398 | + put_device(dev); | |
399 | + } | |
400 | + return rc; | |
401 | 401 | out: |
402 | 402 | up_write(&dcssblk_devices_sem); |
403 | 403 | return rc; |
... | ... | @@ -168,14 +168,12 @@ |
168 | 168 | * Provide an 'ungroup' attribute so the user can remove group devices no |
169 | 169 | * longer needed or accidentially created. Saves memory :) |
170 | 170 | */ |
171 | -static void ccwgroup_ungroup_callback(struct device *dev) | |
171 | +static void ccwgroup_ungroup(struct ccwgroup_device *gdev) | |
172 | 172 | { |
173 | - struct ccwgroup_device *gdev = to_ccwgroupdev(dev); | |
174 | - | |
175 | 173 | mutex_lock(&gdev->reg_mutex); |
176 | 174 | if (device_is_registered(&gdev->dev)) { |
177 | 175 | __ccwgroup_remove_symlinks(gdev); |
178 | - device_unregister(dev); | |
176 | + device_unregister(&gdev->dev); | |
179 | 177 | __ccwgroup_remove_cdev_refs(gdev); |
180 | 178 | } |
181 | 179 | mutex_unlock(&gdev->reg_mutex); |
... | ... | @@ -195,10 +193,9 @@ |
195 | 193 | rc = -EINVAL; |
196 | 194 | goto out; |
197 | 195 | } |
198 | - /* Note that we cannot unregister the device from one of its | |
199 | - * attribute methods, so we have to use this roundabout approach. | |
200 | - */ | |
201 | - rc = device_schedule_callback(dev, ccwgroup_ungroup_callback); | |
196 | + | |
197 | + if (device_remove_file_self(dev, attr)) | |
198 | + ccwgroup_ungroup(gdev); | |
202 | 199 | out: |
203 | 200 | if (rc) { |
204 | 201 | if (rc != -EAGAIN) |
... | ... | @@ -224,6 +221,14 @@ |
224 | 221 | NULL, |
225 | 222 | }; |
226 | 223 | |
224 | +static void ccwgroup_ungroup_workfn(struct work_struct *work) | |
225 | +{ | |
226 | + struct ccwgroup_device *gdev = | |
227 | + container_of(work, struct ccwgroup_device, ungroup_work); | |
228 | + | |
229 | + ccwgroup_ungroup(gdev); | |
230 | +} | |
231 | + | |
227 | 232 | static void ccwgroup_release(struct device *dev) |
228 | 233 | { |
229 | 234 | kfree(to_ccwgroupdev(dev)); |
... | ... | @@ -323,6 +328,7 @@ |
323 | 328 | atomic_set(&gdev->onoff, 0); |
324 | 329 | mutex_init(&gdev->reg_mutex); |
325 | 330 | mutex_lock(&gdev->reg_mutex); |
331 | + INIT_WORK(&gdev->ungroup_work, ccwgroup_ungroup_workfn); | |
326 | 332 | gdev->count = num_devices; |
327 | 333 | gdev->dev.bus = &ccwgroup_bus_type; |
328 | 334 | gdev->dev.parent = parent; |
329 | 335 | |
... | ... | @@ -404,10 +410,10 @@ |
404 | 410 | static int ccwgroup_notifier(struct notifier_block *nb, unsigned long action, |
405 | 411 | void *data) |
406 | 412 | { |
407 | - struct device *dev = data; | |
413 | + struct ccwgroup_device *gdev = to_ccwgroupdev(data); | |
408 | 414 | |
409 | 415 | if (action == BUS_NOTIFY_UNBIND_DRIVER) |
410 | - device_schedule_callback(dev, ccwgroup_ungroup_callback); | |
416 | + schedule_work(&gdev->ungroup_work); | |
411 | 417 | |
412 | 418 | return NOTIFY_OK; |
413 | 419 | } |
-
mentioned in commit 9280dd
-
mentioned in commit 0310c8
-
mentioned in commit 9280dd
-
mentioned in commit 0310c8
-
mentioned in commit 9280dd
-
mentioned in commit 0310c8
-
mentioned in commit 9280dd
-
mentioned in commit 0310c8
-
mentioned in commit 9280dd
-
mentioned in commit 0310c8
-
mentioned in commit 9280dd
-
mentioned in commit 0310c8
-
mentioned in commit 9280dd
-
mentioned in commit 0310c8
-
mentioned in commit 9280dd
-
mentioned in commit 0310c8
-
mentioned in commit 9280dd
-
mentioned in commit 0310c8
-
mentioned in commit 9280dd
-
mentioned in commit 0310c8
-
mentioned in commit 9280dd
-
mentioned in commit 0310c8
-
mentioned in commit 9280dd
-
mentioned in commit 0310c8
-
mentioned in commit 9280dd
-
mentioned in commit 0310c8