Add notes about why debugfs_remove_recursive() cannot be backported
authorLuis R. Rodriguez <lrodriguez@atheros.com>
Wed, 13 Jan 2010 20:36:32 +0000 (12:36 -0800)
committerLuis R. Rodriguez <lrodriguez@atheros.com>
Wed, 13 Jan 2010 20:36:32 +0000 (12:36 -0800)
You should just disable debugging for older kernels if this is used.

Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
compat/compat-2.6.26.c
include/linux/compat-2.6.26.h

index 668d658..c20ddd5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007      Luis R. Rodriguez <mcgrof@winlab.rutgers.edu>
+ * Copyright 2007-2010 Luis R. Rodriguez <mcgrof@winlab.rutgers.edu>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -89,5 +89,116 @@ int dev_set_name(struct device *dev, const char *fmt, ...)
 }
 EXPORT_SYMBOL_GPL(dev_set_name);
 
+#if 0
+/*
+ * Below was an attempt to backport debugfs_remove_recursive() but as
+ * can be seen if enabled it cannot be backported since it relies on
+ * two static variables from fs/debugfs/inode.c . If you need backport
+ * this consider instead just disabling debugfs for drivers that use
+ * this for kernels < 2.6.26
+ */
+static inline int debugfs_positive(struct dentry *dentry)
+{
+       return dentry->d_inode && !d_unhashed(dentry);
+}
+
+static void __debugfs_remove(struct dentry *dentry, struct dentry *parent)
+{
+       int ret = 0;
+
+       if (debugfs_positive(dentry)) {
+               if (dentry->d_inode) {
+                       dget(dentry);
+                       switch (dentry->d_inode->i_mode & S_IFMT) {
+                       case S_IFDIR:
+                               ret = simple_rmdir(parent->d_inode, dentry);
+                               break;
+                       case S_IFLNK:
+                               kfree(dentry->d_inode->i_private);
+                               /* fall through */
+                       default:
+                               simple_unlink(parent->d_inode, dentry);
+                               break;
+                       }
+                       if (!ret)
+                               d_delete(dentry);
+                       dput(dentry);
+               }
+       }
+}
+
+/**
+ * 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);
+#endif
+
 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) */
 
index 0ea99b1..96459e0 100644 (file)
 #include <linux/kernel.h>
 #include <linux/jiffies.h>
 #include <net/sock.h>
+#include <linux/fs.h>
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24))
 #include <net/net_namespace.h>
 #endif
+#include <linux/fs.h>
+#include <linux/types.h>
+
+#if 0
+/* This cannot be backported :( */
+#if defined(CONFIG_DEBUG_FS)
+void debugfs_remove_recursive(struct dentry *dentry);
+#else
+static inline void debugfs_remove_recursive(struct dentry *dentry)
+{ }
+#endif
+#endif
 
 /* These jiffie helpers added as of 2.6.26 */