diff options
Diffstat (limited to 'fs/configfs/dir.c')
-rw-r--r-- | fs/configfs/dir.c | 10 |
1 files changed, 10 insertions, 0 deletions
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c index cb5ea44846af..4e228c80fe9f 100644 --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c | |||
@@ -1207,6 +1207,11 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry) | |||
1207 | return -EINVAL; | 1207 | return -EINVAL; |
1208 | } | 1208 | } |
1209 | 1209 | ||
1210 | /* | ||
1211 | * Ensure that no racing symlink() will make detach_prep() fail while | ||
1212 | * the new link is temporarily attached | ||
1213 | */ | ||
1214 | mutex_lock(&configfs_symlink_mutex); | ||
1210 | spin_lock(&configfs_dirent_lock); | 1215 | spin_lock(&configfs_dirent_lock); |
1211 | do { | 1216 | do { |
1212 | struct mutex *wait_mutex; | 1217 | struct mutex *wait_mutex; |
@@ -1215,6 +1220,7 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry) | |||
1215 | if (ret) { | 1220 | if (ret) { |
1216 | configfs_detach_rollback(dentry); | 1221 | configfs_detach_rollback(dentry); |
1217 | spin_unlock(&configfs_dirent_lock); | 1222 | spin_unlock(&configfs_dirent_lock); |
1223 | mutex_unlock(&configfs_symlink_mutex); | ||
1218 | if (ret != -EAGAIN) { | 1224 | if (ret != -EAGAIN) { |
1219 | config_item_put(parent_item); | 1225 | config_item_put(parent_item); |
1220 | return ret; | 1226 | return ret; |
@@ -1224,10 +1230,12 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry) | |||
1224 | mutex_lock(wait_mutex); | 1230 | mutex_lock(wait_mutex); |
1225 | mutex_unlock(wait_mutex); | 1231 | mutex_unlock(wait_mutex); |
1226 | 1232 | ||
1233 | mutex_lock(&configfs_symlink_mutex); | ||
1227 | spin_lock(&configfs_dirent_lock); | 1234 | spin_lock(&configfs_dirent_lock); |
1228 | } | 1235 | } |
1229 | } while (ret == -EAGAIN); | 1236 | } while (ret == -EAGAIN); |
1230 | spin_unlock(&configfs_dirent_lock); | 1237 | spin_unlock(&configfs_dirent_lock); |
1238 | mutex_unlock(&configfs_symlink_mutex); | ||
1231 | 1239 | ||
1232 | /* Get a working ref for the duration of this function */ | 1240 | /* Get a working ref for the duration of this function */ |
1233 | item = configfs_get_config_item(dentry); | 1241 | item = configfs_get_config_item(dentry); |
@@ -1517,11 +1525,13 @@ void configfs_unregister_subsystem(struct configfs_subsystem *subsys) | |||
1517 | mutex_lock_nested(&configfs_sb->s_root->d_inode->i_mutex, | 1525 | mutex_lock_nested(&configfs_sb->s_root->d_inode->i_mutex, |
1518 | I_MUTEX_PARENT); | 1526 | I_MUTEX_PARENT); |
1519 | mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD); | 1527 | mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD); |
1528 | mutex_lock(&configfs_symlink_mutex); | ||
1520 | spin_lock(&configfs_dirent_lock); | 1529 | spin_lock(&configfs_dirent_lock); |
1521 | if (configfs_detach_prep(dentry, NULL)) { | 1530 | if (configfs_detach_prep(dentry, NULL)) { |
1522 | printk(KERN_ERR "configfs: Tried to unregister non-empty subsystem!\n"); | 1531 | printk(KERN_ERR "configfs: Tried to unregister non-empty subsystem!\n"); |
1523 | } | 1532 | } |
1524 | spin_unlock(&configfs_dirent_lock); | 1533 | spin_unlock(&configfs_dirent_lock); |
1534 | mutex_unlock(&configfs_symlink_mutex); | ||
1525 | configfs_detach_group(&group->cg_item); | 1535 | configfs_detach_group(&group->cg_item); |
1526 | dentry->d_inode->i_flags |= S_DEAD; | 1536 | dentry->d_inode->i_flags |= S_DEAD; |
1527 | mutex_unlock(&dentry->d_inode->i_mutex); | 1537 | mutex_unlock(&dentry->d_inode->i_mutex); |