Skip to content

Commit 84ec758

Browse files
ChenXiaoSongChristoph Hellwig
authored andcommitted
configfs: fix a race in configfs_{,un}register_subsystem()
When configfs_register_subsystem() or configfs_unregister_subsystem() is executing link_group() or unlink_group(), it is possible that two processes add or delete list concurrently. Some unfortunate interleavings of them can cause kernel panic. One of cases is: A --> B --> C --> D A <-- B <-- C <-- D delete list_head *B | delete list_head *C --------------------------------|----------------------------------- configfs_unregister_subsystem | configfs_unregister_subsystem unlink_group | unlink_group unlink_obj | unlink_obj list_del_init | list_del_init __list_del_entry | __list_del_entry __list_del | __list_del // next == C | next->prev = prev | | next->prev = prev prev->next = next | | // prev == B | prev->next = next Fix this by adding mutex when calling link_group() or unlink_group(), but parent configfs_subsystem is NULL when config_item is root. So I create a mutex configfs_subsystem_mutex. Fixes: 7063fbf ("[PATCH] configfs: User-driven configuration filesystem") Signed-off-by: ChenXiaoSong <[email protected]> Signed-off-by: Laibin Qiu <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]>
1 parent 038101e commit 84ec758

File tree

1 file changed

+14
-0
lines changed

1 file changed

+14
-0
lines changed

fs/configfs/dir.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,14 @@
3434
*/
3535
DEFINE_SPINLOCK(configfs_dirent_lock);
3636

37+
/*
38+
* All of link_obj/unlink_obj/link_group/unlink_group require that
39+
* subsys->su_mutex is held.
40+
* But parent configfs_subsystem is NULL when config_item is root.
41+
* Use this mutex when config_item is root.
42+
*/
43+
static DEFINE_MUTEX(configfs_subsystem_mutex);
44+
3745
static void configfs_d_iput(struct dentry * dentry,
3846
struct inode * inode)
3947
{
@@ -1859,7 +1867,9 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys)
18591867
group->cg_item.ci_name = group->cg_item.ci_namebuf;
18601868

18611869
sd = root->d_fsdata;
1870+
mutex_lock(&configfs_subsystem_mutex);
18621871
link_group(to_config_group(sd->s_element), group);
1872+
mutex_unlock(&configfs_subsystem_mutex);
18631873

18641874
inode_lock_nested(d_inode(root), I_MUTEX_PARENT);
18651875

@@ -1884,7 +1894,9 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys)
18841894
inode_unlock(d_inode(root));
18851895

18861896
if (err) {
1897+
mutex_lock(&configfs_subsystem_mutex);
18871898
unlink_group(group);
1899+
mutex_unlock(&configfs_subsystem_mutex);
18881900
configfs_release_fs();
18891901
}
18901902
put_fragment(frag);
@@ -1931,7 +1943,9 @@ void configfs_unregister_subsystem(struct configfs_subsystem *subsys)
19311943

19321944
dput(dentry);
19331945

1946+
mutex_lock(&configfs_subsystem_mutex);
19341947
unlink_group(group);
1948+
mutex_unlock(&configfs_subsystem_mutex);
19351949
configfs_release_fs();
19361950
}
19371951

0 commit comments

Comments
 (0)