aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kobject.c
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2013-09-18 17:15:36 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-10-03 19:38:52 -0400
commit26ea12dec0c84133add937455be76d44fe253d85 (patch)
treef0974bcbaec9d9e178b5a79a8919189103140b91 /lib/kobject.c
parentd69ac5a0bbcf1d9962883fb23e337caf5b38cec8 (diff)
kobject: grab an extra reference on kobject->sd to allow duplicate deletes
sysfs currently has a rather weird behavior regarding removals. A directory removal would delete all files directly under it but wouldn't recurse into subdirectories, which, while a bit inconsistent, seems to make sense at the first glance as each directory is supposedly associated with a kobject and each kobject can take care of the directory deletion; however, this doesn't really hold as we have groups which can be directories without a kobject associated with it and require explicit deletions. We're in the process of separating out sysfs from kboject / driver core and want a consistent behavior. A removal should delete either only the specified node or everything under it. I think it is helpful to support recursive atomic removal and later patches will implement it. Such change means that a sysfs_dirent associated with kobject may be deleted before the kobject itself is removed if one of its ancestor gets removed before it. As sysfs_remove_dir() puts the base ref, we may end up with dangling pointer on descendants. This can be solved by holding an extra reference on the sd from kobject. Acquire an extra reference on the associated sysfs_dirent on directory creation and put it after removal. Signed-off-by: Tejun Heo <tj@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'lib/kobject.c')
-rw-r--r--lib/kobject.c12
1 files changed, 12 insertions, 0 deletions
diff --git a/lib/kobject.c b/lib/kobject.c
index 151089788c21..2fdf7fa9e9bd 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -76,6 +76,13 @@ static int create_dir(struct kobject *kobj)
76 if (error) 76 if (error)
77 sysfs_remove_dir(kobj); 77 sysfs_remove_dir(kobj);
78 } 78 }
79
80 /*
81 * @kobj->sd may be deleted by an ancestor going away. Hold an
82 * extra reference so that it stays until @kobj is gone.
83 */
84 sysfs_get(kobj->sd);
85
79 return error; 86 return error;
80} 87}
81 88
@@ -532,10 +539,15 @@ out:
532 */ 539 */
533void kobject_del(struct kobject *kobj) 540void kobject_del(struct kobject *kobj)
534{ 541{
542 struct sysfs_dirent *sd;
543
535 if (!kobj) 544 if (!kobj)
536 return; 545 return;
537 546
547 sd = kobj->sd;
538 sysfs_remove_dir(kobj); 548 sysfs_remove_dir(kobj);
549 sysfs_put(sd);
550
539 kobj->state_in_sysfs = 0; 551 kobj->state_in_sysfs = 0;
540 kobj_kset_leave(kobj); 552 kobj_kset_leave(kobj);
541 kobject_put(kobj->parent); 553 kobject_put(kobj->parent);