mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Tejun Heo <htejun@gmail.com>
To: Cornelia Huck <cornelia.huck@de.ibm.com>
Cc: linux-kernel <linux-kernel@vger.kernel.org>,
	Alan Stern <stern@rowland.harvard.edu>, Greg K-H <greg@kroah.com>,
	Rusty Russell <rusty@rustcorp.com.au>,
	dmitry.torokhov@gmail.com
Subject: [PATCH RFD] alternative kobject release wait mechanism
Date: Wed, 18 Apr 2007 03:41:10 +0900	[thread overview]
Message-ID: <20070417184110.GJ10619@htj.dyndns.org> (raw)
In-Reply-To: <20070416193619.4659a847@gondolin.boeblingen.de.ibm.com>

Hello, all.

Agreed with the problem but I'm not very enthusiastic for adding
kobj->owner.  How about the following?  exit() routines will have to
do device_unregister_wait() instead of device_unregister().  On return
from it, it's guaranteed that all references to it are dropped and
->release is finished.  The caller is responsible for avoiding
deadlock, of course.

The code is only compile-tested and is more of proof-of-concept than
working code.

DO NOT APPLY.

diff --git a/drivers/base/core.c b/drivers/base/core.c
index 37930d0..72ccf16 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -741,6 +741,17 @@ void put_device(struct device * dev)
 
 
 /**
+ *	put_device_wait - put and wait for all references to go away
+ *	@dev:	device in question.
+ */
+void put_device_wait(struct device * dev)
+{
+	if (dev)
+		kobject_put_wait(&dev->kobj);
+}
+
+
+/**
  *	device_del - delete device from system.
  *	@dev:	device.
  *
@@ -839,6 +850,20 @@ void device_unregister(struct device * dev)
 }
 
 
+/**
+ *	device_unregister_wait - unregister dev and wait for it to be released
+ *	@dev:	device going away.
+ *
+ *	Delete and put @dev; then, wait for it to be released.
+ */
+void device_unregister_wait(struct device * dev)
+{
+	pr_debug("DEV: Unregistering device. ID = '%s'\n", dev->bus_id);
+	device_del(dev);
+	put_device_wait(dev);
+}
+
+
 static struct device * next_device(struct klist_iter * i)
 {
 	struct klist_node * n = klist_next(i);
@@ -917,8 +942,10 @@ EXPORT_SYMBOL_GPL(device_register);
 
 EXPORT_SYMBOL_GPL(device_del);
 EXPORT_SYMBOL_GPL(device_unregister);
+EXPORT_SYMBOL_GPL(device_unregister_wait);
 EXPORT_SYMBOL_GPL(get_device);
 EXPORT_SYMBOL_GPL(put_device);
+EXPORT_SYMBOL_GPL(put_device_wait);
 
 EXPORT_SYMBOL_GPL(device_create_file);
 EXPORT_SYMBOL_GPL(device_remove_file);
diff --git a/include/linux/device.h b/include/linux/device.h
index 5cf30e9..1a1f1da 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -490,6 +490,7 @@ void driver_init(void);
  */
 extern int __must_check device_register(struct device * dev);
 extern void device_unregister(struct device * dev);
+extern void device_unregister_wait(struct device * dev);
 extern void device_initialize(struct device * dev);
 extern int __must_check device_add(struct device * dev);
 extern void device_del(struct device * dev);
@@ -535,6 +536,7 @@ extern int (*platform_notify_remove)(struct device * dev);
  */
 extern struct device * get_device(struct device * dev);
 extern void put_device(struct device * dev);
+extern void put_device_wait(struct device * dev);
 
 
 /* drivers/base/power/shutdown.c */
diff --git a/include/linux/kobject.h b/include/linux/kobject.h
index b850e03..4f0bb2d 100644
--- a/include/linux/kobject.h
+++ b/include/linux/kobject.h
@@ -85,9 +85,11 @@ extern int __must_check kobject_move(struct kobject *, struct kobject *);
 
 extern int __must_check kobject_register(struct kobject *);
 extern void kobject_unregister(struct kobject *);
+extern void kobject_unregister_wait(struct kobject *);
 
 extern struct kobject * kobject_get(struct kobject *);
 extern void kobject_put(struct kobject *);
+extern void kobject_put_wait(struct kobject *);
 
 extern struct kobject *kobject_add_dir(struct kobject *, const char *);
 
diff --git a/lib/kobject.c b/lib/kobject.c
index 057921c..22e5148 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -16,6 +16,15 @@
 #include <linux/stat.h>
 #include <linux/slab.h>
 
+struct kobj_wait {
+	struct list_head	list;
+	struct kobject		*kobj;
+	struct completion	cmpl;
+};
+
+static spinlock_t kobj_wait_lock = SPIN_LOCK_UNLOCKED;
+static LIST_HEAD(kobj_wait_list);
+
 /**
  *	populate_dir - populate directory with attributes.
  *	@kobj:	object we're working on.
@@ -425,6 +434,23 @@ void kobject_unregister(struct kobject * kobj)
 }
 
 /**
+ *	kobject_unregister_wait - unregister, put and wait
+ *	@kobj:	object going away
+ *
+ *	Remove @kobj from hierarchy, decrement refcount and wait for
+ *	it to die.
+ */
+void kobject_unregister_wait(struct kobject * kobj)
+{
+	if (!kobj)
+		return;
+	pr_debug("kobject %s: unregistering\n",kobject_name(kobj));
+	kobject_uevent(kobj, KOBJ_REMOVE);
+	kobject_del(kobj);
+	kobject_put_wait(kobj);
+}
+
+/**
  *	kobject_get - increment refcount for object.
  *	@kobj:	object.
  */
@@ -446,8 +472,22 @@ void kobject_cleanup(struct kobject * kobj)
 	struct kobj_type * t = get_ktype(kobj);
 	struct kset * s = kobj->kset;
 	struct kobject * parent = kobj->parent;
+	struct kobj_wait *kwait;
+	unsigned long flags;
 
 	pr_debug("kobject %s: cleaning up\n",kobject_name(kobj));
+
+	/* is somebody waiting for @kobj to die? */
+	spin_lock_irqsave(&kobj_wait_lock, flags);
+	list_for_each_entry(kwait, &kobj_wait_list, list) {
+		if (kwait->kobj == kobj) {
+			list_del_init(&kwait->list);
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&kobj_wait_lock, flags);
+
+	/* clean up */
 	if (kobj->k_name != kobj->name)
 		kfree(kobj->k_name);
 	kobj->k_name = NULL;
@@ -456,6 +496,10 @@ void kobject_cleanup(struct kobject * kobj)
 	if (s)
 		kset_put(s);
 	kobject_put(parent);
+
+	/* notify waiter */
+	if (kwait)
+		complete(&kwait->cmpl);
 }
 
 static void kobject_release(struct kref *kref)
@@ -475,6 +519,42 @@ void kobject_put(struct kobject * kobj)
 		kref_put(&kobj->kref, kobject_release);
 }
 
