aboutsummaryrefslogtreecommitdiffstats
path: root/fs/configfs/dir.c
diff options
context:
space:
mode:
authorLouis Rilling <louis.rilling@kerlabs.com>2008-07-04 10:56:06 -0400
committerMark Fasheh <mfasheh@suse.com>2008-07-31 19:21:13 -0400
commit2e2ce171c3ba6f2753fb1fd2706b63683394da2d (patch)
treeb3b75b6b140ab6807754fd500c5a55b0cb7324f8 /fs/configfs/dir.c
parent2a109f2a4155f168047aa2f5b3a170e279bef89a (diff)
[PATCH] configfs: Lock new directory inodes before removing on cleanup after failure
Once a new configfs directory is created by configfs_attach_item() or configfs_attach_group(), a failure in the remaining initialization steps leads to removing a directory which inode the VFS may have already accessed. This commit adds the necessary inode locking to safely remove configfs directories while cleaning up after a failure. As an advantage, the locking rules of populate_groups() and detach_groups() become the same: the caller must have the group's inode mutex locked. Signed-off-by: Louis Rilling <louis.rilling@kerlabs.com> Signed-off-by: Joel Becker <joel.becker@oracle.com> Signed-off-by: Mark Fasheh <mfasheh@suse.com>
Diffstat (limited to 'fs/configfs/dir.c')
-rw-r--r--fs/configfs/dir.c48
1 files changed, 29 insertions, 19 deletions
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
index 647499a3479b..4d11479cf2c3 100644
--- a/fs/configfs/dir.c
+++ b/fs/configfs/dir.c
@@ -324,6 +324,8 @@ static void remove_dir(struct dentry * d)
324 * The only thing special about this is that we remove any files in 324 * The only thing special about this is that we remove any files in
325 * the directory before we remove the directory, and we've inlined 325 * the directory before we remove the directory, and we've inlined
326 * what used to be configfs_rmdir() below, instead of calling separately. 326 * what used to be configfs_rmdir() below, instead of calling separately.
327 *
328 * Caller holds the mutex of the item's inode
327 */ 329 */
328 330
329static void configfs_remove_dir(struct config_item * item) 331static void configfs_remove_dir(struct config_item * item)
@@ -612,36 +614,21 @@ static int create_default_group(struct config_group *parent_group,
612static int populate_groups(struct config_group *group) 614static int populate_groups(struct config_group *group)
613{ 615{
614 struct config_group *new_group; 616 struct config_group *new_group;
615 struct dentry *dentry = group->cg_item.ci_dentry;
616 int ret = 0; 617 int ret = 0;
617 int i; 618 int i;
618 619
619 if (group->default_groups) { 620 if (group->default_groups) {
620 /*
621 * FYI, we're faking mkdir here
622 * I'm not sure we need this semaphore, as we're called
623 * from our parent's mkdir. That holds our parent's
624 * i_mutex, so afaik lookup cannot continue through our
625 * parent to find us, let alone mess with our tree.
626 * That said, taking our i_mutex is closer to mkdir
627 * emulation, and shouldn't hurt.
628 */
629 mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD);
630
631 for (i = 0; group->default_groups[i]; i++) { 621 for (i = 0; group->default_groups[i]; i++) {
632 new_group = group->default_groups[i]; 622 new_group = group->default_groups[i];
633 623
634 ret = create_default_group(group, new_group); 624 ret = create_default_group(group, new_group);
635 if (ret) 625 if (ret) {
626 detach_groups(group);
636 break; 627 break;
628 }
637 } 629 }
638
639 mutex_unlock(&dentry->d_inode->i_mutex);
640 } 630 }
641 631
642 if (ret)
643 detach_groups(group);
644
645 return ret; 632 return ret;
646} 633}
647 634
@@ -756,7 +743,15 @@ static int configfs_attach_item(struct config_item *parent_item,
756 if (!ret) { 743 if (!ret) {
757 ret = populate_attrs(item); 744 ret = populate_attrs(item);
758 if (ret) { 745 if (ret) {
746 /*
747 * We are going to remove an inode and its dentry but
748 * the VFS may already have hit and used them. Thus,
749 * we must lock them as rmdir() would.
750 */
751 mutex_lock(&dentry->d_inode->i_mutex);
759 configfs_remove_dir(item); 752 configfs_remove_dir(item);
753 dentry->d_inode->i_flags |= S_DEAD;
754 mutex_unlock(&dentry->d_inode->i_mutex);
760 d_delete(dentry); 755 d_delete(dentry);
761 } 756 }
762 } 757 }
@@ -764,6 +759,7 @@ static int configfs_attach_item(struct config_item *parent_item,
764 return ret; 759 return ret;
765} 760}
766 761
762/* Caller holds the mutex of the item's inode */
767static void configfs_detach_item(struct config_item *item) 763static void configfs_detach_item(struct config_item *item)
768{ 764{
769 detach_attrs(item); 765 detach_attrs(item);
@@ -782,16 +778,30 @@ static int configfs_attach_group(struct config_item *parent_item,
782 sd = dentry->d_fsdata; 778 sd = dentry->d_fsdata;
783 sd->s_type |= CONFIGFS_USET_DIR; 779 sd->s_type |= CONFIGFS_USET_DIR;
784 780
781 /*
782 * FYI, we're faking mkdir in populate_groups()
783 * We must lock the group's inode to avoid races with the VFS
784 * which can already hit the inode and try to add/remove entries
785 * under it.
786 *
787 * We must also lock the inode to remove it safely in case of
788 * error, as rmdir() would.
789 */
790 mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD);
785 ret = populate_groups(to_config_group(item)); 791 ret = populate_groups(to_config_group(item));
786 if (ret) { 792 if (ret) {
787 configfs_detach_item(item); 793 configfs_detach_item(item);
788 d_delete(dentry); 794 dentry->d_inode->i_flags |= S_DEAD;
789 } 795 }
796 mutex_unlock(&dentry->d_inode->i_mutex);
797 if (ret)
798 d_delete(dentry);
790 } 799 }
791 800
792 return ret; 801 return ret;
793} 802}
794 803
804/* Caller holds the mutex of the group's inode */
795static void configfs_detach_group(struct config_item *item) 805static void configfs_detach_group(struct config_item *item)
796{ 806{
797 detach_groups(to_config_group(item)); 807 detach_groups(to_config_group(item));