linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Alan Stern <stern@rowland.harvard.edu>
To: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Hugh Dickins <hugh@veritas.com>,
	Cornelia Huck <cornelia.huck@de.ibm.com>,
	Dmitry Torokhov <dmitry.torokhov@gmail.com>,
	Oliver Neukum <oneukum@suse.de>,
	Maneesh Soni <maneesh@in.ibm.com>, <gregkh@suse.de>,
	Richard Purdie <rpurdie@rpsys.net>,
	James Bottomley <James.Bottomley@SteelEye.com>,
	SCSI development list <linux-scsi@vger.kernel.org>,
	<linux-s390@vger.kernel.org>,
	Kernel development list <linux-kernel@vger.kernel.org>
Subject: [PATCH] sysfs and driver core: add callback helper, used by SCSI and S390
Date: Thu, 15 Mar 2007 15:50:34 -0400 (EDT)	[thread overview]
Message-ID: <Pine.LNX.4.44L0.0703151546190.2482-100000@iolanthe.rowland.org> (raw)
In-Reply-To: <Pine.LNX.4.64.0703150944250.3816@woody.linux-foundation.org>

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>

---

Index: 2.6.21-rc3-git9/include/linux/sysfs.h
===================================================================
--- 2.6.21-rc3-git9.orig/include/linux/sysfs.h
+++ 2.6.21-rc3-git9/include/linux/sysfs.h
@@ -78,6 +78,9 @@ struct sysfs_ops {
 
 #ifdef CONFIG_SYSFS
 
+extern int sysfs_schedule_callback(struct kobject *kobj,
+		void (*func)(void *), void *data);
+
 extern int __must_check
 sysfs_create_dir(struct kobject *, struct dentry *);
 
@@ -132,6 +135,12 @@ extern int __must_check sysfs_init(void)
 
 #else /* CONFIG_SYSFS */
 
+static inline int sysfs_schedule_callback(struct kobject *kobj,
+		void (*func)(void *), void *data)
+{
+	return -ENOSYS;
+}
+
 static inline int sysfs_create_dir(struct kobject * k, struct dentry *shadow)
 {
 	return 0;
Index: 2.6.21-rc3-git9/fs/sysfs/file.c
===================================================================
--- 2.6.21-rc3-git9.orig/fs/sysfs/file.c
+++ 2.6.21-rc3-git9/fs/sysfs/file.c
@@ -629,6 +629,60 @@ void sysfs_remove_file_from_group(struct
 }
 EXPORT_SYMBOL_GPL(sysfs_remove_file_from_group);
 
+struct sysfs_schedule_callback_struct {
+	struct kobject 		*kobj;
+	void			(*func)(void *);
+	void			*data;
+	struct work_struct	work;
+};
+
+static void sysfs_schedule_callback_work(struct work_struct *work)
+{
+	struct sysfs_schedule_callback_struct *ss = container_of(work,
+			struct sysfs_schedule_callback_struct, work);
+
+	(ss->func)(ss->data);
+	kobject_put(ss->kobj);
+	kfree(ss);
+}
+
+/**
+ * sysfs_schedule_callback - helper to schedule a callback for a kobject
+ * @kobj: object we're acting for.
+ * @func: callback function to invoke later.
+ * @data: argument to pass to @func.
+ *
+ * sysfs attribute methods must not unregister themselves or their parent
+ * kobject (which would amount to the same thing).  Attempts to do so will
+ * deadlock, since unregistration is mutually exclusive with driver
+ * callbacks.
+ *
+ * Instead methods can call this routine, which will attempt to allocate
+ * and schedule a workqueue request to call back @func with @data as its
+ * argument in the workqueue's process context.  @kobj will be pinned
+ * until @func returns.
+ *
+ * Returns 0 if the request was submitted, -ENOMEM if storage could not
+ * be allocated.
+ */
+int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *),
+		void *data)
+{
+	struct sysfs_schedule_callback_struct *ss;
+
+	ss = kmalloc(sizeof(*ss), GFP_KERNEL);
+	if (!ss)
+		return -ENOMEM;
+	kobject_get(kobj);
+	ss->kobj = kobj;
+	ss->func = func;
+	ss->data = data;
+	INIT_WORK(&ss->work, sysfs_schedule_callback_work);
+	schedule_work(&ss->work);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(sysfs_schedule_callback);
+
 
 EXPORT_SYMBOL_GPL(sysfs_create_file);
 EXPORT_SYMBOL_GPL(sysfs_remove_file);
Index: 2.6.21-rc3-git9/include/linux/device.h
===================================================================
--- 2.6.21-rc3-git9.orig/include/linux/device.h
+++ 2.6.21-rc3-git9/include/linux/device.h
@@ -353,6 +353,8 @@ extern int __must_check device_create_bi
 					       struct bin_attribute *attr);
 extern void device_remove_bin_file(struct device *dev,
 				   struct bin_attribute *attr);
