aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2007-11-19 10:53:40 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2008-01-24 23:40:36 -0500
commit09f82ea92822a7bbb7e816508abbda47ed54a77f (patch)
tree059011e094839a633597c2e88afc40f779894438
parent97c146ef075dc40ae34407c03d3860fc3850b8e8 (diff)
Kobject: drop child->parent ref at unregistration
This patch (as1015) reverts changes that were made to the driver core about four years ago. The intent back then was to avoid certain kinds of invalid memory accesses by leaving kernel objects allocated as long as any of their children were still allocated. The original and correct approach was to wait only as long as any children were still _registered_; that's what this patch reinstates. This fixes a problem in the SCSI core made visible by the class_device to regular device conversion: A reference loop (scsi_device holds reference to request_queue, which is the child of a gendisk, which is the child of the scsi_device) prevents the data structures from being released, even though they are deregistered okay. It's possible that this change will cause a few bugs to surface, things that have been hidden for several years. They can be fixed easily enough by having the child device take an explicit reference to the parent whenever needed. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Cc: Kay Sievers <kay.sievers@vrfy.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--lib/kobject.c7
1 files changed, 4 insertions, 3 deletions
diff --git a/lib/kobject.c b/lib/kobject.c
index 1015f74212d0..493e991abb1b 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -149,12 +149,16 @@ void kobject_init(struct kobject * kobj)
149 149
150static void unlink(struct kobject * kobj) 150static void unlink(struct kobject * kobj)
151{ 151{
152 struct kobject *parent = kobj->parent;
153
152 if (kobj->kset) { 154 if (kobj->kset) {
153 spin_lock(&kobj->kset->list_lock); 155 spin_lock(&kobj->kset->list_lock);
154 list_del_init(&kobj->entry); 156 list_del_init(&kobj->entry);
155 spin_unlock(&kobj->kset->list_lock); 157 spin_unlock(&kobj->kset->list_lock);
156 } 158 }
159 kobj->parent = NULL;
157 kobject_put(kobj); 160 kobject_put(kobj);
161 kobject_put(parent);
158} 162}
159 163
160/** 164/**
@@ -208,7 +212,6 @@ int kobject_add(struct kobject * kobj)
208 if (error) { 212 if (error) {
209 /* unlink does the kobject_put() for us */ 213 /* unlink does the kobject_put() for us */
210 unlink(kobj); 214 unlink(kobj);
211 kobject_put(parent);
212 215
213 /* be noisy on error issues */ 216 /* be noisy on error issues */
214 if (error == -EEXIST) 217 if (error == -EEXIST)
@@ -590,7 +593,6 @@ static void kobject_cleanup(struct kobject *kobj)
590{ 593{
591 struct kobj_type * t = get_ktype(kobj); 594 struct kobj_type * t = get_ktype(kobj);
592 struct kset * s = kobj->kset; 595 struct kset * s = kobj->kset;
593 struct kobject * parent = kobj->parent;
594 const char *name = kobj->k_name; 596 const char *name = kobj->k_name;
595 597
596 pr_debug("kobject: '%s' (%p): %s\n", 598 pr_debug("kobject: '%s' (%p): %s\n",
@@ -604,7 +606,6 @@ static void kobject_cleanup(struct kobject *kobj)
604 } 606 }
605 if (s) 607 if (s)
606 kset_put(s); 608 kset_put(s);
607 kobject_put(parent);
608} 609}
609 610
610static void kobject_release(struct kref *kref) 611static void kobject_release(struct kref *kref)