cregit-Linux how code gets into the kernel

Release 4.10 fs/configfs/dir.c

Directory: fs/configfs
/* -*- mode: c; c-basic-offset: 8; -*-
 * vim: noexpandtab sw=8 ts=8 sts=0:
 *
 * dir.c - Operations for configfs directories.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 021110-1307, USA.
 *
 * Based on sysfs:
 *      sysfs is Copyright (C) 2001, 2002, 2003 Patrick Mochel
 *
 * configfs Copyright (C) 2005 Oracle.  All rights reserved.
 */


#undef DEBUG

#include <linux/fs.h>
#include <linux/mount.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/err.h>

#include <linux/configfs.h>
#include "configfs_internal.h"


DECLARE_RWSEM(configfs_rename_sem);
/*
 * Protects mutations of configfs_dirent linkage together with proper i_mutex
 * Also protects mutations of symlinks linkage to target configfs_dirent
 * Mutators of configfs_dirent linkage must *both* have the proper inode locked
 * and configfs_dirent_lock locked, in that order.
 * This allows one to safely traverse configfs_dirent trees and symlinks without
 * having to lock inodes.
 *
 * Protects setting of CONFIGFS_USET_DROPPING: checking the flag
 * unlocked is not reliable unless in detach_groups() called from
 * rmdir()/unregister() and from configfs_attach_group()
 */

DEFINE_SPINLOCK(configfs_dirent_lock);


static void configfs_d_iput(struct dentry * dentry, struct inode * inode) { struct configfs_dirent *sd = dentry->d_fsdata; if (sd) { /* Coordinate with configfs_readdir */ spin_lock(&configfs_dirent_lock); /* Coordinate with configfs_attach_attr where will increase * sd->s_count and update sd->s_dentry to new allocated one. * Only set sd->dentry to null when this dentry is the only * sd owner. * If not do so, configfs_d_iput may run just after * configfs_attach_attr and set sd->s_dentry to null * even it's still in use. */ if (atomic_read(&sd->s_count) <= 2) sd->s_dentry = NULL; spin_unlock(&configfs_dirent_lock); configfs_put(sd); } iput(inode); }

Contributors

PersonTokensPropCommitsCommitProp
joel beckerjoel becker6082.19%266.67%
junxiao bijunxiao bi1317.81%133.33%
Total73100.00%3100.00%

const struct dentry_operations configfs_dentry_ops = { .d_iput = configfs_d_iput, .d_delete = always_delete_dentry, }; #ifdef CONFIG_LOCKDEP /* * Helpers to make lockdep happy with our recursive locking of default groups' * inodes (see configfs_attach_group() and configfs_detach_group()). * We put default groups i_mutexes in separate classes according to their depth * from the youngest non-default group ancestor. * * For a non-default group A having default groups A/B, A/C, and A/C/D, default * groups A/B and A/C will have their inode's mutex in class * default_group_class[0], and default group A/C/D will be in * default_group_class[1]. * * The lock classes are declared and assigned in inode.c, according to the * s_depth value. * The s_depth value is initialized to -1, adjusted to >= 0 when attaching * default groups, and reset to -1 when all default groups are attached. During * attachment, if configfs_create() sees s_depth > 0, the lock class of the new * inode's mutex is set to default_group_class[s_depth - 1]. */
static void configfs_init_dirent_depth(struct configfs_dirent *sd) { sd->s_depth = -1; }

Contributors

PersonTokensPropCommitsCommitProp
louis rillinglouis rilling18100.00%1100.00%
Total18100.00%1100.00%


static void configfs_set_dir_dirent_depth(struct configfs_dirent *parent_sd, struct configfs_dirent *sd) { int parent_depth = parent_sd->s_depth; if (parent_depth >= 0) sd->s_depth = parent_depth + 1; }

Contributors

PersonTokensPropCommitsCommitProp
louis rillinglouis rilling37100.00%1100.00%
Total37100.00%1100.00%


