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

Konstantin Khorenko khorenko at virtuozzo.com
Wed Sep 22 14:50:55 MSK 2021


The commit is pushed to "branch-rh9-5.14.vz9.1.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after ark-5.14
------>
commit bbec68b7a2e194136afd94e4d77296e30c2be312
Author: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
Date:   Wed Sep 22 14:50:54 2021 +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.
    
    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;


More information about the Devel mailing list