wrappers for ->i_mutex access
[deliverable/linux.git] / fs / configfs / dir.c
index 7ae97e83f12154a52b90642d2a7b557e956c86e1..f419519ec41fb4f3e932fe18561b34f3313e747b 100644 (file)
@@ -640,13 +640,13 @@ static void detach_groups(struct config_group *group)
 
                child = sd->s_dentry;
 
-               mutex_lock(&d_inode(child)->i_mutex);
+               inode_lock(d_inode(child));
 
                configfs_detach_group(sd->s_element);
                d_inode(child)->i_flags |= S_DEAD;
                dont_mount(child);
 
-               mutex_unlock(&d_inode(child)->i_mutex);
+               inode_unlock(d_inode(child));
 
                d_delete(child);
                dput(child);
@@ -834,11 +834,11 @@ static int configfs_attach_item(struct config_item *parent_item,
                         * the VFS may already have hit and used them. Thus,
                         * we must lock them as rmdir() would.
                         */
-                       mutex_lock(&d_inode(dentry)->i_mutex);
+                       inode_lock(d_inode(dentry));
                        configfs_remove_dir(item);
                        d_inode(dentry)->i_flags |= S_DEAD;
                        dont_mount(dentry);
-                       mutex_unlock(&d_inode(dentry)->i_mutex);
+                       inode_unlock(d_inode(dentry));
                        d_delete(dentry);
                }
        }
@@ -874,7 +874,7 @@ static int configfs_attach_group(struct config_item *parent_item,
                 * We must also lock the inode to remove it safely in case of
                 * error, as rmdir() would.
                 */
-               mutex_lock_nested(&d_inode(dentry)->i_mutex, I_MUTEX_CHILD);
+               inode_lock_nested(d_inode(dentry), I_MUTEX_CHILD);
                configfs_adjust_dir_dirent_depth_before_populate(sd);
                ret = populate_groups(to_config_group(item));
                if (ret) {
@@ -883,7 +883,7 @@ static int configfs_attach_group(struct config_item *parent_item,
                        dont_mount(dentry);
                }
                configfs_adjust_dir_dirent_depth_after_populate(sd);
-               mutex_unlock(&d_inode(dentry)->i_mutex);
+               inode_unlock(d_inode(dentry));
                if (ret)
                        d_delete(dentry);
        }
@@ -1070,11 +1070,55 @@ out:
        return ret;
 }
 
