|
@@ -1207,6 +1207,11 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * Ensure that no racing symlink() will make detach_prep() fail while
|
|
|
|
+ * the new link is temporarily attached
|
|
|
|
+ */
|
|
|
|
+ mutex_lock(&configfs_symlink_mutex);
|
|
spin_lock(&configfs_dirent_lock);
|
|
spin_lock(&configfs_dirent_lock);
|
|
do {
|
|
do {
|
|
struct mutex *wait_mutex;
|
|
struct mutex *wait_mutex;
|
|
@@ -1215,6 +1220,7 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry)
|
|
if (ret) {
|
|
if (ret) {
|
|
configfs_detach_rollback(dentry);
|
|
configfs_detach_rollback(dentry);
|
|
spin_unlock(&configfs_dirent_lock);
|
|
spin_unlock(&configfs_dirent_lock);
|
|
|
|
+ mutex_unlock(&configfs_symlink_mutex);
|
|
if (ret != -EAGAIN) {
|
|
if (ret != -EAGAIN) {
|
|
config_item_put(parent_item);
|
|
config_item_put(parent_item);
|
|
return ret;
|
|
return ret;
|
|
@@ -1224,10 +1230,12 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry)
|
|
mutex_lock(wait_mutex);
|
|
mutex_lock(wait_mutex);
|
|
mutex_unlock(wait_mutex);
|
|
mutex_unlock(wait_mutex);
|
|
|
|
|
|
|
|
+ mutex_lock(&configfs_symlink_mutex);
|
|
spin_lock(&configfs_dirent_lock);
|
|
spin_lock(&configfs_dirent_lock);
|
|
}
|
|
}
|
|
} while (ret == -EAGAIN);
|
|
} while (ret == -EAGAIN);
|
|
spin_unlock(&configfs_dirent_lock);
|
|
spin_unlock(&configfs_dirent_lock);
|
|
|
|
+ mutex_unlock(&configfs_symlink_mutex);
|
|
|
|
|
|
/* Get a working ref for the duration of this function */
|
|
/* Get a working ref for the duration of this function */
|
|
item = configfs_get_config_item(dentry);
|
|
item = configfs_get_config_item(dentry);
|
|
@@ -1517,11 +1525,13 @@ void configfs_unregister_subsystem(struct configfs_subsystem *subsys)
|
|
mutex_lock_nested(&configfs_sb->s_root->d_inode->i_mutex,
|
|
mutex_lock_nested(&configfs_sb->s_root->d_inode->i_mutex,
|
|
I_MUTEX_PARENT);
|
|
I_MUTEX_PARENT);
|
|
mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD);
|
|
mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD);
|
|
|
|
+ mutex_lock(&configfs_symlink_mutex);
|
|
spin_lock(&configfs_dirent_lock);
|
|
spin_lock(&configfs_dirent_lock);
|
|
if (configfs_detach_prep(dentry, NULL)) {
|
|
if (configfs_detach_prep(dentry, NULL)) {
|
|
printk(KERN_ERR "configfs: Tried to unregister non-empty subsystem!\n");
|
|
printk(KERN_ERR "configfs: Tried to unregister non-empty subsystem!\n");
|
|
}
|
|
}
|
|
spin_unlock(&configfs_dirent_lock);
|
|
spin_unlock(&configfs_dirent_lock);
|
|
|
|
+ mutex_unlock(&configfs_symlink_mutex);
|
|
configfs_detach_group(&group->cg_item);
|
|
configfs_detach_group(&group->cg_item);
|
|
dentry->d_inode->i_flags |= S_DEAD;
|
|
dentry->d_inode->i_flags |= S_DEAD;
|
|
mutex_unlock(&dentry->d_inode->i_mutex);
|
|
mutex_unlock(&dentry->d_inode->i_mutex);
|