static void configfs_adjust_dir_dirent_depth_before_populate(struct configfs_dirent *sd) { /* * item's i_mutex class is already setup, so s_depth is now only * used to set new sub-directories s_depth, which is always done * with item's i_mutex locked. */ /* * sd->s_depth == -1 iff we are a non default group. * else (we are a default group) sd->s_depth > 0 (see * create_dir()). */ if (sd->s_depth == -1) /* * We are a non default group and we are going to create * default groups. */ sd->s_depth = 0; }

Contributors

PersonTokensPropCommitsCommitProp
louis rillinglouis rilling29100.00%1100.00%
Total29100.00%1100.00%


static void configfs_adjust_dir_dirent_depth_after_populate(struct configfs_dirent *sd) { /* We will not create default groups anymore. */ sd->s_depth = -1; }

Contributors

PersonTokensPropCommitsCommitProp
louis rillinglouis rilling19100.00%1100.00%
Total19100.00%1100.00%

#else /* CONFIG_LOCKDEP */
static void configfs_init_dirent_depth(struct configfs_dirent *sd) { }

Contributors

PersonTokensPropCommitsCommitProp
louis rillinglouis rilling10100.00%1100.00%
Total10100.00%1100.00%


static void configfs_set_dir_dirent_depth(struct configfs_dirent *parent_sd, struct configfs_dirent *sd) { }

Contributors

PersonTokensPropCommitsCommitProp
louis rillinglouis rilling15100.00%1100.00%
Total15100.00%1100.00%


static void configfs_adjust_dir_dirent_depth_before_populate(struct configfs_dirent *sd) { }

Contributors

PersonTokensPropCommitsCommitProp
louis rillinglouis rilling10100.00%1100.00%
Total10100.00%1100.00%


static void configfs_adjust_dir_dirent_depth_after_populate(struct configfs_dirent *sd) { }

Contributors

PersonTokensPropCommitsCommitProp
louis rillinglouis rilling10100.00%1100.00%
Total10100.00%1100.00%

#endif /* CONFIG_LOCKDEP */ /* * Allocates a new configfs_dirent and links it to the parent configfs_dirent */
static struct configfs_dirent *configfs_new_dirent(struct configfs_dirent *parent_sd, void *element, int type) { struct configfs_dirent * sd; sd = kmem_cache_zalloc(configfs_dir_cachep, GFP_KERNEL); if (!sd) return ERR_PTR(-ENOMEM); atomic_set(&sd->s_count, 1); INIT_LIST_HEAD(&sd->s_links); INIT_LIST_HEAD(&sd->s_children); sd->s_element = element; sd->s_type = type; configfs_init_dirent_depth(sd); spin_lock(&configfs_dirent_lock); if (parent_sd->s_type & CONFIGFS_USET_DROPPING) { spin_unlock(&configfs_dirent_lock); kmem_cache_free(configfs_dir_cachep, sd); return ERR_PTR(-ENOENT); } list_add(&sd->s_sibling, &parent_sd->s_children); spin_unlock(&configfs_dirent_lock); return sd; }

Contributors

PersonTokensPropCommitsCommitProp
joel beckerjoel becker8054.42%225.00%
louis rillinglouis rilling6644.90%562.50%
robert p. j. dayrobert p. j. day10.68%112.50%
Total147100.00%8100.00%

