Release 4.10 fs/configfs/dir.c
/* -*- 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
| Person | Tokens | Prop | Commits | CommitProp |
joel becker | joel becker | 60 | 82.19% | 2 | 66.67% |
junxiao bi | junxiao bi | 13 | 17.81% | 1 | 33.33% |
| Total | 73 | 100.00% | 3 | 100.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
| Person | Tokens | Prop | Commits | CommitProp |
louis rilling | louis rilling | 18 | 100.00% | 1 | 100.00% |
| Total | 18 | 100.00% | 1 | 100.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
| Person | Tokens | Prop | Commits | CommitProp |
louis rilling | louis rilling | 37 | 100.00% | 1 | 100.00% |
| Total | 37 | 100.00% | 1 | 100.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
| Person | Tokens | Prop | Commits | CommitProp |
louis rilling | louis rilling | 29 | 100.00% | 1 | 100.00% |
| Total | 29 | 100.00% | 1 | 100.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
| Person | Tokens | Prop | Commits | CommitProp |
louis rilling | louis rilling | 19 | 100.00% | 1 | 100.00% |
| Total | 19 | 100.00% | 1 | 100.00% |
#else /* CONFIG_LOCKDEP */
static void configfs_init_dirent_depth(struct configfs_dirent *sd)
{
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
louis rilling | louis rilling | 10 | 100.00% | 1 | 100.00% |
| Total | 10 | 100.00% | 1 | 100.00% |
static void configfs_set_dir_dirent_depth(struct configfs_dirent *parent_sd,
struct configfs_dirent *sd)
{
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
louis rilling | louis rilling | 15 | 100.00% | 1 | 100.00% |
| Total | 15 | 100.00% | 1 | 100.00% |
static void
configfs_adjust_dir_dirent_depth_before_populate(struct configfs_dirent *sd)
{
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
louis rilling | louis rilling | 10 | 100.00% | 1 | 100.00% |
| Total | 10 | 100.00% | 1 | 100.00% |
static void
configfs_adjust_dir_dirent_depth_after_populate(struct configfs_dirent *sd)
{
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
louis rilling | louis rilling | 10 | 100.00% | 1 | 100.00% |
| Total | 10 | 100.00% | 1 | 100.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
| Person | Tokens | Prop | Commits | CommitProp |
joel becker | joel becker | 80 | 54.42% | 2 | 25.00% |
louis rilling | louis rilling | 66 | 44.90% | 5 | 62.50% |
robert p. j. day | robert p. j. day | 1 | 0.68% | 1 | 12.50% |
| Total | 147 | 100.00% | 8 | 100.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
| Person | Tokens | Prop | Commits | CommitProp |
joel becker | joel becker | 68 | 98.55% | 1 | 50.00% |
adrian bunk | adrian bunk | 1 | 1.45% | 1 | 50.00% |
| Total | 69 | 100.00% | 2 | 100.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
| Person | Tokens | Prop | Commits | CommitProp |
joel becker | joel becker | 73 | 89.02% | 1 | 33.33% |
louis rilling | louis rilling | 9 | 10.98% | 2 | 66.67% |
| Total | 82 | 100.00% | 3 | 100.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
| Person | Tokens | Prop | Commits | CommitProp |
joel becker | joel becker | 27 | 87.10% | 1 | 33.33% |
dave hansen | dave hansen | 3 | 9.68% | 1 | 33.33% |
al viro | al viro | 1 | 3.23% | 1 | 33.33% |
| Total | 31 | 100.00% | 3 | 100.00% |
static void configfs_init_file(struct inode * inode)
{
inode->i_size = PAGE_SIZE;
inode->i_fop = &configfs_file_operations;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
joel becker | joel becker | 22 | 91.67% | 1 | 33.33% |
al viro | al viro | 1 | 4.17% | 1 | 33.33% |
dave hansen | dave hansen | 1 | 4.17% | 1 | 33.33% |
| Total | 24 | 100.00% | 3 | 100.00% |
static void configfs_init_bin_file(struct inode *inode)
{
inode->i_size = 0;
inode->i_fop = &configfs_bin_file_operations;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
pantelis antoniou | pantelis antoniou | 24 | 100.00% | 1 | 100.00% |
| Total | 24 | 100.00% | 1 | 100.00% |
static void init_symlink(struct inode * inode)
{
inode->i_op = &configfs_symlink_inode_operations;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
joel becker | joel becker | 17 | 94.44% | 1 | 50.00% |
al viro | al viro | 1 | 5.56% | 1 | 50.00% |
| Total | 18 | 100.00% | 2 | 100.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
| Person | Tokens | Prop | Commits | CommitProp |
joel becker | joel becker | 116 | 61.70% | 3 | 30.00% |
al viro | al viro | 42 | 22.34% | 2 | 20.00% |
louis rilling | louis rilling | 24 | 12.77% | 3 | 30.00% |
david howells | david howells | 3 | 1.60% | 1 | 10.00% |
dave hansen | dave hansen | 3 | 1.60% | 1 | 10.00% |
| Total | 188 | 100.00% | 10 | 100.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
| Person | Tokens | Prop | Commits | CommitProp |
louis rilling | louis rilling | 44 | 100.00% | 1 | 100.00% |
| Total | 44 | 100.00% | 1 | 100.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
| Person | Tokens | Prop | Commits | CommitProp |
louis rilling | louis rilling | 39 | 100.00% | 1 | 100.00% |
| Total | 39 | 100.00% | 1 | 100.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
| Person | Tokens | Prop | Commits | CommitProp |
joel becker | joel becker | 104 | 89.66% | 2 | 66.67% |
louis rilling | louis rilling | 12 | 10.34% | 1 | 33.33% |
| Total | 116 | 100.00% | 3 | 100.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
| Person | Tokens | Prop | Commits | CommitProp |
joel becker | joel becker | 71 | 76.34% | 1 | 20.00% |
louis rilling | louis rilling | 12 | 12.90% | 1 | 20.00% |
david howells | david howells | 6 | 6.45% | 1 | 20.00% |
linus torvalds | linus torvalds | 3 | 3.23% | 1 | 20.00% |
al viro | al viro | 1 | 1.08% | 1 | 20.00% |
| Total | 93 | 100.00% | 5 | 100.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
| Person | Tokens | Prop | Commits | CommitProp |
joel becker | joel becker | 40 | 100.00% | 1 | 100.00% |
| Total | 40 | 100.00% | 1 | 100.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
| Person | Tokens | Prop | Commits | CommitProp |
joel becker | joel becker | 73 | 76.04% | 2 | 40.00% |
junxiao bi | junxiao bi | 12 | 12.50% | 1 | 20.00% |
pantelis antoniou | pantelis antoniou | 10 | 10.42% | 1 | 20.00% |
dave hansen | dave hansen | 1 | 1.04% | 1 | 20.00% |
| Total | 96 | 100.00% | 5 | 100.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
| Person | Tokens | Prop | Commits | CommitProp |
joel becker | joel becker | 122 | 73.94% | 1 | 25.00% |
nick piggin | nick piggin | 21 | 12.73% | 1 | 25.00% |
louis rilling | louis rilling | 19 | 11.52% | 1 | 25.00% |
al viro | al viro | 3 | 1.82% | 1 | 25.00% |
| Total | 165 | 100.00% | 4 | 100.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
| Person | Tokens | Prop | Commits | CommitProp |
joel becker | joel becker | 108 | 67.92% | 2 | 28.57% |
louis rilling | louis rilling | 43 | 27.04% | 3 | 42.86% |
al viro | al viro | 6 | 3.77% | 1 | 14.29% |
david howells | david howells | 2 | 1.26% | 1 | 14.29% |
| Total | 159 | 100.00% | 7 | 100.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
| Person | Tokens | Prop | Commits | CommitProp |
joel becker | joel becker | 48 | 87.27% | 1 | 50.00% |
louis rilling | louis rilling | 7 | 12.73% | 1 | 50.00% |
| Total | 55 | 100.00% | 2 | 100.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
| Person | Tokens | Prop | Commits | CommitProp |
joel becker | joel becker | 114 | 90.48% | 1 | 50.00% |
louis rilling | louis rilling | 12 | 9.52% | 1 | 50.00% |
| Total | 126 | 100.00% | 2 | 100.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
| Person | Tokens | Prop | Commits | CommitProp |
joel becker | joel becker | 100 | 66.23% | 1 | 50.00% |
pantelis antoniou | pantelis antoniou | 51 | 33.77% | 1 | 50.00% |
| Total | 151 | 100.00% | 2 | 100.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
| Person | Tokens | Prop | Commits | CommitProp |
joel becker | joel becker | 123 | 86.01% | 1 | 20.00% |
david howells | david howells | 9 | 6.29% | 1 | 20.00% |
al viro | al viro | 7 | 4.90% | 2 | 40.00% |
louis rilling | louis rilling | 4 | 2.80% | 1 | 20.00% |
| Total | 143 | 100.00% | 5 | 100.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
| Person | Tokens | Prop | Commits | CommitProp |
joel becker | joel becker | 142 | 94.04% | 2 | 50.00% |
al viro | al viro | 6 | 3.97% | 1 | 25.00% |
david howells | david howells | 3 | 1.99% | 1 | 25.00% |
| Total | 151 | 100.00% | 4 | 100.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
| Person | Tokens | Prop | Commits | CommitProp |
joel becker | joel becker | 43 | 78.18% | 1 | 33.33% |
christoph hellwig | christoph hellwig | 8 | 14.55% | 1 | 33.33% |
louis rilling | louis rilling | 4 | 7.27% | 1 | 33.33% |
| Total | 55 | 100.00% | 3 | 100.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
| Person | Tokens | Prop | Commits | CommitProp |
christoph hellwig | christoph hellwig | 46 | 100.00% | 1 | 100.00% |
| Total | 46 | 100.00% | 1 | 100.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
| Person | Tokens | Prop | Commits | CommitProp |
joel becker | joel becker | 60 | 100.00% | 2 | 100.00% |
| Total | 60 | 100.00% | 2 | 100.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
| Person | Tokens | Prop | Commits | CommitProp |
joel becker | joel becker | 57 | 100.00% | 2 | 100.00% |
| Total | 57 | 100.00% | 2 | 100.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
| Person | Tokens | Prop | Commits | CommitProp |
joel becker | joel becker | 35 | 81.40% | 1 | 50.00% |
christoph hellwig | christoph hellwig | 8 | 18.60% | 1 | 50.00% |
| Total | 43 | 100.00% | 2 | 100.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
| Person | Tokens | Prop | Commits | CommitProp |
joel becker | joel becker | 89 | 91.75% | 1 | 50.00% |
christoph hellwig | christoph hellwig | 8 | 8.25% | 1 | 50.00% |
| Total | 97 | 100.00% | 2 | 100.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
| Person | Tokens | Prop | Commits | CommitProp |
joel becker | joel becker | 66 | 68.04% | 1 | 16.67% |
louis rilling | louis rilling | 14 | 14.43% | 1 | 16.67% |
david howells | david howells | 9 | 9.28% | 1 | 16.67% |
al viro | al viro | 7 | 7.22% | 2 | 33.33% |
mark fasheh | mark fasheh | 1 | 1.03% | 1 | 16.67% |
| Total | 97 | 100.00% | 6 | 100.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
| Person | Tokens | Prop | Commits | CommitProp |
joel becker | joel becker | 21 | 100.00% | 1 | 100.00% |
| Total | 21 | 100.00% | 1 | 100.00% |
static int configfs_attach_group(struct config_item *parent_item,
struct config_item *item,
struct dentry *dentry)
{
int ret;
struct