From: Andrew Lunn <[email protected]>

Unlike sysfs, debugfs is not netns aware. So batman has to take care
to avoid namespace clashes.

Each namespace is given a directory within debugfs/batman-adv/netns,
using the namespaces inum as the directory name.

Files for namespaces other than the global namespace are placed within
the namespace specific directory. Additionally, a symbolic link is
used to link the global namespaces inum back to debugfs/batman-adv/ so
tools do not need to differentiate between the global namespace and
other namespaces.

Signed-off-by: Andrew Lunn <[email protected]>
Signed-off-by: Sven Eckelmann <[email protected]>
---
 compat-patches/0002-ns.inum.patch |  25 ++++++++
 net/batman-adv/debugfs.c          | 130 +++++++++++++++++++++++++++++++++++++-
 2 files changed, 152 insertions(+), 3 deletions(-)
 create mode 100644 compat-patches/0002-ns.inum.patch

diff --git a/compat-patches/0002-ns.inum.patch 
b/compat-patches/0002-ns.inum.patch
new file mode 100644
index 0000000..9856f6e
--- /dev/null
+++ b/compat-patches/0002-ns.inum.patch
@@ -0,0 +1,25 @@
+From: Sven Eckelmann <[email protected]>
+Date: Sat, 12 Mar 2016 00:24:58 +0100
+Subject: [PATCH] ns.inum
+---
+ net/batman-adv/debugfs.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/net/batman-adv/debugfs.c b/net/batman-adv/debugfs.c
+index cc583e6..59616a6 100644
+--- a/net/batman-adv/debugfs.c
++++ b/net/batman-adv/debugfs.c
+@@ -78,7 +78,13 @@ static DEFINE_MUTEX(batadv_debugfs_ns_mutex);
+  */
+ static unsigned int batadv_debugfs_ns_id(const struct net *net)
+ {
++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
++      return 0; /* ???? */
++#elif LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0)
++      return net->proc_inum;
++#else
+       return net->ns.inum;
++#endif
+ }
+ 
+ static struct dentry *batadv_debugfs_ns_get(struct net *net)
diff --git a/net/batman-adv/debugfs.c b/net/batman-adv/debugfs.c
index 3dc5208..cc583e6 100644
--- a/net/batman-adv/debugfs.c
+++ b/net/batman-adv/debugfs.c
@@ -27,8 +27,12 @@
 #include <linux/fs.h>
 #include <linux/jiffies.h>
 #include <linux/kernel.h>
+#include <linux/kref.h>
+#include <linux/list.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/netdevice.h>
+#include <linux/ns_common.h>
 #include <linux/poll.h>
 #include <linux/printk.h>
 #include <linux/sched.h> /* for linux/wait.h */
@@ -42,6 +46,7 @@
 #include <linux/types.h>
 #include <linux/uaccess.h>
 #include <linux/wait.h>
+#include <net/net_namespace.h>
 #include <stdarg.h>
 
 #include "bridge_loop_avoidance.h"
@@ -53,6 +58,84 @@
 #include "translation-table.h"
 
 static struct dentry *batadv_debugfs;
+static struct dentry *batadv_ns_debugfs;
+
+struct batadv_debugfs_ns_entry {
+       struct net *net;
+       struct dentry *dir;
+       struct kref refcount;
+       struct list_head link;
+};
+
+static LIST_HEAD(batadv_debugfs_ns);
+static DEFINE_MUTEX(batadv_debugfs_ns_mutex);
+
+/**
+ * batadv_debugfs_ns_id - Get namespace specific id
+ * @net: namespace of the soft-interface
+ *
+ * Return: internal id of the namespace
+ */
+static unsigned int batadv_debugfs_ns_id(const struct net *net)
+{
+       return net->ns.inum;
+}
+
+static struct dentry *batadv_debugfs_ns_get(struct net *net)
+{
+       struct batadv_debugfs_ns_entry *ns_entry;
+       char name[32];
+
+       mutex_lock(&batadv_debugfs_ns_mutex);
+       list_for_each_entry(ns_entry, &batadv_debugfs_ns, link) {
+               if (ns_entry->net == net) {
+                       kref_get(&ns_entry->refcount);
+                       mutex_unlock(&batadv_debugfs_ns_mutex);
+                       return ns_entry->dir;
+               }
+       }
+
+       ns_entry = kzalloc(sizeof(*ns_entry), GFP_ATOMIC);
+       if (ns_entry) {
+               INIT_LIST_HEAD(&ns_entry->link);
+               ns_entry->net = net;
+               kref_init(&ns_entry->refcount);
+               sprintf(name, "%u", batadv_debugfs_ns_id(net));
+               ns_entry->dir = debugfs_create_dir(name, batadv_ns_debugfs);
+               if (!ns_entry->dir) {
+                       kfree(ns_entry);
+                       mutex_unlock(&batadv_debugfs_ns_mutex);
+                       return NULL;
+               }
+               list_add(&ns_entry->link, &batadv_debugfs_ns);
+       }
+       mutex_unlock(&batadv_debugfs_ns_mutex);
+       return ns_entry->dir;
+}
+
+static void batadv_ns_entry_release(struct kref *ref)
+{
+       struct batadv_debugfs_ns_entry *ns_entry;
+
+       ns_entry = container_of(ref, struct batadv_debugfs_ns_entry, refcount);
+       debugfs_remove_recursive(ns_entry->dir);
+       list_del(&ns_entry->link);
+       kfree(ns_entry);
+}
+
+static void batadv_debugfs_ns_put(struct net *net)
+{
+       struct batadv_debugfs_ns_entry *ns_entry;
+
+       mutex_lock(&batadv_debugfs_ns_mutex);
+       list_for_each_entry(ns_entry, &batadv_debugfs_ns, link) {
+               if (ns_entry->net == net) {
+                       kref_put(&ns_entry->refcount, batadv_ns_entry_release);
+                       break;
+               }
+       }
+       mutex_unlock(&batadv_debugfs_ns_mutex);
+}
 
 #ifdef CONFIG_BATMAN_ADV_DEBUG
 #define BATADV_LOG_BUFF_MASK (batadv_log_buff_len - 1)