+/**
+ *	kobject_put_wait - put and wait for all references to go away
+ *	@kobj:	object
+ *
+ *	This function is used by @kobj owner to kill it - it puts a
+ *	reference to @kobj and waits till all the references are gone
+ *	and ->release is finished.  @kobj must have been deleted and
+ *	the caller is responsible for guaranteeing that all references
+ *	will be dropped in foreseeable future.
+ */
+void kobject_put_wait(struct kobject * kobj)
+{
+	struct kobj_wait kwait;
+	unsigned long flags;
+
+	if (!kobj)
+		return;
+
+	BUG_ON(!list_empty(&kobj->entry));
+
+	init_completion(&kwait.cmpl);
+	kwait.kobj = kobj;
+
+	spin_lock_irqsave(&kobj_wait_lock, flags);
+	list_add(&kwait.list, &kobj_wait_list);
+	spin_unlock_irqrestore(&kobj_wait_lock, flags);
+
+	kobject_put(kobj);
+
+	if (!wait_for_completion_timeout(&kwait.cmpl, 30 * HZ)) {
+		printk(KERN_WARNING "kobject_put_wait: kobject %p is still "
+		       "alive after 30s, possible reference count bug\n", kobj);
+		dump_stack();
+		wait_for_completion(&kwait.cmpl);
+	}
+}
 
 static void dir_release(struct kobject *kobj)
 {
@@ -691,8 +771,10 @@ void subsys_remove_file(struct subsystem * s, struct subsys_attribute * a)
 EXPORT_SYMBOL(kobject_init);
 EXPORT_SYMBOL(kobject_register);
 EXPORT_SYMBOL(kobject_unregister);
+EXPORT_SYMBOL(kobject_unregister_wait);
 EXPORT_SYMBOL(kobject_get);
 EXPORT_SYMBOL(kobject_put);
+EXPORT_SYMBOL(kobject_put_wait);
 EXPORT_SYMBOL(kobject_add);
 EXPORT_SYMBOL(kobject_del);
 

  parent reply	other threads:[~2007-04-17 18:41 UTC|newest]

Thread overview: 70+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-04-16 17:36 [Patch -mm 0/3] RFC: module unloading vs. release function Cornelia Huck
2007-04-16 18:30 ` Dmitry Torokhov
2007-04-16 18:47   ` Greg KH
2007-04-16 19:03     ` Dmitry Torokhov
2007-04-16 19:11       ` Greg KH
2007-04-16 20:20         ` Dmitry Torokhov
2007-04-16 19:38   ` Alan Stern
2007-04-16 19:47     ` Dmitry Torokhov
2007-04-16 19:52       ` Greg KH
2007-04-16 20:18         ` Dmitry Torokhov
2007-04-16 21:02           ` Alan Stern
2007-04-17  7:49             ` Cornelia Huck
2007-04-16 20:44     ` Alexey Dobriyan
2007-04-17  2:55       ` Rusty Russell
2007-04-17  7:36     ` Cornelia Huck
2007-04-16 18:53 ` Greg KH
2007-04-17 18:41 ` Tejun Heo [this message]
2007-04-17 18:49   ` [PATCH RFD] alternative kobject release wait mechanism Tejun Heo
2007-04-18  8:11     ` Cornelia Huck
2007-04-18  8:46       ` Tejun Heo
2007-04-18  9:35         ` Cornelia Huck
2007-04-18  9:55           ` Tejun Heo
2007-04-18  8:07   ` Cornelia Huck
2007-04-18  8:36     ` Tejun Heo
2007-04-18 14:53   ` Alan Stern
2007-04-18 15:26     ` Cornelia Huck
2007-04-18 15:34     ` Tejun Heo
2007-04-18 15:45       ` Tejun Heo
2007-04-18 19:07         ` Alan Stern
2007-04-20  5:27           ` Tejun Heo
2007-04-20  9:11             ` Cornelia Huck
2007-04-20 15:01             ` Alan Stern
2007-04-20 15:57               ` Dmitry Torokhov
2007-04-21 15:19                 ` Alan Stern
2007-04-20 15:40             ` Alan Stern
2007-04-21  0:03               ` Greg KH
2007-04-21 21:36                 ` Alan Stern
2007-04-22 17:40                   ` Greg KH
2007-04-23  7:08                     ` Cornelia Huck
2007-04-23 19:47                       ` Alan Stern
2007-04-24 19:38                     ` Alan Stern
2007-04-25  9:00                       ` Cornelia Huck
2007-04-25 20:13                         ` Alan Stern
2007-04-26  8:21                           ` Cornelia Huck
2007-04-26 14:58                             ` Alan Stern
2007-04-26 15:12                               ` Cornelia Huck
2007-04-18 16:11       ` Alan Stern
2007-04-18 16:38         ` Tejun Heo
2007-04-18 16:41       ` Dmitry Torokhov
2007-04-19 12:51         ` Cornelia Huck
2007-04-19 13:13           ` Dmitry Torokhov
2007-04-19 13:48             ` Cornelia Huck
2007-04-19 14:21               ` Dmitry Torokhov
2007-04-20  5:59                 ` Tejun Heo
2007-04-20 16:35                   ` Dmitry Torokhov
2007-04-20 16:52                     ` Tejun Heo
2007-04-20 17:59                       ` Dmitry Torokhov
2007-04-23  6:40                         ` Tejun Heo
2007-04-23  6:53                           ` Greg KH
2007-04-19 17:19         ` Alan Stern
2007-04-19 18:39           ` Dmitry Torokhov
2007-04-19 22:37             ` Alan Stern
2007-04-20 16:35               ` Dmitry Torokhov
2007-04-21 15:30                 ` Alan Stern
2007-04-18 15:06   ` Cornelia Huck
2007-04-18 16:06     ` Tejun Heo
2007-04-19 13:29       ` Cornelia Huck
2007-04-19 14:20         ` Alan Stern
2007-04-19 14:49           ` Cornelia Huck
2007-04-20  9:04             ` Cornelia Huck

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=20070417184110.GJ10619@htj.dyndns.org \
    --to=htejun@gmail.com \
    --cc=cornelia.huck@de.ibm.com \
    --cc=dmitry.torokhov@gmail.com \
    --cc=greg@kroah.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=rusty@rustcorp.com.au \
    --cc=stern@rowland.harvard.edu \
    /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

all inboxes | Powered by JetHome®