+extern int device_schedule_callback(struct device *dev,
+		void (*func)(struct device *));
 
 /* device resource management */
 typedef void (*dr_release_t)(struct device *dev, void *res);
Index: 2.6.21-rc3-git9/drivers/base/core.c
===================================================================
--- 2.6.21-rc3-git9.orig/drivers/base/core.c
+++ 2.6.21-rc3-git9/drivers/base/core.c
@@ -407,6 +407,35 @@ void device_remove_bin_file(struct devic
 }
 EXPORT_SYMBOL_GPL(device_remove_bin_file);
 
+/**
+ * device_schedule_callback - helper to schedule a callback for a device
+ * @dev: device.
+ * @func: callback function to invoke later.
+ *
+ * Attribute methods must not unregister themselves or their parent device
+ * (which would amount to the same thing).  Attempts to do so will deadlock,
+ * since unregistration is mutually exclusive with driver callbacks.
+ *
+ * Instead methods can call this routine, which will attempt to allocate
+ * and schedule a workqueue request to call back @func with @dev as its
+ * argument in the workqueue's process context.  @dev will be pinned until
+ * @func returns.
+ *
+ * Returns 0 if the request was submitted, -ENOMEM if storage could not
+ * be allocated.
+ *
+ * NOTE: This routine won't work if CONFIG_SYSFS isn't set!  It uses an
+ * underlying sysfs routine (since it is intended for use by attribute
+ * methods), and if sysfs isn't available you'll get nothing but -ENOSYS.
+ */
+int device_schedule_callback(struct device *dev,
+		void (*func)(struct device *))
+{
+	return sysfs_schedule_callback(&dev->kobj,
+			(void (*)(void *)) func, dev);
+}
+EXPORT_SYMBOL_GPL(device_schedule_callback);
+
 static void klist_children_get(struct klist_node *n)
 {
 	struct device *dev = container_of(n, struct device, knode_parent);
Index: 2.6.21-rc3-git9/drivers/scsi/scsi_sysfs.c
===================================================================
--- 2.6.21-rc3-git9.orig/drivers/scsi/scsi_sysfs.c
+++ 2.6.21-rc3-git9/drivers/scsi/scsi_sysfs.c
@@ -452,10 +452,22 @@ store_rescan_field (struct device *dev, 
 }
 static DEVICE_ATTR(rescan, S_IWUSR, NULL, store_rescan_field);
 
+static void sdev_store_delete_callback(struct device *dev)
+{
+	scsi_remove_device(to_scsi_device(dev));
+}
+
 static ssize_t sdev_store_delete(struct device *dev, struct device_attribute *attr, const char *buf,
 				 size_t count)
 {
-	scsi_remove_device(to_scsi_device(dev));
+	int rc;
+
+	/* An attribute cannot be unregistered by one of its own methods,
+	 * so we have to use this roundabout approach.
+	 */
+	rc = device_schedule_callback(dev, sdev_store_delete_callback);
+	if (rc)
+		count = rc;
 	return count;
 };
 static DEVICE_ATTR(delete, S_IWUSR, NULL, sdev_store_delete);
Index: 2.6.21-rc3-git9/drivers/s390/cio/ccwgroup.c
===================================================================
--- 2.6.21-rc3-git9.orig/drivers/s390/cio/ccwgroup.c
+++ 2.6.21-rc3-git9/drivers/s390/cio/ccwgroup.c
@@ -71,19 +71,31 @@ __ccwgroup_remove_symlinks(struct ccwgro
  * Provide an 'ungroup' attribute so the user can remove group devices no
  * longer needed or accidentially created. Saves memory :)
  */
+static void ccwgroup_ungroup_callback(struct device *dev)
+{
+	struct ccwgroup_device *gdev = to_ccwgroupdev(dev);
+
+	__ccwgroup_remove_symlinks(gdev);
+	device_unregister(dev);
+}
+
 static ssize_t
 ccwgroup_ungroup_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
 	struct ccwgroup_device *gdev;
+	int rc;
 
 	gdev = to_ccwgroupdev(dev);
 
 	if (gdev->state != CCWGROUP_OFFLINE)
 		return -EINVAL;
 
-	__ccwgroup_remove_symlinks(gdev);
-	device_unregister(dev);
-
+	/* Note that we cannot unregister the device from one of its
+	 * attribute methods, so we have to use this roundabout approach.
+	 */
+	rc = device_schedule_callback(dev, ccwgroup_ungroup_callback);
+	if (rc)
+		count = rc;
 	return count;
 }
 


  reply	other threads:[~2007-03-15 19:50 UTC|newest]