+static int configfs_do_depend_item(struct dentry *subsys_dentry,
+                                  struct config_item *target)
+{
+       struct configfs_dirent *p;
+       int ret;
+
+       spin_lock(&configfs_dirent_lock);
+       /* Scan the tree, return 0 if found */
+       ret = configfs_depend_prep(subsys_dentry, target);
+       if (ret)
+               goto out_unlock_dirent_lock;
+
+       /*
+        * We are sure that the item is not about to be removed by rmdir(), and
+        * not in the middle of attachment by mkdir().
+        */
+       p = target->ci_dentry->d_fsdata;
+       p->s_dependent_count += 1;
+
+out_unlock_dirent_lock:
+       spin_unlock(&configfs_dirent_lock);
+
+       return ret;
+}
+
+static inline struct configfs_dirent *
+configfs_find_subsys_dentry(struct configfs_dirent *root_sd,
+                           struct config_item *subsys_item)
+{
+       struct configfs_dirent *p;
+       struct configfs_dirent *ret = NULL;
+
+       list_for_each_entry(p, &root_sd->s_children, s_sibling) {
+               if (p->s_type & CONFIGFS_DIR &&
+                   p->s_element == subsys_item) {
+                       ret = p;
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+
 int configfs_depend_item(struct configfs_subsystem *subsys,
                         struct config_item *target)
 {
        int ret;
-       struct configfs_dirent *p, *root_sd, *subsys_sd = NULL;
+       struct configfs_dirent *subsys_sd;
        struct config_item *s_item = &subsys->su_group.cg_item;
        struct dentry *root;
 
@@ -1091,43 +1135,19 @@ int configfs_depend_item(struct configfs_subsystem *subsys,
         * subsystem is really registered, and so we need to lock out
         * configfs_[un]register_subsystem().
         */
-       mutex_lock(&d_inode(root)->i_mutex);
-
-       root_sd = root->d_fsdata;
-
-       list_for_each_entry(p, &root_sd->s_children, s_sibling) {
-               if (p->s_type & CONFIGFS_DIR) {
-                       if (p->s_element == s_item) {
-                               subsys_sd = p;
-                               break;
-                       }
-               }
-       }
+       inode_lock(d_inode(root));
 
+       subsys_sd = configfs_find_subsys_dentry(root->d_fsdata, s_item);
        if (!subsys_sd) {
                ret = -ENOENT;
                goto out_unlock_fs;
        }
 
        /* Ok, now we can trust subsys/s_item */
+       ret = configfs_do_depend_item(subsys_sd->s_dentry, target);
 
-       spin_lock(&configfs_dirent_lock);
-       /* Scan the tree, return 0 if found */
-       ret = configfs_depend_prep(subsys_sd->s_dentry, target);
-       if (ret)
-               goto out_unlock_dirent_lock;
-
-       /*
-        * We are sure that the item is not about to be removed by rmdir(), and
-        * not in the middle of attachment by mkdir().
-        */
-       p = target->ci_dentry->d_fsdata;
-       p->s_dependent_count += 1;
-
-out_unlock_dirent_lock:
-       spin_unlock(&configfs_dirent_lock);
 out_unlock_fs:
-       mutex_unlock(&d_inode(root)->i_mutex);
+       inode_unlock(d_inode(root));
 
        /*
         * If we succeeded, the fs is pinned via other methods.  If not,
@@ -1144,8 +1164,7 @@ EXPORT_SYMBOL(configfs_depend_item);
  * configfs_depend_item() because we know that that the client driver is
  * pinned, thus the subsystem is pinned, and therefore configfs is pinned.
  */
-void configfs_undepend_item(struct configfs_subsystem *subsys,
-                           struct config_item *target)
+void configfs_undepend_item(struct config_item *target)
 {
        struct configfs_dirent *sd;
 
@@ -1168,6 +1187,79 @@ void configfs_undepend_item(struct configfs_subsystem *subsys,
 }
 EXPORT_SYMBOL(configfs_undepend_item);
 
+/*
+ * caller_subsys is a caller's subsystem not target's. This is used to
+ * determine if we should lock root and check subsys or not. When we are
+ * in the same subsystem as our target there is no need to do locking as
+ * we know that subsys is valid and is not unregistered during this function
+ * as we are called from callback of one of his children and VFS holds a lock
+ * on some inode. Otherwise we have to lock our root to  ensure that target's
+ * subsystem it is not unregistered during this function.
+ */
+int configfs_depend_item_unlocked(struct configfs_subsystem *caller_subsys,
+                                 struct config_item *target)
+{
+       struct configfs_subsystem *target_subsys;
+       struct config_group *root, *parent;
+       struct configfs_dirent *subsys_sd;
+       int ret = -ENOENT;
+
+       /* Disallow this function for configfs root */
+       if (configfs_is_root(target))
+               return -EINVAL;
+
+       parent = target->ci_group;
+       /*
+        * This may happen when someone is trying to depend root
+        * directory of some subsystem
+        */
+       if (configfs_is_root(&parent->cg_item)) {
+               target_subsys = to_configfs_subsystem(to_config_group(target));
+               root = parent;
+       } else {
+               target_subsys = parent->cg_subsys;
+               /* Find a cofnigfs root as we may need it for locking */
+               for (root = parent; !configfs_is_root(&root->cg_item);
+                    root = root->cg_item.ci_group)
+                       ;
+       }
+
+       if (target_subsys != caller_subsys) {
+               /*
+                * We are in other configfs subsystem, so we have to do
+                * additional locking to prevent other subsystem from being
+                * unregistered
+                */
+               inode_lock(d_inode(root->cg_item.ci_dentry));
+
+               /*
+                * As we are trying to depend item from other subsystem
+                * we have to check if this subsystem is still registered
+                */
+               subsys_sd = configfs_find_subsys_dentry(
+                               root->cg_item.ci_dentry->d_fsdata,
+                               &target_subsys->su_group.cg_item);
+               if (!subsys_sd)
+                       goto out_root_unlock;
+       } else {
+               subsys_sd = target_subsys->su_group.cg_item.ci_dentry->d_fsdata;
+       }
+
+       /* Now we can execute core of depend item */
+       ret = configfs_do_depend_item(subsys_sd->s_dentry, target);
+
+       if (target_subsys != caller_subsys)
+out_root_unlock:
+               /*
+                * We were called from subsystem other than our target so we
+                * took some locks so now it's time to release them
+                */
+               inode_unlock(d_inode(root->cg_item.ci_dentry));
+
+       return ret;
+}
+EXPORT_SYMBOL(configfs_depend_item_unlocked);
+
 static int configfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 {
        int ret = 0;
@@ -1469,7 +1561,7 @@ int configfs_rename_dir(struct config_item * item, const char *new_name)
        down_write(&configfs_rename_sem);
        parent = item->parent->dentry;
 
-       mutex_lock(&d_inode(parent)->i_mutex);
+       inode_lock(d_inode(parent));
 
        new_dentry = lookup_one_len(new_name, parent, strlen(new_name));
        if (!IS_ERR(new_dentry)) {
@@ -1485,7 +1577,7 @@ int configfs_rename_dir(struct config_item * item, const char *new_name)
                        error = -EEXIST;
                dput(new_dentry);
        }
-       mutex_unlock(&d_inode(parent)->i_mutex);
+       inode_unlock(d_inode(parent));
        up_write(&configfs_rename_sem);
 
        return error;
@@ -1498,7 +1590,7 @@ static int configfs_dir_open(struct inode *inode, struct file *file)
        struct configfs_dirent * parent_sd = dentry->d_fsdata;
        int err;
 
-       mutex_lock(&d_inode(dentry)->i_mutex);
+       inode_lock(d_inode(dentry));
        /*
         * Fake invisibility if dir belongs to a group/default groups hierarchy
         * being attached
@@ -1511,7 +1603,7 @@ static int configfs_dir_open(struct inode *inode, struct file *file)
                else
                        err = 0;
        }
-       mutex_unlock(&d_inode(dentry)->i_mutex);
+       inode_unlock(d_inode(dentry));
 
        return err;
 }
@@ -1521,11 +1613,11 @@ static int configfs_dir_close(struct inode *inode, struct file *file)
        struct dentry * dentry = file->f_path.dentry;
        struct configfs_dirent * cursor = file->private_data;
 
-       mutex_lock(&d_inode(dentry)->i_mutex);
+       inode_lock(d_inode(dentry));
        spin_lock(&configfs_dirent_lock);
        list_del_init(&cursor->s_sibling);
        spin_unlock(&configfs_dirent_lock);
-       mutex_unlock(&d_inode(dentry)->i_mutex);
+       inode_unlock(d_inode(dentry));
 
        release_configfs_dirent(cursor);
 
@@ -1606,7 +1698,7 @@ static loff_t configfs_dir_lseek(struct file *file, loff_t offset, int whence)
 {
        struct dentry * dentry = file->f_path.dentry;
 
-       mutex_lock(&d_inode(dentry)->i_mutex);
+       inode_lock(d_inode(dentry));
        switch (whence) {
                case 1:
                        offset += file->f_pos;
@@ -1614,7 +1706,7 @@ static loff_t configfs_dir_lseek(struct file *file, loff_t offset, int whence)
                        if (offset >= 0)
                                break;
                default:
-                       mutex_unlock(&d_inode(dentry)->i_mutex);
+                       inode_unlock(d_inode(dentry));
                        return -EINVAL;
        }
        if (offset != file->f_pos) {
@@ -1640,7 +1732,7 @@ static loff_t configfs_dir_lseek(struct file *file, loff_t offset, int whence)
                        spin_unlock(&configfs_dirent_lock);
                }
        }
-       mutex_unlock(&d_inode(dentry)->i_mutex);
+       inode_unlock(d_inode(dentry));
        return offset;
 }
 
@@ -1675,14 +1767,14 @@ int configfs_register_group(struct config_group *parent_group,
 
        parent = parent_group->cg_item.ci_dentry;
 
-       mutex_lock_nested(&d_inode(parent)->i_mutex, I_MUTEX_PARENT);
+       inode_lock_nested(d_inode(parent), I_MUTEX_PARENT);
        ret = create_default_group(parent_group, group);
        if (!ret) {
                spin_lock(&configfs_dirent_lock);
                configfs_dir_set_ready(group->cg_item.ci_dentry->d_fsdata);
                spin_unlock(&configfs_dirent_lock);
        }
-       mutex_unlock(&d_inode(parent)->i_mutex);
+       inode_unlock(d_inode(parent));
        return ret;
 }
 EXPORT_SYMBOL(configfs_register_group);
@@ -1699,7 +1791,7 @@ void configfs_unregister_group(struct config_group *group)
        struct dentry *dentry = group->cg_item.ci_dentry;
        struct dentry *parent = group->cg_item.ci_parent->ci_dentry;
 
-       mutex_lock_nested(&d_inode(parent)->i_mutex, I_MUTEX_PARENT);
+       inode_lock_nested(d_inode(parent), I_MUTEX_PARENT);
        spin_lock(&configfs_dirent_lock);
        configfs_detach_prep(dentry, NULL);
        spin_unlock(&configfs_dirent_lock);
@@ -1708,7 +1800,7 @@ void configfs_unregister_group(struct config_group *group)
        d_inode(dentry)->i_flags |= S_DEAD;
        dont_mount(dentry);
        d_delete(dentry);
-       mutex_unlock(&d_inode(parent)->i_mutex);
+       inode_unlock(d_inode(parent));
 
        dput(dentry);
 
@@ -1780,7 +1872,7 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys)
        sd = root->d_fsdata;
        link_group(to_config_group(sd->s_element), group);
 
-       mutex_lock_nested(&d_inode(root)->i_mutex, I_MUTEX_PARENT);
+       inode_lock_nested(d_inode(root), I_MUTEX_PARENT);
 
        err = -ENOMEM;
        dentry = d_alloc_name(root, group->cg_item.ci_name);
@@ -1800,7 +1892,7 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys)
                }
        }
 
-       mutex_unlock(&d_inode(root)->i_mutex);
+       inode_unlock(d_inode(root));
 
        if (err) {
                unlink_group(group);
@@ -1821,9 +1913,9 @@ void configfs_unregister_subsystem(struct configfs_subsystem *subsys)
                return;
        }
 
-       mutex_lock_nested(&d_inode(root)->i_mutex,
+       inode_lock_nested(d_inode(root),
                          I_MUTEX_PARENT);
-       mutex_lock_nested(&d_inode(dentry)->i_mutex, I_MUTEX_CHILD);
+       inode_lock_nested(d_inode(dentry), I_MUTEX_CHILD);
        mutex_lock(&configfs_symlink_mutex);
        spin_lock(&configfs_dirent_lock);
        if (configfs_detach_prep(dentry, NULL)) {
@@ -1834,11 +1926,11 @@ void configfs_unregister_subsystem(struct configfs_subsystem *subsys)
        configfs_detach_group(&group->cg_item);
        d_inode(dentry)->i_flags |= S_DEAD;
        dont_mount(dentry);
-       mutex_unlock(&d_inode(dentry)->i_mutex);
+       inode_unlock(d_inode(dentry));
 
        d_delete(dentry);
 
-       mutex_unlock(&d_inode(root)->i_mutex);
+       inode_unlock(d_inode(root));
 
        dput(dentry);
 
This page took 0.029948 seconds and 5 git commands to generate.