Commit 0b60f9ead5d4816e7e3d6e28f4a0d22d4a1b2513

Authored by Tejun Heo
Committed by Greg Kroah-Hartman
1 parent ac0ece9174

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

arch/s390/include/asm/ccwgroup.h
... ... @@ -23,6 +23,7 @@
23 23 unsigned int count;
24 24 struct device dev;
25 25 struct ccw_device *cdev[0];
  26 + struct work_struct ungroup_work;
26 27 };
27 28  
28 29 /**
arch/s390/pci/pci_sysfs.c
... ... @@ -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  
drivers/s390/block/dcssblk.c
... ... @@ -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;
drivers/s390/cio/ccwgroup.c
... ... @@ -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 }