aboutsummaryrefslogtreecommitdiffstats
path: root/fs/configfs/dir.c
diff options
context:
space:
mode:
authorJoel Becker <joel.becker@oracle.com>2006-04-12 00:37:20 -0400
committerMark Fasheh <mark.fasheh@oracle.com>2006-05-17 17:38:51 -0400
commiteed7a0db460595b139428d252798a83f1e1ce1d3 (patch)
tree129db180cb8bac9810b6168802914c5ae2f619a3 /fs/configfs/dir.c
parent84efad1a53dd05969094f9a2562b4e6666571c00 (diff)
configfs: configfs_mkdir() failed to cleanup linkage.
If configfs_mkdir() errored in certain ways after the parent<->child linkage was already created, it would not undo the linkage. Also, comment the reference counting for clarity. Signed-off-by: Joel Becker <joel.becker@oracle.com> Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>
Diffstat (limited to 'fs/configfs/dir.c')
-rw-r--r--fs/configfs/dir.c104
1 files changed, 72 insertions, 32 deletions
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
index 810c1395d6b2..5f952187fc53 100644
--- a/fs/configfs/dir.c
+++ b/fs/configfs/dir.c
@@ -505,13 +505,15 @@ static int populate_groups(struct config_group *group)
505 int i; 505 int i;
506 506
507 if (group->default_groups) { 507 if (group->default_groups) {
508 /* FYI, we're faking mkdir here 508 /*
509 * FYI, we're faking mkdir here
509 * I'm not sure we need this semaphore, as we're called 510 * I'm not sure we need this semaphore, as we're called
510 * from our parent's mkdir. That holds our parent's 511 * from our parent's mkdir. That holds our parent's
511 * i_mutex, so afaik lookup cannot continue through our 512 * i_mutex, so afaik lookup cannot continue through our
512 * parent to find us, let alone mess with our tree. 513 * parent to find us, let alone mess with our tree.
513 * That said, taking our i_mutex is closer to mkdir 514 * That said, taking our i_mutex is closer to mkdir
514 * emulation, and shouldn't hurt. */ 515 * emulation, and shouldn't hurt.
516 */
515 mutex_lock(&dentry->d_inode->i_mutex); 517 mutex_lock(&dentry->d_inode->i_mutex);
516 518
517 for (i = 0; group->default_groups[i]; i++) { 519 for (i = 0; group->default_groups[i]; i++) {
@@ -546,20 +548,34 @@ static void unlink_obj(struct config_item *item)
546 548
547 item->ci_group = NULL; 549 item->ci_group = NULL;
548 item->ci_parent = NULL; 550 item->ci_parent = NULL;
551
552 /* Drop the reference for ci_entry */
549 config_item_put(item); 553 config_item_put(item);
550 554
555 /* Drop the reference for ci_parent */
551 config_group_put(group); 556 config_group_put(group);
552 } 557 }
553} 558}
554 559
555static void link_obj(struct config_item *parent_item, struct config_item *item) 560static void link_obj(struct config_item *parent_item, struct config_item *item)
556{ 561{
557 /* Parent seems redundant with group, but it makes certain 562 /*
558 * traversals much nicer. */ 563 * Parent seems redundant with group, but it makes certain
564 * traversals much nicer.
565 */
559 item->ci_parent = parent_item; 566 item->ci_parent = parent_item;
567
568 /*
569 * We hold a reference on the parent for the child's ci_parent
570 * link.
571 */
560 item->ci_group = config_group_get(to_config_group(parent_item)); 572 item->ci_group = config_group_get(to_config_group(parent_item));
561 list_add_tail(&item->ci_entry, &item->ci_group->cg_children); 573 list_add_tail(&item->ci_entry, &item->ci_group->cg_children);
562 574
575 /*
576 * We hold a reference on the child for ci_entry on the parent's
577 * cg_children
578 */
563 config_item_get(item); 579 config_item_get(item);
564} 580}
565 581
@@ -684,6 +700,10 @@ static void client_drop_item(struct config_item *parent_item,
684 type = parent_item->ci_type; 700 type = parent_item->ci_type;
685 BUG_ON(!type); 701 BUG_ON(!type);
686 702
703 /*
704 * If ->drop_item() exists, it is responsible for the
705 * config_item_put().
706 */
687 if (type->ct_group_ops && type->ct_group_ops->drop_item) 707 if (type->ct_group_ops && type->ct_group_ops->drop_item)
688 type->ct_group_ops->drop_item(to_config_group(parent_item), 708 type->ct_group_ops->drop_item(to_config_group(parent_item),
689 item); 709 item);
@@ -694,14 +714,14 @@ static void client_drop_item(struct config_item *parent_item,
694 714
695static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) 715static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
696{ 716{
697 int ret; 717 int ret, module_got = 0;
698 struct config_group *group; 718 struct config_group *group;
699 struct config_item *item; 719 struct config_item *item;
700 struct config_item *parent_item; 720 struct config_item *parent_item;
701 struct configfs_subsystem *subsys; 721 struct configfs_subsystem *subsys;
702 struct configfs_dirent *sd; 722 struct configfs_dirent *sd;
703 struct config_item_type *type; 723 struct config_item_type *type;
704 struct module *owner; 724 struct module *owner = NULL;
705 char *name; 725 char *name;
706 726
707 if (dentry->d_parent == configfs_sb->s_root) { 727 if (dentry->d_parent == configfs_sb->s_root) {
@@ -754,43 +774,63 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
754 774
755 kfree(name); 775 kfree(name);
756 if (!item) { 776 if (!item) {
777 /*
778 * If item == NULL, then link_obj() was never called.
779 * There are no extra references to clean up.
780 */
757 ret = -ENOMEM; 781 ret = -ENOMEM;
758 goto out_put; 782 goto out_put;
759 } 783 }
760 784
761 ret = -EINVAL; 785 /*
786 * link_obj() has been called (via link_group() for groups).
787 * From here on out, errors must clean that up.
788 */
789
762 type = item->ci_type; 790 type = item->ci_type;
763 if (type) { 791 if (!type) {
764 owner = type->ct_owner; 792 ret = -EINVAL;
765 if (try_module_get(owner)) { 793 goto out_unlink;
766 if (group) { 794 }
767 ret = configfs_attach_group(parent_item,
768 item,
769 dentry);
770 } else {
771 ret = configfs_attach_item(parent_item,
772 item,
773 dentry);
774 }
775 795
776 if (ret) { 796 owner = type->ct_owner;
777 down(&subsys->su_sem); 797 if (!try_module_get(owner)) {
778 if (group) 798 ret = -EINVAL;
779 unlink_group(group); 799 goto out_unlink;
780 else 800 }
781 unlink_obj(item);
782 client_drop_item(parent_item, item);
783 up(&subsys->su_sem);
784 801
785 module_put(owner); 802 /*
786 } 803 * I hate doing it this way, but if there is
787 } 804 * an error, module_put() probably should
805 * happen after any cleanup.
806 */
807 module_got = 1;
808
809 if (group)
810 ret = configfs_attach_group(parent_item, item, dentry);
811 else
812 ret = configfs_attach_item(parent_item, item, dentry);
813
814out_unlink:
815 if (ret) {
816 /* Tear down everything we built up */
817 down(&subsys->su_sem);
818 if (group)
819 unlink_group(group);
820 else
821 unlink_obj(item);
822 client_drop_item(parent_item, item);
823 up(&subsys->su_sem);
824
825 if (module_got)
826 module_put(owner);
788 } 827 }
789 828
790out_put: 829out_put:
791 /* 830 /*
792 * link_obj()/link_group() took a reference from child->parent. 831 * link_obj()/link_group() took a reference from child->parent,
793 * Drop our working ref 832 * so the parent is safely pinned. We can drop our working
833 * reference.
794 */ 834 */
795 config_item_put(parent_item); 835 config_item_put(parent_item);
796 836