@@ -451,6 +534,7 @@ void batadv_debugfs_init(void)
 {
        struct batadv_debuginfo **bat_debug;
        struct dentry *file;
+       char name[32];
 
        batadv_debugfs = debugfs_create_dir(BATADV_DEBUGFS_SUBDIR, NULL);
        if (batadv_debugfs == ERR_PTR(-ENODEV))
@@ -471,6 +555,15 @@ void batadv_debugfs_init(void)
                }
        }
 
+       batadv_ns_debugfs = debugfs_create_dir("netns", batadv_debugfs);
+       if (!batadv_ns_debugfs)
+               goto err;
+
+       /* Create a symlink for the default name space */
+       sprintf(name, "%u", batadv_debugfs_ns_id(&init_net));
+       if (!debugfs_create_symlink(name, batadv_ns_debugfs, ".."))
+               goto err;
+
        return;
 err:
        debugfs_remove_recursive(batadv_debugfs);
@@ -492,14 +585,24 @@ void batadv_debugfs_destroy(void)
  */
 int batadv_debugfs_add_hardif(struct batadv_hard_iface *hard_iface)
 {
+       struct net *net = dev_net(hard_iface->net_dev);
+       char *name = hard_iface->net_dev->name;
        struct batadv_debuginfo **bat_debug;
+       struct dentry *debugfs_ns_dir;
        struct dentry *file;
 
        if (!batadv_debugfs)
                goto out;
 
-       hard_iface->debug_dir = debugfs_create_dir(hard_iface->net_dev->name,
-                                                  batadv_debugfs);
+       debugfs_ns_dir = batadv_debugfs;
+
+       if (net != &init_net) {
+               debugfs_ns_dir = batadv_debugfs_ns_get(net);
+               if (!debugfs_ns_dir)
+                       goto out;
+       }
+
+       hard_iface->debug_dir = debugfs_create_dir(name, debugfs_ns_dir);
        if (!hard_iface->debug_dir)
                goto out;
 
@@ -517,6 +620,8 @@ int batadv_debugfs_add_hardif(struct batadv_hard_iface 
*hard_iface)
 rem_attr:
        debugfs_remove_recursive(hard_iface->debug_dir);
        hard_iface->debug_dir = NULL;
+       if (net != &init_net)
+               batadv_debugfs_ns_put(net);
 out:
        return -ENOMEM;
 }
@@ -528,22 +633,36 @@ out:
  */
 void batadv_debugfs_del_hardif(struct batadv_hard_iface *hard_iface)
 {
+       struct net *net = dev_net(hard_iface->net_dev);
+
        if (batadv_debugfs) {
                debugfs_remove_recursive(hard_iface->debug_dir);
                hard_iface->debug_dir = NULL;
        }
+       if (net != &init_net)
+               batadv_debugfs_ns_put(net);
 }
 
 int batadv_debugfs_add_meshif(struct net_device *dev)
 {
        struct batadv_priv *bat_priv = netdev_priv(dev);
        struct batadv_debuginfo **bat_debug;
+       struct net *net = dev_net(dev);
+       struct dentry *debugfs_ns_dir;
        struct dentry *file;
 
        if (!batadv_debugfs)
                goto out;
 
-       bat_priv->debug_dir = debugfs_create_dir(dev->name, batadv_debugfs);
+       debugfs_ns_dir = batadv_debugfs;
+
+       if (net != &init_net) {
+               debugfs_ns_dir = batadv_debugfs_ns_get(net);
+               if (!debugfs_ns_dir)
+                       goto out;
+       }
+
+       bat_priv->debug_dir = debugfs_create_dir(dev->name, debugfs_ns_dir);
        if (!bat_priv->debug_dir)
                goto out;
 
@@ -572,6 +691,8 @@ int batadv_debugfs_add_meshif(struct net_device *dev)
 rem_attr:
        debugfs_remove_recursive(bat_priv->debug_dir);
        bat_priv->debug_dir = NULL;
+       if (net != &init_net)
+               batadv_debugfs_ns_put(net);
 out:
        return -ENOMEM;
 }
@@ -579,6 +700,7 @@ out:
 void batadv_debugfs_del_meshif(struct net_device *dev)
 {
        struct batadv_priv *bat_priv = netdev_priv(dev);
+       struct net *net = dev_net(dev);
 
        batadv_debug_log_cleanup(bat_priv);
 
@@ -586,4 +708,6 @@ void batadv_debugfs_del_meshif(struct net_device *dev)
                debugfs_remove_recursive(bat_priv->debug_dir);
                bat_priv->debug_dir = NULL;
        }
+       if (net != &init_net)
+               batadv_debugfs_ns_put(net);
 }
-- 
2.7.0

Reply via email to