|
|
|
@@ -355,6 +355,10 @@ static int configfs_detach_prep(struct dentry *dentry)
|
|
|
|
|
/* Mark that we've taken i_mutex */
|
|
|
|
|
sd->s_type |= CONFIGFS_USET_DROPPING;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Yup, recursive. If there's a problem, blame
|
|
|
|
|
* deep nesting of default_groups
|
|
|
|
|
*/
|
|
|
|
|
ret = configfs_detach_prep(sd->s_dentry);
|
|
|
|
|
if (!ret)
|
|
|
|
|
continue;
|
|
|
|
@@ -760,6 +764,239 @@ static void client_drop_item(struct config_item *parent_item,
|
|
|
|
|
config_item_put(item);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
static void configfs_dump_one(struct configfs_dirent *sd, int level)
|
|
|
|
|
{
|
|
|
|
|
printk(KERN_INFO "%*s\"%s\":\n", level, " ", configfs_get_name(sd));
|
|
|
|
|
|
|
|
|
|
#define type_print(_type) if (sd->s_type & _type) printk(KERN_INFO "%*s %s\n", level, " ", #_type);
|
|
|
|
|
type_print(CONFIGFS_ROOT);
|
|
|
|
|
type_print(CONFIGFS_DIR);
|
|
|
|
|
type_print(CONFIGFS_ITEM_ATTR);
|
|
|
|
|
type_print(CONFIGFS_ITEM_LINK);
|
|
|
|
|
type_print(CONFIGFS_USET_DIR);
|
|
|
|
|
type_print(CONFIGFS_USET_DEFAULT);
|
|
|
|
|
type_print(CONFIGFS_USET_DROPPING);
|
|
|
|
|
#undef type_print
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int configfs_dump(struct configfs_dirent *sd, int level)
|
|
|
|
|
{
|
|
|
|
|
struct configfs_dirent *child_sd;
|
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
|
|
configfs_dump_one(sd, level);
|
|
|
|
|
|
|
|
|
|
if (!(sd->s_type & (CONFIGFS_DIR|CONFIGFS_ROOT)))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
list_for_each_entry(child_sd, &sd->s_children, s_sibling) {
|
|
|
|
|
ret = configfs_dump(child_sd, level + 2);
|
|
|
|
|
if (ret)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* configfs_depend_item() and configfs_undepend_item()
|
|
|
|
|
*
|
|
|
|
|
* WARNING: Do not call these from a configfs callback!
|
|
|
|
|
*
|
|
|
|
|
* This describes these functions and their helpers.
|
|
|
|
|
*
|
|
|
|
|
* Allow another kernel system to depend on a config_item. If this
|
|
|
|
|
* happens, the item cannot go away until the dependant can live without
|
|
|
|
|
* it. The idea is to give client modules as simple an interface as
|
|
|
|
|
* possible. When a system asks them to depend on an item, they just
|
|
|
|
|
* call configfs_depend_item(). If the item is live and the client
|
|
|
|
|
* driver is in good shape, we'll happily do the work for them.
|
|
|
|
|
*
|
|
|
|
|
* Why is the locking complex? Because configfs uses the VFS to handle
|
|
|
|
|
* all locking, but this function is called outside the normal
|
|
|
|
|
* VFS->configfs path. So it must take VFS locks to prevent the
|
|
|
|
|
* VFS->configfs stuff (configfs_mkdir(), configfs_rmdir(), etc). This is
|
|
|
|
|
* why you can't call these functions underneath configfs callbacks.
|
|
|
|
|
*
|
|
|
|
|
* Note, btw, that this can be called at *any* time, even when a configfs
|
|
|
|
|
* subsystem isn't registered, or when configfs is loading or unloading.
|
|
|
|
|
* Just like configfs_register_subsystem(). So we take the same
|
|
|
|
|
* precautions. We pin the filesystem. We lock each i_mutex _in_order_
|
|
|
|
|
* on our way down the tree. If we can find the target item in the
|
|
|
|
|
* configfs tree, it must be part of the subsystem tree as well, so we
|
|
|
|
|
* do not need the subsystem semaphore. Holding the i_mutex chain locks
|
|
|
|
|
* out mkdir() and rmdir(), who might be racing us.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* configfs_depend_prep()
|
|
|
|
|
*
|
|
|
|
|
* Only subdirectories count here. Files (CONFIGFS_NOT_PINNED) are
|
|
|
|
|
* attributes. This is similar but not the same to configfs_detach_prep().
|
|
|
|
|
* Note that configfs_detach_prep() expects the parent to be locked when it
|
|
|
|
|
* is called, but we lock the parent *inside* configfs_depend_prep(). We
|
|
|
|
|
* do that so we can unlock it if we find nothing.
|
|
|
|
|
*
|
|
|
|
|
* Here we do a depth-first search of the dentry hierarchy looking for
|
|
|
|
|
* our object. We take i_mutex on each step of the way down. IT IS
|
|
|
|
|
* ESSENTIAL THAT i_mutex LOCKING IS ORDERED. If we come back up a branch,
|
|
|
|
|
* we'll drop the i_mutex.
|
|
|
|
|
*
|
|
|
|
|
* If the target is not found, -ENOENT is bubbled up and we have released
|
|
|
|
|
* all locks. If the target was found, the locks will be cleared by
|
|
|
|
|
* configfs_depend_rollback().
|
|
|
|
|
*
|
|
|
|
|
* This adds a requirement that all config_items be unique!
|
|
|
|
|
*
|
|
|
|
|
* This is recursive because the locking traversal is tricky. There isn't
|
|
|
|
|
* much on the stack, though, so folks that need this function - be careful
|
|
|
|
|
* about your stack! Patches will be accepted to make it iterative.
|
|
|
|
|
*/
|
|
|
|
|
static int configfs_depend_prep(struct dentry *origin,
|
|
|
|
|
struct config_item *target)
|
|
|
|
|
{
|
|
|
|
|
struct configfs_dirent *child_sd, *sd = origin->d_fsdata;
|
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
|
|
BUG_ON(!origin || !sd);
|
|
|
|
|
|
|
|
|
|
/* Lock this guy on the way down */
|
|
|
|
|
mutex_lock(&sd->s_dentry->d_inode->i_mutex);
|
|
|
|
|
if (sd->s_element == target) /* Boo-yah */
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
list_for_each_entry(child_sd, &sd->s_children, s_sibling) {
|
|
|
|
|
if (child_sd->s_type & CONFIGFS_DIR) {
|
|
|
|
|
ret = configfs_depend_prep(child_sd->s_dentry,
|
|
|
|
|
target);
|
|
|
|
|
if (!ret)
|
|
|
|
|
goto out; /* Child path boo-yah */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* We looped all our children and didn't find target */
|
|
|
|
|
mutex_unlock(&sd->s_dentry->d_inode->i_mutex);
|
|
|
|
|
ret = -ENOENT;
|
|
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This is ONLY called if configfs_depend_prep() did its job. So we can
|
|
|
|
|
* trust the entire path from item back up to origin.
|
|
|
|
|
*
|
|
|
|
|
* We walk backwards from item, unlocking each i_mutex. We finish by
|
|
|
|
|
* unlocking origin.
|
|
|
|
|
*/
|
|
|
|
|
static void configfs_depend_rollback(struct dentry *origin,
|
|
|
|
|
struct config_item *item)
|
|
|
|
|
{
|
|
|
|
|
struct dentry *dentry = item->ci_dentry;
|
|
|
|
|
|
|
|
|
|
while (dentry != origin) {
|
|
|
|
|
mutex_unlock(&dentry->d_inode->i_mutex);
|
|
|
|
|
dentry = dentry->d_parent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mutex_unlock(&origin->d_inode->i_mutex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int configfs_depend_item(struct configfs_subsystem *subsys,
|
|
|
|
|
struct config_item *target)
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
struct configfs_dirent *p, *root_sd, *subsys_sd = NULL;
|
|
|
|
|
struct config_item *s_item = &subsys->su_group.cg_item;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Pin the configfs filesystem. This means we can safely access
|
|
|
|
|
* the root of the configfs filesystem.
|
|
|
|
|
*/
|
|
|
|
|
ret = configfs_pin_fs();
|
|
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Next, lock the root directory. We're going to check that the
|
|
|
|
|
* subsystem is really registered, and so we need to lock out
|
|
|
|
|
* configfs_[un]register_subsystem().
|
|
|
|
|
*/
|
|
|
|
|
mutex_lock(&configfs_sb->s_root->d_inode->i_mutex);
|
|
|
|
|
|
|
|
|
|
root_sd = configfs_sb->s_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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!subsys_sd) {
|
|
|
|
|
ret = -ENOENT;
|
|
|
|
|
goto out_unlock_fs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Ok, now we can trust subsys/s_item */
|
|
|
|
|
|
|
|
|
|
/* Scan the tree, locking i_mutex recursively, return 0 if found */
|
|
|
|
|
ret = configfs_depend_prep(subsys_sd->s_dentry, target);
|
|
|
|
|
if (ret)
|
|
|
|
|
goto out_unlock_fs;
|
|
|
|
|
|
|
|
|
|
/* We hold all i_mutexes from the subsystem down to the target */
|
|
|
|
|
p = target->ci_dentry->d_fsdata;
|
|
|
|
|
p->s_dependent_count += 1;
|
|
|
|
|
|
|
|
|
|
configfs_depend_rollback(subsys_sd->s_dentry, target);
|
|
|
|
|
|
|
|
|
|
out_unlock_fs:
|
|
|
|
|
mutex_unlock(&configfs_sb->s_root->d_inode->i_mutex);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If we succeeded, the fs is pinned via other methods. If not,
|
|
|
|
|
* we're done with it anyway. So release_fs() is always right.
|
|
|
|
|
*/
|
|
|
|
|
configfs_release_fs();
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL(configfs_depend_item);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Release the dependent linkage. This is much simpler than
|
|
|
|
|
* 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)
|
|
|
|
|
{
|
|
|
|
|
struct configfs_dirent *sd;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Since we can trust everything is pinned, we just need i_mutex
|
|
|
|
|
* on the item.
|
|
|
|
|
*/
|
|
|
|
|
mutex_lock(&target->ci_dentry->d_inode->i_mutex);
|
|
|
|
|
|
|
|
|
|
sd = target->ci_dentry->d_fsdata;
|
|
|
|
|
BUG_ON(sd->s_dependent_count < 1);
|
|
|
|
|
|
|
|
|
|
sd->s_dependent_count -= 1;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* After this unlock, we cannot trust the item to stay alive!
|
|
|
|
|
* DO NOT REFERENCE item after this unlock.
|
|
|
|
|
*/
|
|
|
|
|
mutex_unlock(&target->ci_dentry->d_inode->i_mutex);
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL(configfs_undepend_item);
|
|
|
|
|
|
|
|
|
|
static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
|
|
|
|
|
{
|
|
|
|
@@ -906,6 +1143,13 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry)
|
|
|
|
|
if (sd->s_type & CONFIGFS_USET_DEFAULT)
|
|
|
|
|
return -EPERM;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Here's where we check for dependents. We're protected by
|
|
|
|
|
* i_mutex.
|
|
|
|
|
*/
|
|
|
|
|
if (sd->s_dependent_count)
|
|
|
|
|
return -EBUSY;
|
|
|
|
|
|
|
|
|
|
/* Get a working ref until we have the child */
|
|
|
|
|
parent_item = configfs_get_config_item(dentry->d_parent);
|
|
|
|
|
subsys = to_config_group(parent_item)->cg_subsys;
|
|
|
|
|