]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
configfs: accessing item hierarchy during rmdir(2)
authorJoel Becker <joel.becker@oracle.com>
Sat, 7 Oct 2006 00:33:23 +0000 (17:33 -0700)
committerMark Fasheh <mark.fasheh@oracle.com>
Wed, 11 Jul 2007 00:11:01 +0000 (17:11 -0700)
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>
Documentation/filesystems/configfs/configfs.txt
fs/configfs/dir.c
include/linux/configfs.h

index 21f038e66724702dee5ce7aca4a0ae661991c637..aef74cdecc21fe636cd30a929e4153c5349568bf 100644 (file)
@@ -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);
                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);
        };
                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.
 
 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
 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
index d3b1dbb9b5b8f6a8a4b43b0cd6199d29f6baa9ce..125954723eb701d4f1e2ef80e5ef0e44075e0c42 100644 (file)
@@ -713,6 +713,28 @@ static void configfs_detach_group(struct config_item *item)
        configfs_detach_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
 /*
  * 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),
         */
        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);
 }
        else
                config_item_put(item);
 }
@@ -842,11 +864,14 @@ out_unlink:
        if (ret) {
                /* Tear down everything we built up */
                mutex_lock(&subsys->su_mutex);
        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);
                if (group)
                        unlink_group(group);
                else
                        unlink_obj(item);
                client_drop_item(parent_item, item);
+
                mutex_unlock(&subsys->su_mutex);
 
                if (module_got)
                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);
                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);
                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);
        }
 
                unlink_obj(item);
        }
 
index 5ce0fc4e3b5bdb071a9bf545f3a8fd0dbd51ebdc..8227e730dac7097f73cbd8259d6588dc00439e2d 100644 (file)
@@ -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);
        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);
 };
 
        void (*drop_item)(struct config_group *group, struct config_item *item);
 };