diff options
-rw-r--r-- | Documentation/filesystems/configfs/configfs.txt | 12 | ||||
-rw-r--r-- | fs/configfs/dir.c | 29 | ||||
-rw-r--r-- | include/linux/configfs.h | 1 |
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 | |||
268 | for the item to actually disappear from the subsystem's usage. But it | 270 | for the item to actually disappear from the subsystem's usage. But it |
269 | is gone from configfs. | 271 | is gone from configfs. |
270 | 272 | ||
273 | When drop_item() is called, the item's linkage has already been torn | ||
274 | down. It no longer has a reference on its parent and has no place in | ||
275 | the item hierarchy. If a client needs to do some cleanup before this | ||
276 | teardown happens, the subsystem can implement the | ||
277 | ct_group_ops->disconnect_notify() method. The method is called after | ||
278 | configfs has removed the item from the filesystem view but before the | ||
279 | item is removed from its parent group. Like drop_item(), | ||
280 | disconnect_notify() is void and cannot fail. Client subsystems should | ||
281 | not drop any references here, as they still must do it in drop_item(). | ||
282 | |||
271 | A config_group cannot be removed while it still has child items. This | 283 | A config_group cannot be removed while it still has child items. This |
272 | is implemented in the configfs rmdir(2) code. ->drop_item() will not be | 284 | is implemented in the configfs rmdir(2) code. ->drop_item() will not be |
273 | called, as the item has not been dropped. rmdir(2) will fail, as the | 285 | called, 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 | */ | ||
725 | static 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 | ||