[Devel] [PATCH RHEL7 COMMIT] kernfs/sysfs: add ioctl to get fd network namespace tag

Vasily Averin vvs at virtuozzo.com
Tue Jul 21 07:44:34 MSK 2020


The commit is pushed to "branch-rh7-3.10.0-1127.10.1.vz7.162.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-1127.10.1.vz7.162.10
------>
commit 1e0149eb5819491726c4370a60447ce2715364a6
Author: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
Date:   Tue Jul 21 07:44:34 2020 +0300

    kernfs/sysfs: add ioctl to get fd network namespace tag
    
    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.
    
    v2: fix bad net namespace referencing
    https://jira.sw.ru/browse/PSBM-105161
    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/linux/socket.h      |  1 +
 net/socket.c                | 12 ++++++++++++
 6 files changed, 43 insertions(+)

diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index 522947230f65e..01d2e53acef2e 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -1469,4 +1469,5 @@ const struct file_operations kernfs_dir_fops = {
 	.iterate	= kernfs_fop_readdir,
 	.release	= kernfs_dir_fop_release,
 	.llseek		= kernfs_dir_fop_llseek,
+	.unlocked_ioctl = kernfs_ioctl,
 };
diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c
index 3886845a26789..963a5d05d4f3f 100644
--- a/fs/kernfs/file.c
+++ b/fs/kernfs/file.c
@@ -15,6 +15,10 @@
 #include <linux/pagemap.h>
 #include <linux/sched.h>
 #include <linux/fsnotify.h>
+#include <linux/proc_ns.h>
+#include <linux/magic.h>
+#include <linux/socket.h>
+#include <net/net_namespace.h>
 
 #include "kernfs-internal.h"
 
@@ -891,6 +895,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		= kernfs_fop_read,
 	.write		= kernfs_fop_write,
@@ -899,6 +921,7 @@ const struct file_operations kernfs_file_fops = {
 	.open		= kernfs_fop_open,
 	.release	= kernfs_fop_release,
 	.poll		= kernfs_fop_poll,
+	.unlocked_ioctl = kernfs_ioctl,
 };
 
 /**
diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h
index 0dab7ce93f22a..fa102d625a494 100644
--- a/fs/kernfs/kernfs-internal.h
+++ b/fs/kernfs/kernfs-internal.h
@@ -119,6 +119,7 @@ struct kernfs_node *kernfs_new_node(struct kernfs_node *parent,
 extern const struct file_operations kernfs_file_fops;
 
 void kernfs_unmap_bin_file(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 485360932341f..d3fe1f6dbd4fb 100644
--- a/include/linux/kernfs.h
+++ b/include/linux/kernfs.h
@@ -16,6 +16,7 @@
 #include <linux/rbtree.h>
 #include <linux/atomic.h>
 #include <linux/wait.h>
+#include <linux/ioctl.h>
 
 struct file;
 struct dentry;
@@ -479,4 +480,8 @@ kernfs_mount(struct file_system_type *fs_type, int flags,
 				magic, new_sb_created, NULL);
 }
 
+#define KERNIO 0xb8
+
+#define KERNFS_GET_NS _IO(KERNIO, 0x1)
+
 #endif	/* __LINUX_KERNFS_H */
diff --git a/include/linux/socket.h b/include/linux/socket.h
index 591cec9a9bd87..790bb8e356b8f 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -356,4 +356,5 @@ extern int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg,
 			  unsigned int vlen, unsigned int flags);
 
 extern struct ns_common *get_net_ns(struct ns_common *ns);
+extern struct ns_common *maybe_get_net_ns(struct ns_common *ns);
 #endif /* _LINUX_SOCKET_H */
diff --git a/net/socket.c b/net/socket.c
index 3cd3cbd2be1bc..a60a04faa6a72 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -1097,6 +1097,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);
+
 static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg)
 {
 	struct socket *sock;


More information about the Devel mailing list