[Devel] [PATCH RH9 05/13] kernfs/sysfs: add ioctl to get fd network namespace tag

Pavel Tikhomirov ptikhomirov at virtuozzo.com
Tue Sep 21 19:04:23 MSK 2021


Sysfs mounts save current netns when mounting and show different set of
network devices in /sys/class/net based on it. But there is currently no
simple way to find out to that netns the sysfs mount is tagged to.

Lets add an ioctl so that we can get open file descriptor to this
namespace on nsfs. Next we would be able to readlink this fd to get
network namespace id.

Sysfs holds only "passive" reference to the net namespace, so the only
guaranty we have is that struct net is not freed yet. So lets add a
helper maybe_get_net_ns to get net only if it's fully alive.

https://jira.sw.ru/browse/PSBM-105161

Signed-off-by: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>

+++
kernfs/sysfs: include proc_fs.h for open_related_ns() visibility

mFixes: d53f348850ab ("kernfs/sysfs: add ioctl to get fd network namespace
tag")

Signed-off-by: Konstantin Khorenko <khorenko at virtuozzo.com>

(cherry-picked from vz8 commit ddb41e4466a775d9a956721581d311bc6a832516)
Signed-off-by: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
---
 fs/kernfs/dir.c             |  1 +
 fs/kernfs/file.c            | 23 +++++++++++++++++++++++
 fs/kernfs/kernfs-internal.h |  1 +
 include/linux/kernfs.h      |  5 +++++
 include/net/net_namespace.h |  1 +
 net/core/net_namespace.c    | 12 ++++++++++++
 6 files changed, 43 insertions(+)

diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index f576c5ba364b..283ac6197a76 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -1718,4 +1718,5 @@ const struct file_operations kernfs_dir_fops = {
 	.iterate_shared	= kernfs_fop_readdir,
 	.release	= kernfs_dir_fop_release,
 	.llseek		= generic_file_llseek,
+	.unlocked_ioctl = kernfs_ioctl,
 };
diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c
index c75719312147..749eb8b1e61f 100644
--- a/fs/kernfs/file.c
+++ b/fs/kernfs/file.c
@@ -15,6 +15,10 @@
 #include <linux/sched/mm.h>
 #include <linux/fsnotify.h>
 #include <linux/uio.h>
+#include <linux/proc_fs.h>
+#include <linux/proc_ns.h>
+#include <linux/magic.h>
+#include <net/net_namespace.h>
 
 #include "kernfs-internal.h"
 
@@ -940,6 +944,24 @@ void kernfs_notify(struct kernfs_node *kn)
 }
 EXPORT_SYMBOL_GPL(kernfs_notify);
 
+long kernfs_ioctl(struct file *file, unsigned int ioctl,
+		  unsigned long arg)
+{
+	struct dentry *dentry = file->f_path.dentry;
+	const void *ns = kernfs_info(dentry->d_sb)->ns;
+	struct net *net;
+
+	switch (ioctl) {
+	case KERNFS_GET_NS:
+		if (dentry->d_sb->s_magic != SYSFS_MAGIC || !ns)
+			return -ENOTTY;
+		net = (struct net *)ns;
+		return open_related_ns(&net->ns, maybe_get_net_ns);
+	default:
+		return -ENOTTY;
+	}
+}
+
 const struct file_operations kernfs_file_fops = {
 	.read_iter	= kernfs_fop_read_iter,
 	.write_iter	= kernfs_fop_write_iter,
@@ -951,6 +973,7 @@ const struct file_operations kernfs_file_fops = {
 	.fsync		= noop_fsync,
 	.splice_read	= generic_file_splice_read,
 	.splice_write	= iter_file_splice_write,
+	.unlocked_ioctl = kernfs_ioctl,
 };
 
 /**
diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h
index b457b7a19015..61f268eea730 100644
--- a/fs/kernfs/kernfs-internal.h
+++ b/fs/kernfs/kernfs-internal.h
@@ -125,6 +125,7 @@ struct kernfs_node *kernfs_new_node(struct kernfs_node *parent,
 extern const struct file_operations kernfs_file_fops;
 
 void kernfs_drain_open_files(struct kernfs_node *kn);
+long kernfs_ioctl(struct file *file, unsigned int ioctl, unsigned long arg);
 
 /*
  * symlink.c
diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h
index 147d1ef4cd21..78148e99a220 100644
--- a/include/linux/kernfs.h
+++ b/include/linux/kernfs.h
@@ -16,6 +16,7 @@
 #include <linux/atomic.h>
 #include <linux/uidgid.h>
 #include <linux/wait.h>
+#include <linux/ioctl.h>
 
 struct file;
 struct dentry;
@@ -606,4 +607,8 @@ static inline int kernfs_rename(struct kernfs_node *kn,
 	return kernfs_rename_ns(kn, new_parent, new_name, NULL);
 }
 
+#define KERNIO 0xb8
+
+#define KERNFS_GET_NS _IO(KERNIO, 0x1)
+
 #endif	/* __LINUX_KERNFS_H */
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index 232ef169c691..0f087b234364 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -194,6 +194,7 @@ void net_ns_get_ownership(const struct net *net, kuid_t *uid, kgid_t *gid);
 void net_ns_barrier(void);
 
 struct ns_common *get_net_ns(struct ns_common *ns);
+struct ns_common *maybe_get_net_ns(struct ns_common *ns);
 struct net *get_net_ns_by_fd(int fd);
 #else /* CONFIG_NET_NS */
 #include <linux/sched.h>
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 0212ee494b88..e40ad5d30b15 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -667,6 +667,18 @@ struct ns_common *get_net_ns(struct ns_common *ns)
 }
 EXPORT_SYMBOL_GPL(get_net_ns);
 
+struct ns_common *maybe_get_net_ns(struct ns_common *ns)
+{
+	struct net *net;
+
+	net = maybe_get_net(container_of(ns, struct net, ns));
+	if (!net)
+		return ERR_PTR(-ENXIO);
+
+	return &net->ns;
+}
+EXPORT_SYMBOL_GPL(maybe_get_net_ns);
+
 struct net *get_net_ns_by_fd(int fd)
 {
 	struct file *file;
-- 
2.31.1



More information about the Devel mailing list