configfs: accessing item hierarchy during rmdir(2)
Add a notification callback, ops->disconnect_notify(). It has the same prototype as ->drop_item(), but it will be called just before the item linkage is broken. This way, configfs users who want to do work while the object is still in the heirarchy have a chance. Client drivers will still need to config_item_put() in their ->drop_item(), if they implement it. They need do nothing in ->disconnect_notify(). They don't have to provide it if they don't care. But someone who wants to be notified before ci_parent is set to NULL can now be notified. Signed-off-by: Joel Becker <joel.becker@oracle.com> Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>
This commit is contained in:
		
							parent
							
								
									6d748924b7
								
							
						
					
					
						commit
						299894cc90
					
				| @ -238,6 +238,8 @@ config_item_type. | ||||
| 		struct config_group *(*make_group)(struct config_group *group, | ||||
| 						   const char *name); | ||||
| 		int (*commit_item)(struct config_item *item); | ||||
| 		void (*disconnect_notify)(struct config_group *group, | ||||
| 					  struct config_item *item); | ||||
| 		void (*drop_item)(struct config_group *group, | ||||
| 				  struct config_item *item); | ||||
| 	}; | ||||
| @ -268,6 +270,16 @@ the item in other threads, the memory is safe.  It may take some time | ||||
| for the item to actually disappear from the subsystem's usage.  But it | ||||
| is gone from configfs. | ||||
| 
 | ||||
| When drop_item() is called, the item's linkage has already been torn | ||||
| down.  It no longer has a reference on its parent and has no place in | ||||
| the item hierarchy.  If a client needs to do some cleanup before this | ||||
| teardown happens, the subsystem can implement the | ||||
| ct_group_ops->disconnect_notify() method.  The method is called after | ||||
| configfs has removed the item from the filesystem view but before the | ||||
| item is removed from its parent group.  Like drop_item(), | ||||
| disconnect_notify() is void and cannot fail.  Client subsystems should | ||||
| not drop any references here, as they still must do it in drop_item(). | ||||
| 
 | ||||
| A config_group cannot be removed while it still has child items.  This | ||||
| is implemented in the configfs rmdir(2) code.  ->drop_item() will not be | ||||
| called, as the item has not been dropped.  rmdir(2) will fail, as the | ||||
|  | ||||
| @ -713,6 +713,28 @@ static void configfs_detach_group(struct config_item *item) | ||||
| 	configfs_detach_item(item); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * After the item has been detached from the filesystem view, we are | ||||
|  * ready to tear it out of the hierarchy.  Notify the client before | ||||
|  * we do that so they can perform any cleanup that requires | ||||
|  * navigating the hierarchy.  A client does not need to provide this | ||||
|  * callback.  The subsystem semaphore MUST be held by the caller, and | ||||
|  * references must be valid for both items.  It also assumes the | ||||
|  * caller has validated ci_type. | ||||
|  */ | ||||
| static void client_disconnect_notify(struct config_item *parent_item, | ||||
| 				     struct config_item *item) | ||||
| { | ||||
| 	struct config_item_type *type; | ||||
| 
 | ||||
| 	type = parent_item->ci_type; | ||||
| 	BUG_ON(!type); | ||||
| 
 | ||||
| 	if (type->ct_group_ops && type->ct_group_ops->disconnect_notify) | ||||
| 		type->ct_group_ops->disconnect_notify(to_config_group(parent_item), | ||||
| 						      item); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Drop the initial reference from make_item()/make_group() | ||||
|  * This function assumes that reference is held on item | ||||
| @ -733,7 +755,7 @@ static void client_drop_item(struct config_item *parent_item, | ||||
| 	 */ | ||||
| 	if (type->ct_group_ops && type->ct_group_ops->drop_item) | ||||
| 		type->ct_group_ops->drop_item(to_config_group(parent_item), | ||||
| 						item); | ||||
| 					      item); | ||||
| 	else | ||||
| 		config_item_put(item); | ||||
| } | ||||
| @ -842,11 +864,14 @@ out_unlink: | ||||
| 	if (ret) { | ||||
| 		/* Tear down everything we built up */ | ||||
| 		mutex_lock(&subsys->su_mutex); | ||||
| 
 | ||||
| 		client_disconnect_notify(parent_item, item); | ||||
| 		if (group) | ||||
| 			unlink_group(group); | ||||
| 		else | ||||
| 			unlink_obj(item); | ||||
| 		client_drop_item(parent_item, item); | ||||
| 
 | ||||
| 		mutex_unlock(&subsys->su_mutex); | ||||
| 
 | ||||
| 		if (module_got) | ||||
| @ -911,11 +936,13 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry) | ||||
| 		configfs_detach_group(item); | ||||
| 
 | ||||
| 		mutex_lock(&subsys->su_mutex); | ||||
| 		client_disconnect_notify(parent_item, item); | ||||
| 		unlink_group(to_config_group(item)); | ||||
| 	} else { | ||||
| 		configfs_detach_item(item); | ||||
| 
 | ||||
| 		mutex_lock(&subsys->su_mutex); | ||||
| 		client_disconnect_notify(parent_item, item); | ||||
| 		unlink_obj(item); | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
| @ -169,6 +169,7 @@ struct configfs_group_operations { | ||||
| 	struct config_item *(*make_item)(struct config_group *group, const char *name); | ||||
| 	struct config_group *(*make_group)(struct config_group *group, const char *name); | ||||
| 	int (*commit_item)(struct config_item *item); | ||||
| 	void (*disconnect_notify)(struct config_group *group, struct config_item *item); | ||||
| 	void (*drop_item)(struct config_group *group, struct config_item *item); | ||||
| }; | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user