/* * * Return -EEXIST if there is already a configfs element with the same * name for the same parent. * * called with parent inode's i_mutex held */
static int configfs_dirent_exists(struct configfs_dirent *parent_sd, const unsigned char *new) { struct configfs_dirent * sd; list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { if (sd->s_element) { const unsigned char *existing = configfs_get_name(sd); if (strcmp(existing, new)) continue; else return -EEXIST; } } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
joel beckerjoel becker6898.55%150.00%
adrian bunkadrian bunk11.45%150.00%
Total69100.00%2100.00%


int configfs_make_dirent(struct configfs_dirent * parent_sd, struct dentry * dentry, void * element, umode_t mode, int type) { struct configfs_dirent * sd; sd = configfs_new_dirent(parent_sd, element, type); if (IS_ERR(sd)) return PTR_ERR(sd); sd->s_mode = mode; sd->s_dentry = dentry; if (dentry) dentry->d_fsdata = configfs_get(sd); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
joel beckerjoel becker7389.02%133.33%
louis rillinglouis rilling910.98%266.67%
Total82100.00%3100.00%


static void init_dir(struct inode * inode) { inode->i_op = &configfs_dir_inode_operations; inode->i_fop = &configfs_dir_operations; /* directory inodes start off with i_nlink == 2 (for "." entry) */ inc_nlink(inode); }

Contributors

PersonTokensPropCommitsCommitProp
joel beckerjoel becker2787.10%133.33%
dave hansendave hansen39.68%133.33%
al viroal viro13.23%133.33%
Total31100.00%3100.00%


static void configfs_init_file(struct inode * inode) { inode->i_size = PAGE_SIZE; inode->i_fop = &configfs_file_operations; }

Contributors

PersonTokensPropCommitsCommitProp
joel beckerjoel becker2291.67%133.33%
al viroal viro14.17%133.33%
dave hansendave hansen14.17%133.33%
Total24100.00%3100.00%


static void configfs_init_bin_file(struct inode *inode) { inode->i_size = 0; inode->i_fop = &configfs_bin_file_operations; }

Contributors

PersonTokensPropCommitsCommitProp
pantelis antonioupantelis antoniou24100.00%1100.00%
Total24100.00%1100.00%


static void init_symlink(struct inode * inode) { inode->i_op = &configfs_symlink_inode_operations; }

Contributors

PersonTokensPropCommitsCommitProp
joel beckerjoel becker1794.44%150.00%
al viroal viro15.56%150.00%
Total18100.00%2100.00%

/** * configfs_create_dir - create a directory for an config_item. * @item: config_itemwe're creating directory for. * @dentry: config_item's dentry. * * Note: user-created entries won't be allowed under this new directory * until it is validated by configfs_dir_set_ready() */
static int configfs_create_dir(struct config_item *item, struct dentry *dentry) { int error; umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO; struct dentry *p = dentry->d_parent; BUG_ON(!item); error = configfs_dirent_exists(p->d_fsdata, dentry->d_name.name); if (unlikely(error)) return error; error = configfs_make_dirent(p->d_fsdata, dentry, item, mode, CONFIGFS_DIR | CONFIGFS_USET_CREATING); if (unlikely(error)) return error; configfs_set_dir_dirent_depth(p->d_fsdata, dentry->d_fsdata); error = configfs_create(dentry, mode, init_dir); if (!error) { inc_nlink(d_inode(p)); item->ci_dentry = dentry; } else { struct configfs_dirent *sd = dentry->d_fsdata; if (sd) { spin_lock(&configfs_dirent_lock); list_del_init(&sd->s_sibling); spin_unlock(&configfs_dirent_lock); configfs_put(sd); } } return error; }

Contributors

PersonTokensPropCommitsCommitProp
joel beckerjoel becker11661.70%330.00%
al viroal viro4222.34%220.00%
louis rillinglouis rilling2412.77%330.00%
david howellsdavid howells31.60%110.00%
dave hansendave hansen31.60%110.00%
Total188100.00%10100.00%

/* * Allow userspace to create new entries under a new directory created with * configfs_create_dir(), and under all of its chidlren directories recursively. * @sd configfs_dirent of the new directory to validate * * Caller must hold configfs_dirent_lock. */
static void configfs_dir_set_ready(struct configfs_dirent *sd) { struct configfs_dirent *child_sd; sd->s_type &= ~CONFIGFS_USET_CREATING; list_for_each_entry(child_sd, &sd->s_children, s_sibling) if (child_sd->s_type & CONFIGFS_USET_CREATING) configfs_dir_set_ready(child_sd); }

Contributors

PersonTokensPropCommitsCommitProp
louis rillinglouis rilling44100.00%1100.00%
Total44100.00%1100.00%

/* * Check that a directory does not belong to a directory hierarchy being * attached and not validated yet. * @sd configfs_dirent of the directory to check * * @return non-zero iff the directory was validated * * Note: takes configfs_dirent_lock, so the result may change from false to true * in two consecutive calls, but never from true to false. */
int configfs_dirent_is_ready(struct configfs_dirent *sd) { int ret; spin_lock(&configfs_dirent_lock); ret = !(sd->s_type & CONFIGFS_USET_CREATING); spin_unlock(&configfs_dirent_lock); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
louis rillinglouis rilling39100.00%1100.00%
Total39100.00%1100.00%


int configfs_create_link(struct configfs_symlink *sl, struct dentry *parent, struct dentry *dentry) { int err = 0; umode_t mode = S_IFLNK | S_IRWXUGO; err = configfs_make_dirent(parent->d_fsdata, dentry, sl, mode, CONFIGFS_ITEM_LINK); if (!err) { err = configfs_create(dentry, mode, init_symlink); if (err) { struct configfs_dirent *sd = dentry->d_fsdata; if (sd) { spin_lock(&configfs_dirent_lock); list_del_init(&sd->s_sibling); spin_unlock(&configfs_dirent_lock); configfs_put(sd); } } } return err; }

Contributors

PersonTokensPropCommitsCommitProp
joel beckerjoel becker10489.66%266.67%
louis rillinglouis rilling1210.34%133.33%
Total116100.00%3100.00%


static void remove_dir(struct dentry * d) { struct dentry * parent = dget(d->d_parent); struct configfs_dirent * sd; sd = d->d_fsdata; spin_lock(&configfs_dirent_lock); list_del_init(&sd->s_sibling); spin_unlock(&configfs_dirent_lock); configfs_put(sd); if (d_really_is_positive(d)) simple_rmdir(d_inode(parent),d); pr_debug(" o %pd removing done (%d)\n", d, d_count(d)); dput(parent); }

Contributors

PersonTokensPropCommitsCommitProp
joel beckerjoel becker7176.34%120.00%
louis rillinglouis rilling1212.90%120.00%
david howellsdavid howells66.45%120.00%
linus torvaldslinus torvalds33.23%120.00%
al viroal viro11.08%120.00%
Total93100.00%5100.00%

/** * configfs_remove_dir - remove an config_item's directory. * @item: config_item we're removing. * * The only thing special about this is that we remove any files in * the directory before we remove the directory, and we've inlined * what used to be configfs_rmdir() below, instead of calling separately. * * Caller holds the mutex of the item's inode */
static void configfs_remove_dir(struct config_item * item) { struct dentry * dentry = dget(item->ci_dentry); if (!dentry) return; remove_dir(dentry); /** * Drop reference from dget() on entrance. */ dput(dentry); }

Contributors

PersonTokensPropCommitsCommitProp
joel beckerjoel becker40100.00%1100.00%
Total40100.00%1100.00%

/* attaches attribute's configfs_dirent to the dentry corresponding to the * attribute file */
static int configfs_attach_attr(struct configfs_dirent * sd, struct dentry * dentry) { struct configfs_attribute * attr = sd->s_element; int error; spin_lock(&configfs_dirent_lock); dentry->d_fsdata = configfs_get(sd); sd->s_dentry = dentry; spin_unlock(&configfs_dirent_lock); error = configfs_create(dentry, (attr->ca_mode & S_IALLUGO) | S_IFREG, (sd->s_type & CONFIGFS_ITEM_BIN_ATTR) ? configfs_init_bin_file : configfs_init_file); if (error) configfs_put(sd); return error; }

Contributors

PersonTokensPropCommitsCommitProp
joel beckerjoel becker7376.04%240.00%
junxiao bijunxiao bi1212.50%120.00%
pantelis antonioupantelis antoniou1010.42%120.00%
dave hansendave hansen11.04%120.00%
Total96100.00%5100.00%


static struct dentry * configfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) { struct configfs_dirent * parent_sd = dentry->d_parent->d_fsdata; struct configfs_dirent * sd; int found = 0; int err; /* * Fake invisibility if dir belongs to a group/default groups hierarchy * being attached * * This forbids userspace to read/write attributes of items which may * not complete their initialization, since the dentries of the * attributes won't be instantiated. */ err = -ENOENT; if (!configfs_dirent_is_ready(parent_sd)) goto out; list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { if (sd->s_type & CONFIGFS_NOT_PINNED) { const unsigned char * name = configfs_get_name(sd); if (strcmp(name, dentry->d_name.name)) continue; found = 1; err = configfs_attach_attr(sd, dentry); break; } } if (!found) { /* * If it doesn't exist and it isn't a NOT_PINNED item, * it must be negative. */ if (dentry->d_name.len > NAME_MAX) return ERR_PTR(-ENAMETOOLONG); d_add(dentry, NULL); return NULL; } out: return ERR_PTR(err); }

Contributors

PersonTokensPropCommitsCommitProp
joel beckerjoel becker12273.94%125.00%
nick pigginnick piggin2112.73%125.00%
louis rillinglouis rilling1911.52%125.00%
al viroal viro31.82%125.00%
Total165100.00%4100.00%

/* * Only subdirectories count here. Files (CONFIGFS_NOT_PINNED) are * attributes and are removed by rmdir(). We recurse, setting * CONFIGFS_USET_DROPPING on all children that are candidates for * default detach. * If there is an error, the caller will reset the flags via * configfs_detach_rollback(). */
static int configfs_detach_prep(struct dentry *dentry, struct dentry **wait) { struct configfs_dirent *parent_sd = dentry->d_fsdata; struct configfs_dirent *sd; int ret; /* Mark that we're trying to drop the group */ parent_sd->s_type |= CONFIGFS_USET_DROPPING; ret = -EBUSY; if (!list_empty(&parent_sd->s_links)) goto out; ret = 0; list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { if (!sd->s_element || (sd->s_type & CONFIGFS_NOT_PINNED)) continue; if (sd->s_type & CONFIGFS_USET_DEFAULT) { /* Abort if racing with mkdir() */ if (sd->s_type & CONFIGFS_USET_IN_MKDIR) { if (wait) *wait= dget(sd->s_dentry); return -EAGAIN; } /* * Yup, recursive. If there's a problem, blame * deep nesting of default_groups */ ret = configfs_detach_prep(sd->s_dentry, wait); if (!ret) continue; } else ret = -ENOTEMPTY; break; } out: return ret; }

Contributors

PersonTokensPropCommitsCommitProp
joel beckerjoel becker10867.92%228.57%
louis rillinglouis rilling4327.04%342.86%
al viroal viro63.77%114.29%
david howellsdavid howells21.26%114.29%
Total159100.00%7100.00%

/* * Walk the tree, resetting CONFIGFS_USET_DROPPING wherever it was * set. */
static void configfs_detach_rollback(struct dentry *dentry) { struct configfs_dirent *parent_sd = dentry->d_fsdata; struct configfs_dirent *sd; parent_sd->s_type &= ~CONFIGFS_USET_DROPPING; list_for_each_entry(sd, &parent_sd->s_children, s_sibling) if (sd->s_type & CONFIGFS_USET_DEFAULT) configfs_detach_rollback(sd->s_dentry); }

Contributors

PersonTokensPropCommitsCommitProp
joel beckerjoel becker4887.27%150.00%
louis rillinglouis rilling712.73%150.00%
Total55100.00%2100.00%


static void detach_attrs(struct config_item * item) { struct dentry * dentry = dget(item->ci_dentry); struct configfs_dirent * parent_sd; struct configfs_dirent * sd, * tmp; if (!dentry) return; pr_debug("configfs %s: dropping attrs for dir\n", dentry->d_name.name); parent_sd = dentry->d_fsdata; list_for_each_entry_safe(sd, tmp, &parent_sd->s_children, s_sibling) { if (!sd->s_element || !(sd->s_type & CONFIGFS_NOT_PINNED)) continue; spin_lock(&configfs_dirent_lock); list_del_init(&sd->s_sibling); spin_unlock(&configfs_dirent_lock); configfs_drop_dentry(sd, dentry); configfs_put(sd); } /** * Drop reference from dget() on entrance. */ dput(dentry); }

Contributors

PersonTokensPropCommitsCommitProp
joel beckerjoel becker11490.48%150.00%
louis rillinglouis rilling129.52%150.00%
Total126100.00%2100.00%


static int populate_attrs(struct config_item *item) { struct config_item_type *t = item->ci_type; struct configfs_attribute *attr; struct configfs_bin_attribute *bin_attr; int error = 0; int i; if (!t) return -EINVAL; if (t->ct_attrs) { for (i = 0; (attr = t->ct_attrs[i]) != NULL; i++) { if ((error = configfs_create_file(item, attr))) break; } } if (t->ct_bin_attrs) { for (i = 0; (bin_attr = t->ct_bin_attrs[i]) != NULL; i++) { error = configfs_create_bin_file(item, bin_attr); if (error) break; } } if (error) detach_attrs(item); return error; }

Contributors

PersonTokensPropCommitsCommitProp
joel beckerjoel becker10066.23%150.00%
pantelis antonioupantelis antoniou5133.77%150.00%
Total151100.00%2100.00%

static int configfs_attach_group(struct config_item *parent_item, struct config_item *item, struct dentry *dentry); static void configfs_detach_group(struct config_item *item);
static void detach_groups(struct config_group *group) { struct dentry * dentry = dget(group->cg_item.ci_dentry); struct dentry *child; struct configfs_dirent *parent_sd; struct configfs_dirent *sd, *tmp; if (!dentry) return; parent_sd = dentry->d_fsdata; list_for_each_entry_safe(sd, tmp, &parent_sd->s_children, s_sibling) { if (!sd->s_element || !(sd->s_type & CONFIGFS_USET_DEFAULT)) continue; child = sd->s_dentry; inode_lock(d_inode(child)); configfs_detach_group(sd->s_element); d_inode(child)->i_flags |= S_DEAD; dont_mount(child); inode_unlock(d_inode(child)); d_delete(child); dput(child); } /** * Drop reference from dget() on entrance. */ dput(dentry); }

Contributors

PersonTokensPropCommitsCommitProp
joel beckerjoel becker12386.01%120.00%
david howellsdavid howells96.29%120.00%
al viroal viro74.90%240.00%
louis rillinglouis rilling42.80%120.00%
Total143100.00%5100.00%

/* * This fakes mkdir(2) on a default_groups[] entry. It * creates a dentry, attachs it, and then does fixup * on the sd->s_type. * * We could, perhaps, tweak our parent's ->mkdir for a minute and * try using vfs_mkdir. Just a thought. */
static int create_default_group(struct config_group *parent_group, struct config_group *group) { int ret; struct configfs_dirent *sd; /* We trust the caller holds a reference to parent */ struct dentry *child, *parent = parent_group->cg_item.ci_dentry; if (!group->cg_item.ci_name) group->cg_item.ci_name = group->cg_item.ci_namebuf; ret = -ENOMEM; child = d_alloc_name(parent, group->cg_item.ci_name); if (child) { d_add(child, NULL); ret = configfs_attach_group(&parent_group->cg_item, &group->cg_item, child); if (!ret) { sd = child->d_fsdata; sd->s_type |= CONFIGFS_USET_DEFAULT; } else { BUG_ON(d_inode(child)); d_drop(child); dput(child); } } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
joel beckerjoel becker14294.04%250.00%
al viroal viro63.97%125.00%
david howellsdavid howells31.99%125.00%
Total151100.00%4100.00%


static int populate_groups(struct config_group *group) { struct config_group *new_group; int ret = 0; list_for_each_entry(new_group, &group->default_groups, group_entry) { ret = create_default_group(group, new_group); if (ret) { detach_groups(group); break; } } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
joel beckerjoel becker4378.18%133.33%
christoph hellwigchristoph hellwig814.55%133.33%
louis rillinglouis rilling47.27%133.33%
Total55100.00%3100.00%


void configfs_remove_default_groups(struct config_group *group) { struct config_group *g, *n; list_for_each_entry_safe(g, n, &group->default_groups, group_entry) { list_del(&g->group_entry); config_item_put(&g->cg_item); } }

Contributors

PersonTokensPropCommitsCommitProp
christoph hellwigchristoph hellwig46100.00%1100.00%
Total46100.00%1100.00%

EXPORT_SYMBOL(configfs_remove_default_groups); /* * All of link_obj/unlink_obj/link_group/unlink_group require that * subsys->su_mutex is held. */
static void unlink_obj(struct config_item *item) { struct config_group *group; group = item->ci_group; if (group) { list_del_init(&item->ci_entry); item->ci_group = NULL; item->ci_parent = NULL; /* Drop the reference for ci_entry */ config_item_put(item); /* Drop the reference for ci_parent */ config_group_put(group); } }

Contributors

PersonTokensPropCommitsCommitProp
joel beckerjoel becker60100.00%2100.00%
Total60100.00%2100.00%


static void link_obj(struct config_item *parent_item, struct config_item *item) { /* * Parent seems redundant with group, but it makes certain * traversals much nicer. */ item->ci_parent = parent_item; /* * We hold a reference on the parent for the child's ci_parent * link. */ item->ci_group = config_group_get(to_config_group(parent_item)); list_add_tail(&item->ci_entry, &item->ci_group->cg_children); /* * We hold a reference on the child for ci_entry on the parent's * cg_children */ config_item_get(item); }

Contributors

PersonTokensPropCommitsCommitProp
joel beckerjoel becker57100.00%2100.00%
Total57100.00%2100.00%


static void unlink_group(struct config_group *group) { struct config_group *new_group; list_for_each_entry(new_group, &group->default_groups, group_entry) unlink_group(new_group); group->cg_subsys = NULL; unlink_obj(&group->cg_item); }

Contributors

PersonTokensPropCommitsCommitProp
joel beckerjoel becker3581.40%150.00%
christoph hellwigchristoph hellwig818.60%150.00%
Total43100.00%2100.00%


static void link_group(struct config_group *parent_group, struct config_group *group) { struct config_group *new_group; struct configfs_subsystem *subsys = NULL; /* gcc is a turd */ link_obj(&parent_group->cg_item, &group->cg_item); if (parent_group->cg_subsys) subsys = parent_group->cg_subsys; else if (configfs_is_root(&parent_group->cg_item)) subsys = to_configfs_subsystem(group); else BUG(); group->cg_subsys = subsys; list_for_each_entry(new_group, &group->default_groups, group_entry) link_group(group, new_group); }

Contributors

PersonTokensPropCommitsCommitProp
joel beckerjoel becker8991.75%150.00%
christoph hellwigchristoph hellwig88.25%150.00%
Total97100.00%2100.00%

/* * The goal is that configfs_attach_item() (and * configfs_attach_group()) can be called from either the VFS or this * module. That is, they assume that the items have been created, * the dentry allocated, and the dcache is all ready to go. * * If they fail, they must clean up after themselves as if they * had never been called. The caller (VFS or local function) will * handle cleaning up the dcache bits. * * configfs_detach_group() and configfs_detach_item() behave similarly on * the way out. They assume that the proper semaphores are held, they * clean up the configfs items, and they expect their callers will * handle the dcache bits. */
static int configfs_attach_item(struct config_item *parent_item, struct config_item *item, struct dentry *dentry) { int ret; ret = configfs_create_dir(item, dentry); if (!ret) { ret = populate_attrs(item); if (ret) { /* * We are going to remove an inode and its dentry but * the VFS may already have hit and used them. Thus, * we must lock them as rmdir() would. */ inode_lock(d_inode(dentry)); configfs_remove_dir(item); d_inode(dentry)->i_flags |= S_DEAD; dont_mount(dentry); inode_unlock(d_inode(dentry)); d_delete(dentry); } } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
joel beckerjoel becker6668.04%116.67%
louis rillinglouis rilling1414.43%116.67%
david howellsdavid howells99.28%116.67%
al viroal viro77.22%233.33%
mark fashehmark fasheh11.03%116.67%
Total97100.00%6100.00%

/* Caller holds the mutex of the item's inode */
static void configfs_detach_item(struct config_item *item) { detach_attrs(item); configfs_remove_dir(item); }

Contributors

PersonTokensPropCommitsCommitProp
joel beckerjoel becker21100.00%1100.00%
Total21100.00%1100.00%


static int configfs_attach_group(struct config_item *parent_item, struct config_item *item, struct dentry *dentry) { int ret; struct