Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

[PATCH] sysfs and driver core: add callback helper, used by SCSI and S390

This patch (as868) adds a helper routine for device drivers that need
to set up a callback to perform some action in a different process's
context. This is intended for use by attribute methods that want to
unregister themselves or their parent device. Attribute method calls
are mutually exclusive with unregistration, so such actions cannot be
taken directly.

Two attribute methods are converted to use the new helper routine: one
for SCSI device deletion and one for System/390 ccwgroup devices.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Cc: Hugh Dickins <hugh@veritas.com>
Cc: Cornelia Huck <cornelia.huck@de.ibm.com>
Cc: Oliver Neukum <oneukum@suse.de>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Alan Stern and committed by
Linus Torvalds
d9a9cdfb 6ab27c6b

+122 -4
+29
drivers/base/core.c
··· 407 407 } 408 408 EXPORT_SYMBOL_GPL(device_remove_bin_file); 409 409 410 + /** 411 + * device_schedule_callback - helper to schedule a callback for a device 412 + * @dev: device. 413 + * @func: callback function to invoke later. 414 + * 415 + * Attribute methods must not unregister themselves or their parent device 416 + * (which would amount to the same thing). Attempts to do so will deadlock, 417 + * since unregistration is mutually exclusive with driver callbacks. 418 + * 419 + * Instead methods can call this routine, which will attempt to allocate 420 + * and schedule a workqueue request to call back @func with @dev as its 421 + * argument in the workqueue's process context. @dev will be pinned until 422 + * @func returns. 423 + * 424 + * Returns 0 if the request was submitted, -ENOMEM if storage could not 425 + * be allocated. 426 + * 427 + * NOTE: This routine won't work if CONFIG_SYSFS isn't set! It uses an 428 + * underlying sysfs routine (since it is intended for use by attribute 429 + * methods), and if sysfs isn't available you'll get nothing but -ENOSYS. 430 + */ 431 + int device_schedule_callback(struct device *dev, 432 + void (*func)(struct device *)) 433 + { 434 + return sysfs_schedule_callback(&dev->kobj, 435 + (void (*)(void *)) func, dev); 436 + } 437 + EXPORT_SYMBOL_GPL(device_schedule_callback); 438 + 410 439 static void klist_children_get(struct klist_node *n) 411 440 { 412 441 struct device *dev = container_of(n, struct device, knode_parent);
+15 -3
drivers/s390/cio/ccwgroup.c
··· 71 71 * Provide an 'ungroup' attribute so the user can remove group devices no 72 72 * longer needed or accidentially created. Saves memory :) 73 73 */ 74 + static void ccwgroup_ungroup_callback(struct device *dev) 75 + { 76 + struct ccwgroup_device *gdev = to_ccwgroupdev(dev); 77 + 78 + __ccwgroup_remove_symlinks(gdev); 79 + device_unregister(dev); 80 + } 81 + 74 82 static ssize_t 75 83 ccwgroup_ungroup_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) 76 84 { 77 85 struct ccwgroup_device *gdev; 86 + int rc; 78 87 79 88 gdev = to_ccwgroupdev(dev); 80 89 81 90 if (gdev->state != CCWGROUP_OFFLINE) 82 91 return -EINVAL; 83 92 84 - __ccwgroup_remove_symlinks(gdev); 85 - device_unregister(dev); 86 - 93 + /* Note that we cannot unregister the device from one of its 94 + * attribute methods, so we have to use this roundabout approach. 95 + */ 96 + rc = device_schedule_callback(dev, ccwgroup_ungroup_callback); 97 + if (rc) 98 + count = rc; 87 99 return count; 88 100 } 89 101
+13 -1
drivers/scsi/scsi_sysfs.c
··· 452 452 } 453 453 static DEVICE_ATTR(rescan, S_IWUSR, NULL, store_rescan_field); 454 454 455 + static void sdev_store_delete_callback(struct device *dev) 456 + { 457 + scsi_remove_device(to_scsi_device(dev)); 458 + } 459 + 455 460 static ssize_t sdev_store_delete(struct device *dev, struct device_attribute *attr, const char *buf, 456 461 size_t count) 457 462 { 458 - scsi_remove_device(to_scsi_device(dev)); 463 + int rc; 464 + 465 + /* An attribute cannot be unregistered by one of its own methods, 466 + * so we have to use this roundabout approach. 467 + */ 468 + rc = device_schedule_callback(dev, sdev_store_delete_callback); 469 + if (rc) 470 + count = rc; 459 471 return count; 460 472 }; 461 473 static DEVICE_ATTR(delete, S_IWUSR, NULL, sdev_store_delete);
+54
fs/sysfs/file.c
··· 629 629 } 630 630 EXPORT_SYMBOL_GPL(sysfs_remove_file_from_group); 631 631 632 + struct sysfs_schedule_callback_struct { 633 + struct kobject *kobj; 634 + void (*func)(void *); 635 + void *data; 636 + struct work_struct work; 637 + }; 638 + 639 + static void sysfs_schedule_callback_work(struct work_struct *work) 640 + { 641 + struct sysfs_schedule_callback_struct *ss = container_of(work, 642 + struct sysfs_schedule_callback_struct, work); 643 + 644 + (ss->func)(ss->data); 645 + kobject_put(ss->kobj); 646 + kfree(ss); 647 + } 648 + 649 + /** 650 + * sysfs_schedule_callback - helper to schedule a callback for a kobject 651 + * @kobj: object we're acting for. 652 + * @func: callback function to invoke later. 653 + * @data: argument to pass to @func. 654 + * 655 + * sysfs attribute methods must not unregister themselves or their parent 656 + * kobject (which would amount to the same thing). Attempts to do so will 657 + * deadlock, since unregistration is mutually exclusive with driver 658 + * callbacks. 659 + * 660 + * Instead methods can call this routine, which will attempt to allocate 661 + * and schedule a workqueue request to call back @func with @data as its 662 + * argument in the workqueue's process context. @kobj will be pinned 663 + * until @func returns. 664 + * 665 + * Returns 0 if the request was submitted, -ENOMEM if storage could not 666 + * be allocated. 667 + */ 668 + int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *), 669 + void *data) 670 + { 671 + struct sysfs_schedule_callback_struct *ss; 672 + 673 + ss = kmalloc(sizeof(*ss), GFP_KERNEL); 674 + if (!ss) 675 + return -ENOMEM; 676 + kobject_get(kobj); 677 + ss->kobj = kobj; 678 + ss->func = func; 679 + ss->data = data; 680 + INIT_WORK(&ss->work, sysfs_schedule_callback_work); 681 + schedule_work(&ss->work); 682 + return 0; 683 + } 684 + EXPORT_SYMBOL_GPL(sysfs_schedule_callback); 685 + 632 686 633 687 EXPORT_SYMBOL_GPL(sysfs_create_file); 634 688 EXPORT_SYMBOL_GPL(sysfs_remove_file);
+2
include/linux/device.h
··· 353 353 struct bin_attribute *attr); 354 354 extern void device_remove_bin_file(struct device *dev, 355 355 struct bin_attribute *attr); 356 + extern int device_schedule_callback(struct device *dev, 357 + void (*func)(struct device *)); 356 358 357 359 /* device resource management */ 358 360 typedef void (*dr_release_t)(struct device *dev, void *res);
+9
include/linux/sysfs.h
··· 78 78 79 79 #ifdef CONFIG_SYSFS 80 80 81 + extern int sysfs_schedule_callback(struct kobject *kobj, 82 + void (*func)(void *), void *data); 83 + 81 84 extern int __must_check 82 85 sysfs_create_dir(struct kobject *, struct dentry *); 83 86 ··· 134 131 extern int __must_check sysfs_init(void); 135 132 136 133 #else /* CONFIG_SYSFS */ 134 + 135 + static inline int sysfs_schedule_callback(struct kobject *kobj, 136 + void (*func)(void *), void *data) 137 + { 138 + return -ENOSYS; 139 + } 137 140 138 141 static inline int sysfs_create_dir(struct kobject * k, struct dentry *shadow) 139 142 {