aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/filesystems/configfs/configfs.txt12
-rw-r--r--fs/configfs/dir.c29
-rw-r--r--include/linux/configfs.h1
3 files changed, 41 insertions, 1 deletions
diff --git a/Documentation/filesystems/configfs/configfs.txt b/Documentation/filesystems/configfs/configfs.txt
index 21f038e66724..aef74cdecc21 100644
--- a/Documentation/filesystems/configfs/configfs.txt
+++ b/Documentation/filesystems/configfs/configfs.txt
@@ -238,6 +238,8 @@ config_item_type.
238 struct config_group *(*make_group)(struct config_group *group, 238 struct config_group *(*make_group)(struct config_group *group,
239 const char *name); 239 const char *name);
240 int (*commit_item)(struct config_item *item); 240 int (*commit_item)(struct config_item *item);
241 void (*disconnect_notify)(struct config_group *group,
242 struct config_item *item);
241 void (*drop_item)(struct config_group *group, 243 void (*drop_item)(struct config_group *group,
242 struct config_item *item); 244 struct config_item *item);
243 }; 245 };
@@ -268,6 +270,16 @@ the item in other threads, the memory is safe. It may take some time
268for the item to actually disappear from the subsystem's usage. But it 270for the item to actually disappear from the subsystem's usage. But it
269is gone from configfs. 271is gone from configfs.
270 272
273When drop_item() is called, the item's linkage has already been torn
274down. It no longer has a reference on its parent and has no place in
275the item hierarchy. If a client needs to do some cleanup before this
276teardown happens, the subsystem can implement the
277ct_group_ops->disconnect_notify() method. The method is called after
278configfs has removed the item from the filesystem view but before the
279item is removed from its parent group. Like drop_item(),
280disconnect_notify() is void and cannot fail. Client subsystems should
281not drop any references here, as they still must do it in drop_item().
282
271A config_group cannot be removed while it still has child items. This 283A config_group cannot be removed while it still has child items. This
272is implemented in the configfs rmdir(2) code. ->drop_item() will not be 284is implemented in the configfs rmdir(2) code. ->drop_item() will not be
273called, as the item has not been dropped. rmdir(2) will fail, as the 285called, as the item has not been dropped. rmdir(2) will fail, as the
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
index d3b1dbb9b5b8..125954723eb7 100644
--- a/fs/configfs/dir.c
+++ b/fs/configfs/dir.c
@@ -714,6 +714,28 @@ static void configfs_detach_group(struct config_item *item)
714} 714}
715 715
716/* 716/*
717 * After the item has been detached from the filesystem view, we are
718 * ready to tear it out of the hierarchy. Notify the client before
719 * we do that so they can perform any cleanup that requires
720 * navigating the hierarchy. A client does not need to provide this
721 * callback. The subsystem semaphore MUST be held by the caller, and
722 * references must be valid for both items. It also assumes the
723 * caller has validated ci_type.
724 */
725static void client_disconnect_notify(struct config_item *parent_item,
726 struct config_item *item)
727{
728 struct config_item_type *type;
729
730 type = parent_item->ci_type;
731 BUG_ON(!type);
732
733 if (type->ct_group_ops && type->ct_group_ops->disconnect_notify)
734 type->ct_group_ops->disconnect_notify(to_config_group(parent_item),
735 item);
736}
737
738/*
717 * Drop the initial reference from make_item()/make_group() 739 * Drop the initial reference from make_item()/make_group()
718 * This function assumes that reference is held on item 740 * This function assumes that reference is held on item
719 * and that item holds a valid reference to the parent. Also, it 741 * and that item holds a valid reference to the parent. Also, it
@@ -733,7 +755,7 @@ static void client_drop_item(struct config_item *parent_item,
733 */ 755 */
734 if (type->ct_group_ops && type->ct_group_ops->drop_item) 756 if (type->ct_group_ops && type->ct_group_ops->drop_item)
735 type->ct_group_ops->drop_item(to_config_group(parent_item), 757 type->ct_group_ops->drop_item(to_config_group(parent_item),
736 item); 758 item);
737 else 759 else
738 config_item_put(item); 760 config_item_put(item);
739} 761}
@@ -842,11 +864,14 @@ out_unlink:
842 if (ret) { 864 if (ret) {
843 /* Tear down everything we built up */ 865 /* Tear down everything we built up */
844 mutex_lock(&subsys->su_mutex); 866 mutex_lock(&subsys->su_mutex);
867
868 client_disconnect_notify(parent_item, item);
845 if (group) 869 if (group)
846 unlink_group(group); 870 unlink_group(group);
847 else 871 else
848 unlink_obj(item); 872 unlink_obj(item);
849 client_drop_item(parent_item, item); 873 client_drop_item(parent_item, item);
874
850 mutex_unlock(&subsys->su_mutex); 875 mutex_unlock(&subsys->su_mutex);
851 876
852 if (module_got) 877 if (module_got)
@@ -911,11 +936,13 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry)
911 configfs_detach_group(item); 936 configfs_detach_group(item);
912 937
913 mutex_lock(&subsys->su_mutex); 938 mutex_lock(&subsys->su_mutex);
939 client_disconnect_notify(parent_item, item);
914 unlink_group(to_config_group(item)); 940 unlink_group(to_config_group(item));
915 } else { 941 } else {
916 configfs_detach_item(item); 942 configfs_detach_item(item);
917 943
918 mutex_lock(&subsys->su_mutex); 944 mutex_lock(&subsys->su_mutex);
945 client_disconnect_notify(parent_item, item);
919 unlink_obj(item); 946 unlink_obj(item);
920 } 947 }
921 948
diff --git a/include/linux/configfs.h b/include/linux/configfs.h
index 5ce0fc4e3b5b..8227e730dac7 100644
--- a/include/linux/configfs.h
+++ b/include/linux/configfs.h
@@ -169,6 +169,7 @@ struct configfs_group_operations {
169 struct config_item *(*make_item)(struct config_group *group, const char *name); 169 struct config_item *(*make_item)(struct config_group *group, const char *name);
170 struct config_group *(*make_group)(struct config_group *group, const char *name); 170 struct config_group *(*make_group)(struct config_group *group, const char *name);
171 int (*commit_item)(struct config_item *item); 171 int (*commit_item)(struct config_item *item);
172 void (*disconnect_notify)(struct config_group *group, struct config_item *item);
172 void (*drop_item)(struct config_group *group, struct config_item *item); 173 void (*drop_item)(struct config_group *group, struct config_item *item);
173}; 174};
174 175