|
@@ -533,8 +533,7 @@ EXPORT_SYMBOL_GPL(debugfs_remove);
|
|
|
*/
|
|
|
void debugfs_remove_recursive(struct dentry *dentry)
|
|
|
{
|
|
|
- struct dentry *child;
|
|
|
- struct dentry *parent;
|
|
|
+ struct dentry *child, *next, *parent;
|
|
|
|
|
|
if (IS_ERR_OR_NULL(dentry))
|
|
|
return;
|
|
@@ -544,61 +543,37 @@ void debugfs_remove_recursive(struct dentry *dentry)
|
|
|
return;
|
|
|
|
|
|
parent = dentry;
|
|
|
+ down:
|
|
|
mutex_lock(&parent->d_inode->i_mutex);
|
|
|
+ list_for_each_entry_safe(child, next, &parent->d_subdirs, d_u.d_child) {
|
|
|
+ if (!debugfs_positive(child))
|
|
|
+ continue;
|
|
|
|
|
|
- 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);
|
|
|
- next_sibling:
|
|
|
-
|
|
|
- /*
|
|
|
- * If "child" isn't empty, walk down the tree and
|
|
|
- * remove all its descendants first.
|
|
|
- */
|
|
|
+ /* perhaps simple_empty(child) makes more sense */
|
|
|
if (!list_empty(&child->d_subdirs)) {
|
|
|
mutex_unlock(&parent->d_inode->i_mutex);
|
|
|
parent = child;
|
|
|
- mutex_lock(&parent->d_inode->i_mutex);
|
|
|
- continue;
|
|
|
+ goto down;
|
|
|
}
|
|
|
- __debugfs_remove(child, parent);
|
|
|
- if (parent->d_subdirs.next == &child->d_u.d_child) {
|
|
|
- /*
|
|
|
- * Try the next sibling.
|
|
|
- */
|
|
|
- if (child->d_u.d_child.next != &parent->d_subdirs) {
|
|
|
- child = list_entry(child->d_u.d_child.next,
|
|
|
- struct dentry,
|
|
|
- d_u.d_child);
|
|
|
- goto next_sibling;
|
|
|
- }
|
|
|
-
|
|
|
- /*
|
|
|
- * 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);
|
|
|
+ up:
|
|
|
+ if (!__debugfs_remove(child, parent))
|
|
|
+ simple_release_fs(&debugfs_mount, &debugfs_mount_count);
|
|
|
}
|
|
|
|
|
|
- parent = dentry->d_parent;
|
|
|
+ mutex_unlock(&parent->d_inode->i_mutex);
|
|
|
+ child = parent;
|
|
|
+ parent = parent->d_parent;
|
|
|
mutex_lock(&parent->d_inode->i_mutex);
|
|
|
- __debugfs_remove(dentry, parent);
|
|
|
+
|
|
|
+ if (child != dentry) {
|
|
|
+ next = list_entry(child->d_u.d_child.next, struct dentry,
|
|
|
+ d_u.d_child);
|
|
|
+ goto up;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!__debugfs_remove(child, parent))
|
|
|
+ simple_release_fs(&debugfs_mount, &debugfs_mount_count);
|
|
|
mutex_unlock(&parent->d_inode->i_mutex);
|
|
|
- simple_release_fs(&debugfs_mount, &debugfs_mount_count);
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(debugfs_remove_recursive);
|
|
|
|