debugfs: Implement debugfs_remove_recursive()
debugfs_remove_recursive() will remove a dentry and all its children. Drivers can use this to zap their whole debugfs tree so that they don't need to keep track of every single debugfs dentry they created. It may fail to remove the whole tree in certain cases: sh-3.2# rmmod atmel-mci < /sys/kernel/debug/mmc0/ios/clock mmc0: card b368 removed atmel_mci atmel_mci.0: Lost dma0chan1, falling back to PIO sh-3.2# ls /sys/kernel/debug/mmc0/ ios But I'm not sure if that case can be handled in any sane manner. Signed-off-by: Haavard Skinnemoen <haavard.skinnemoen@atmel.com> Cc: Pierre Ossman <drzeus-list@drzeus.cx> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Родитель
43166141f7
Коммит
9505e63756
|
@ -309,32 +309,10 @@ struct dentry *debugfs_create_symlink(const char *name, struct dentry *parent,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(debugfs_create_symlink);
|
EXPORT_SYMBOL_GPL(debugfs_create_symlink);
|
||||||
|
|
||||||
/**
|
static void __debugfs_remove(struct dentry *dentry, struct dentry *parent)
|
||||||
* debugfs_remove - removes a file or directory from the debugfs filesystem
|
|
||||||
* @dentry: a pointer to a the dentry of the file or directory to be
|
|
||||||
* removed.
|
|
||||||
*
|
|
||||||
* This function removes a file or directory in debugfs that was previously
|
|
||||||
* created with a call to another debugfs function (like
|
|
||||||
* debugfs_create_file() or variants thereof.)
|
|
||||||
*
|
|
||||||
* This function is required to be called in order for the file to be
|
|
||||||
* removed, no automatic cleanup of files will happen when a module is
|
|
||||||
* removed, you are responsible here.
|
|
||||||
*/
|
|
||||||
void debugfs_remove(struct dentry *dentry)
|
|
||||||
{
|
{
|
||||||
struct dentry *parent;
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (!dentry)
|
|
||||||
return;
|
|
||||||
|
|
||||||
parent = dentry->d_parent;
|
|
||||||
if (!parent || !parent->d_inode)
|
|
||||||
return;
|
|
||||||
|
|
||||||
mutex_lock(&parent->d_inode->i_mutex);
|
|
||||||
if (debugfs_positive(dentry)) {
|
if (debugfs_positive(dentry)) {
|
||||||
if (dentry->d_inode) {
|
if (dentry->d_inode) {
|
||||||
dget(dentry);
|
dget(dentry);
|
||||||
|
@ -354,11 +332,111 @@ void debugfs_remove(struct dentry *dentry)
|
||||||
dput(dentry);
|
dput(dentry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* debugfs_remove - removes a file or directory from the debugfs filesystem
|
||||||
|
* @dentry: a pointer to a the dentry of the file or directory to be
|
||||||
|
* removed.
|
||||||
|
*
|
||||||
|
* This function removes a file or directory in debugfs that was previously
|
||||||
|
* created with a call to another debugfs function (like
|
||||||
|
* debugfs_create_file() or variants thereof.)
|
||||||
|
*
|
||||||
|
* This function is required to be called in order for the file to be
|
||||||
|
* removed, no automatic cleanup of files will happen when a module is
|
||||||
|
* removed, you are responsible here.
|
||||||
|
*/
|
||||||
|
void debugfs_remove(struct dentry *dentry)
|
||||||
|
{
|
||||||
|
struct dentry *parent;
|
||||||
|
|
||||||
|
if (!dentry)
|
||||||
|
return;
|
||||||
|
|
||||||
|
parent = dentry->d_parent;
|
||||||
|
if (!parent || !parent->d_inode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mutex_lock(&parent->d_inode->i_mutex);
|
||||||
|
__debugfs_remove(dentry, parent);
|
||||||
mutex_unlock(&parent->d_inode->i_mutex);
|
mutex_unlock(&parent->d_inode->i_mutex);
|
||||||
simple_release_fs(&debugfs_mount, &debugfs_mount_count);
|
simple_release_fs(&debugfs_mount, &debugfs_mount_count);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(debugfs_remove);
|
EXPORT_SYMBOL_GPL(debugfs_remove);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* debugfs_remove_recursive - recursively removes a directory
|
||||||
|
* @dentry: a pointer to a the dentry of the directory to be removed.
|
||||||
|
*
|
||||||
|
* This function recursively removes a directory tree in debugfs that
|
||||||
|
* was previously created with a call to another debugfs function
|
||||||
|
* (like debugfs_create_file() or variants thereof.)
|
||||||
|
*
|
||||||
|
* This function is required to be called in order for the file to be
|
||||||
|
* removed, no automatic cleanup of files will happen when a module is
|
||||||
|
* removed, you are responsible here.
|
||||||
|
*/
|
||||||
|
void debugfs_remove_recursive(struct dentry *dentry)
|
||||||
|
{
|
||||||
|
struct dentry *child;
|
||||||
|
struct dentry *parent;
|
||||||
|
|
||||||
|
if (!dentry)
|
||||||
|
return;
|
||||||
|
|
||||||
|
parent = dentry->d_parent;
|
||||||
|
if (!parent || !parent->d_inode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
parent = dentry;
|
||||||
|
mutex_lock(&parent->d_inode->i_mutex);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
/*
|
||||||
|
* When all dentries under "parent" has been removed,
|
||||||
|
* walk up the tree until we reach our starting point.
|
||||||
|
*/
|
||||||
|
if (list_empty(&parent->d_subdirs)) {
|
||||||
|
mutex_unlock(&parent->d_inode->i_mutex);
|
||||||
|
if (parent == dentry)
|
||||||
|
break;
|
||||||
|
parent = parent->d_parent;
|
||||||
|
mutex_lock(&parent->d_inode->i_mutex);
|
||||||
|
}
|
||||||
|
child = list_entry(parent->d_subdirs.next, struct dentry,
|
||||||
|
d_u.d_child);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If "child" isn't empty, walk down the tree and
|
||||||
|
* remove all its descendants first.
|
||||||
|
*/
|
||||||
|
if (!list_empty(&child->d_subdirs)) {
|
||||||
|
mutex_unlock(&parent->d_inode->i_mutex);
|
||||||
|
parent = child;
|
||||||
|
mutex_lock(&parent->d_inode->i_mutex);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
__debugfs_remove(child, parent);
|
||||||
|
if (parent->d_subdirs.next == &child->d_u.d_child) {
|
||||||
|
/*
|
||||||
|
* Avoid infinite loop if we fail to remove
|
||||||
|
* one dentry.
|
||||||
|
*/
|
||||||
|
mutex_unlock(&parent->d_inode->i_mutex);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
simple_release_fs(&debugfs_mount, &debugfs_mount_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
parent = dentry->d_parent;
|
||||||
|
mutex_lock(&parent->d_inode->i_mutex);
|
||||||
|
__debugfs_remove(dentry, parent);
|
||||||
|
mutex_unlock(&parent->d_inode->i_mutex);
|
||||||
|
simple_release_fs(&debugfs_mount, &debugfs_mount_count);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(debugfs_remove_recursive);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* debugfs_rename - rename a file/directory in the debugfs filesystem
|
* debugfs_rename - rename a file/directory in the debugfs filesystem
|
||||||
* @old_dir: a pointer to the parent dentry for the renamed object. This
|
* @old_dir: a pointer to the parent dentry for the renamed object. This
|
||||||
|
|
|
@ -44,6 +44,7 @@ struct dentry *debugfs_create_symlink(const char *name, struct dentry *parent,
|
||||||
const char *dest);
|
const char *dest);
|
||||||
|
|
||||||
void debugfs_remove(struct dentry *dentry);
|
void debugfs_remove(struct dentry *dentry);
|
||||||
|
void debugfs_remove_recursive(struct dentry *dentry);
|
||||||
|
|
||||||
struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry,
|
struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry,
|
||||||
struct dentry *new_dir, const char *new_name);
|
struct dentry *new_dir, const char *new_name);
|
||||||
|
@ -101,6 +102,9 @@ static inline struct dentry *debugfs_create_symlink(const char *name,
|
||||||
static inline void debugfs_remove(struct dentry *dentry)
|
static inline void debugfs_remove(struct dentry *dentry)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
static inline void debugfs_remove_recursive(struct dentry *dentry)
|
||||||
|
{ }
|
||||||
|
|
||||||
static inline struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry,
|
static inline struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry,
|
||||||
struct dentry *new_dir, char *new_name)
|
struct dentry *new_dir, char *new_name)
|
||||||
{
|
{
|
||||||
|
|
Загрузка…
Ссылка в новой задаче