aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLouis Rilling <Louis.Rilling@kerlabs.com>2008-06-16 13:01:01 -0400
committerMark Fasheh <mfasheh@suse.com>2008-07-14 16:57:16 -0400
commitb3e76af87441fc36eef3516d73ab2314e7b2d911 (patch)
tree36c6c6a21ac16b609302845a7dcb91749a972e4c /fs
parent107ed40bd070df5e4a0a012042c45c40963dc574 (diff)
configfs: Fix deadlock with racing rmdir() and rename()
This patch fixes the deadlock between racing sys_rename() and configfs_rmdir(). The idea is to avoid locking i_mutexes of default groups in configfs_detach_prep(), and rely instead on the new configfs_dirent_lock to protect against configfs_dirent's linkage mutations. To ensure that an mkdir() racing with rmdir() will not create new items in a to-be-removed default group, we make configfs_new_dirent() check for the CONFIGFS_USET_DROPPING flag right before linking the new dirent, and return error if the flag is set. This makes racing mkdir()/symlink()/dir_open() fail in places where errors could already happen, resp. in (attach_item()|attach_group())/create_link()/new_dirent(). configfs_depend() remains safe since it locks all the path from configfs root, and is thus mutually exclusive with rmdir(). An advantage of this is that now detach_groups() unconditionnaly takes the default groups i_mutex, which makes it more consistent with populate_groups(). Signed-off-by: Louis Rilling <Louis.Rilling@kerlabs.com> Signed-off-by: Joel Becker <joel.becker@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/configfs/dir.c45
1 files changed, 25 insertions, 20 deletions
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
index 918a332babfe..d5b5985716ba 100644
--- a/fs/configfs/dir.c
+++ b/fs/configfs/dir.c
@@ -43,6 +43,10 @@ DECLARE_RWSEM(configfs_rename_sem);
43 * and configfs_dirent_lock locked, in that order. 43 * and configfs_dirent_lock locked, in that order.
44 * This allows one to safely traverse configfs_dirent trees and symlinks without 44 * This allows one to safely traverse configfs_dirent trees and symlinks without
45 * having to lock inodes. 45 * having to lock inodes.
46 *
47 * Protects setting of CONFIGFS_USET_DROPPING: checking the flag
48 * unlocked is not reliable unless in detach_groups() called from
49 * rmdir()/unregister() and from configfs_attach_group()
46 */ 50 */
47DEFINE_SPINLOCK(configfs_dirent_lock); 51DEFINE_SPINLOCK(configfs_dirent_lock);
48 52
@@ -91,6 +95,11 @@ static struct configfs_dirent *configfs_new_dirent(struct configfs_dirent * pare
91 INIT_LIST_HEAD(&sd->s_children); 95 INIT_LIST_HEAD(&sd->s_children);
92 sd->s_element = element; 96 sd->s_element = element;
93 spin_lock(&configfs_dirent_lock); 97 spin_lock(&configfs_dirent_lock);
98 if (parent_sd->s_type & CONFIGFS_USET_DROPPING) {
99 spin_unlock(&configfs_dirent_lock);
100 kmem_cache_free(configfs_dir_cachep, sd);
101 return ERR_PTR(-ENOENT);
102 }
94 list_add(&sd->s_sibling, &parent_sd->s_children); 103 list_add(&sd->s_sibling, &parent_sd->s_children);
95 spin_unlock(&configfs_dirent_lock); 104 spin_unlock(&configfs_dirent_lock);
96 105
@@ -349,11 +358,11 @@ static struct dentry * configfs_lookup(struct inode *dir,
349 358
350/* 359/*
351 * Only subdirectories count here. Files (CONFIGFS_NOT_PINNED) are 360 * Only subdirectories count here. Files (CONFIGFS_NOT_PINNED) are
352 * attributes and are removed by rmdir(). We recurse, taking i_mutex 361 * attributes and are removed by rmdir(). We recurse, setting
353 * on all children that are candidates for default detach. If the 362 * CONFIGFS_USET_DROPPING on all children that are candidates for
354 * result is clean, then configfs_detach_group() will handle dropping 363 * default detach.
355 * i_mutex. If there is an error, the caller will clean up the i_mutex 364 * If there is an error, the caller will reset the flags via
356 * holders via configfs_detach_rollback(). 365 * configfs_detach_rollback().
357 */ 366 */
358static int configfs_detach_prep(struct dentry *dentry) 367static int configfs_detach_prep(struct dentry *dentry)
359{ 368{
@@ -370,8 +379,7 @@ static int configfs_detach_prep(struct dentry *dentry)
370 if (sd->s_type & CONFIGFS_NOT_PINNED) 379 if (sd->s_type & CONFIGFS_NOT_PINNED)
371 continue; 380 continue;
372 if (sd->s_type & CONFIGFS_USET_DEFAULT) { 381 if (sd->s_type & CONFIGFS_USET_DEFAULT) {
373 mutex_lock(&sd->s_dentry->d_inode->i_mutex); 382 /* Mark that we're trying to drop the group */
374 /* Mark that we've taken i_mutex */
375 sd->s_type |= CONFIGFS_USET_DROPPING; 383 sd->s_type |= CONFIGFS_USET_DROPPING;
376 384
377 /* 385 /*
@@ -392,7 +400,7 @@ out:
392} 400}
393 401
394/* 402/*
395 * Walk the tree, dropping i_mutex wherever CONFIGFS_USET_DROPPING is 403 * Walk the tree, resetting CONFIGFS_USET_DROPPING wherever it was
396 * set. 404 * set.
397 */ 405 */
398static void configfs_detach_rollback(struct dentry *dentry) 406static void configfs_detach_rollback(struct dentry *dentry)
@@ -403,11 +411,7 @@ static void configfs_detach_rollback(struct dentry *dentry)
403 list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { 411 list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
404 if (sd->s_type & CONFIGFS_USET_DEFAULT) { 412 if (sd->s_type & CONFIGFS_USET_DEFAULT) {
405 configfs_detach_rollback(sd->s_dentry); 413 configfs_detach_rollback(sd->s_dentry);
406 414 sd->s_type &= ~CONFIGFS_USET_DROPPING;
407 if (sd->s_type & CONFIGFS_USET_DROPPING) {
408 sd->s_type &= ~CONFIGFS_USET_DROPPING;
409 mutex_unlock(&sd->s_dentry->d_inode->i_mutex);
410 }
411 } 415 }
412 } 416 }
413} 417}
@@ -486,16 +490,12 @@ static void detach_groups(struct config_group *group)
486 490
487 child = sd->s_dentry; 491 child = sd->s_dentry;
488 492
493 mutex_lock(&child->d_inode->i_mutex);
494
489 configfs_detach_group(sd->s_element); 495 configfs_detach_group(sd->s_element);
490 child->d_inode->i_flags |= S_DEAD; 496 child->d_inode->i_flags |= S_DEAD;
491 497
492 /* 498 mutex_unlock(&child->d_inode->i_mutex);
493 * From rmdir/unregister, a configfs_detach_prep() pass
494 * has taken our i_mutex for us. Drop it.
495 * From mkdir/register cleanup, there is no sem held.
496 */
497 if (sd->s_type & CONFIGFS_USET_DROPPING)
498 mutex_unlock(&child->d_inode->i_mutex);
499 499
500 d_delete(child); 500 d_delete(child);
501 dput(child); 501 dput(child);
@@ -1181,12 +1181,15 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry)
1181 return -EINVAL; 1181 return -EINVAL;
1182 } 1182 }
1183 1183
1184 spin_lock(&configfs_dirent_lock);
1184 ret = configfs_detach_prep(dentry); 1185 ret = configfs_detach_prep(dentry);
1185 if (ret) { 1186 if (ret) {
1186 configfs_detach_rollback(dentry); 1187 configfs_detach_rollback(dentry);
1188 spin_unlock(&configfs_dirent_lock);
1187 config_item_put(parent_item); 1189 config_item_put(parent_item);
1188 return ret; 1190 return ret;
1189 } 1191 }
1192 spin_unlock(&configfs_dirent_lock);
1190 1193
1191 /* Get a working ref for the duration of this function */ 1194 /* Get a working ref for the duration of this function */
1192 item = configfs_get_config_item(dentry); 1195 item = configfs_get_config_item(dentry);
@@ -1476,9 +1479,11 @@ void configfs_unregister_subsystem(struct configfs_subsystem *subsys)
1476 mutex_lock_nested(&configfs_sb->s_root->d_inode->i_mutex, 1479 mutex_lock_nested(&configfs_sb->s_root->d_inode->i_mutex,
1477 I_MUTEX_PARENT); 1480 I_MUTEX_PARENT);
1478 mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD); 1481 mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD);
1482 spin_lock(&configfs_dirent_lock);
1479 if (configfs_detach_prep(dentry)) { 1483 if (configfs_detach_prep(dentry)) {
1480 printk(KERN_ERR "configfs: Tried to unregister non-empty subsystem!\n"); 1484 printk(KERN_ERR "configfs: Tried to unregister non-empty subsystem!\n");
1481 } 1485 }
1486 spin_unlock(&configfs_dirent_lock);
1482 configfs_detach_group(&group->cg_item); 1487 configfs_detach_group(&group->cg_item);
1483 dentry->d_inode->i_flags |= S_DEAD; 1488 dentry->d_inode->i_flags |= S_DEAD;
1484 mutex_unlock(&dentry->d_inode->i_mutex); 1489 mutex_unlock(&dentry->d_inode->i_mutex);