Thread overview: 51+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-03-08 13:05 refcounting drivers' data structures used in sysfs buffers Oliver Neukum
2007-03-08 16:02 ` Alan Stern
2007-03-09  0:45   ` Oliver Neukum
2007-03-09 16:32     ` Alan Stern
2007-03-09 16:44       ` Oliver Neukum
2007-03-09 17:02         ` Dmitry Torokhov
2007-03-09 17:18           ` Oliver Neukum
2007-03-09 17:34             ` Dmitry Torokhov
2007-03-09 19:32               ` Alan Stern
2007-03-09 20:05                 ` Oliver Neukum
2007-03-09 20:27                   ` Alan Stern
2007-03-09 20:39                     ` Oliver Neukum
2007-03-09 20:08               ` Alan Stern
2007-03-09 20:48                 ` Oliver Neukum
2007-03-10 19:19                   ` Alan Stern
2007-03-12  8:54                     ` Oliver Neukum
2007-03-12 14:57                       ` Alan Stern
2007-03-12 15:23                         ` Oliver Neukum
2007-03-12 15:42                           ` Dmitry Torokhov
2007-03-12 15:59                             ` Oliver Neukum
2007-03-12 16:21                               ` Alan Stern
2007-03-12 18:25                                 ` Oliver Neukum
2007-03-12 19:31                                   ` Alan Stern
2007-03-12 19:49                                     ` Oliver Neukum
2007-03-12 20:03                                       ` Alan Stern
2007-03-12 20:15                                         ` Oliver Neukum
2007-03-12 20:31                                         ` Dmitry Torokhov
2007-03-12 20:45                                           ` Alan Stern
2007-03-12 21:31                                           ` Richard Purdie
2007-03-13 15:00                                             ` 2.6.21-rc suspend regression: sysfs deadlock Alan Stern
2007-03-13 18:42                                               ` Cornelia Huck
2007-03-13 21:20                                                 ` Linus Torvalds
2007-03-14 16:12                                                   ` Alan Stern
2007-03-14 18:43                                                     ` Cornelia Huck
2007-03-14 19:23                                                       ` Alan Stern
2007-03-15 10:27                                                         ` Cornelia Huck
2007-03-15 12:31                                                           ` Hugh Dickins
2007-03-15 13:02                                                             ` Oliver Neukum
2007-03-15 13:22                                                               ` Dmitry Torokhov
2007-03-15 13:59                                                                 ` Hugh Dickins
2007-03-15 14:27                                                           ` Alan Stern
2007-03-15 15:32                                                             ` Cornelia Huck
2007-03-15 16:29                                                             ` Hugh Dickins
2007-03-15 16:51                                                               ` Linus Torvalds
2007-03-15 19:50                                                                 ` Alan Stern [this message]
2007-03-15 19:51                                                                 ` [PATCH] sysfs: reinstate exclusion between method calls and attribute unregistration Alan Stern
2007-03-13 19:00                                               ` 2.6.21-rc suspend regression: sysfs deadlock Hugh Dickins
2007-03-13 20:09                                                 ` Alan Stern
2007-03-13 20:55                                                   ` Hugh Dickins
2007-03-13 21:08                                                     ` Dmitry Torokhov
2007-03-13 21:20                                                     ` Alan Stern

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=Pine.LNX.4.44L0.0703151546190.2482-100000@iolanthe.rowland.org \
    --to=stern@rowland.harvard.edu \
    --cc=James.Bottomley@SteelEye.com \
    --cc=cornelia.huck@de.ibm.com \
    --cc=dmitry.torokhov@gmail.com \
    --cc=gregkh@suse.de \
    --cc=hugh@veritas.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-s390@vger.kernel.org \
    --cc=linux-scsi@vger.kernel.org \
    --cc=maneesh@in.ibm.com \
    --cc=oneukum@suse.de \
    --cc=rpurdie@rpsys.net \
    --cc=torvalds@linux-foundation.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).