Skip to content

Commit 26ea12d

Browse files
htejungregkh
authored andcommitted
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 <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent d69ac5a commit 26ea12d

File tree

2 files changed

+18
-1
lines changed

2 files changed

+18
-1
lines changed

fs/sysfs/dir.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -549,7 +549,12 @@ void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
549549
{
550550
struct sysfs_inode_attrs *ps_iattr;
551551

552-
BUG_ON(sd->s_flags & SYSFS_FLAG_REMOVED);
552+
/*
553+
* Removal can be called multiple times on the same node. Only the
554+
* first invocation is effective and puts the base ref.
555+
*/
556+
if (sd->s_flags & SYSFS_FLAG_REMOVED)
557+
return;
553558

554559
sysfs_unlink_sibling(sd);
555560

lib/kobject.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,13 @@ static int create_dir(struct kobject *kobj)
7676
if (error)
7777
sysfs_remove_dir(kobj);
7878
}
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+
7986
return error;
8087
}
8188

@@ -532,10 +539,15 @@ int kobject_move(struct kobject *kobj, struct kobject *new_parent)
532539
*/
533540
void kobject_del(struct kobject *kobj)
534541
{
542+
struct sysfs_dirent *sd;
543+
535544
if (!kobj)
536545
return;
537546

547+
sd = kobj->sd;
538548
sysfs_remove_dir(kobj);
549+
sysfs_put(sd);
550+
539551
kobj->state_in_sysfs = 0;
540552
kobj_kset_leave(kobj);
541553
kobject_put(kobj->parent);

0 commit comments

Comments
 (0)