[RFC PATCH 2/4] namespacefs: Add methods to create/remove PID namespace directories
From: Yordan Karadzhov (VMware)
Date: Thu Nov 18 2021 - 13:13:18 EST
Each existing namespace on the system will be represented by a
corresponding directory in namespacesfs. When a namespace is created
a new directory will be added. When a namespace is destroyed, its
corresponding directory will be removed. When fully functional,
'namespacesfs' will provide a direct (1 to 1) mapping between the
hierarchy of all namespaces that are currently active on the system
and the hierarchy of directories in 'namespacesfs'.
As a first step towards this, here we add methods for creating and
removing PID namespace directories. For the moment the PID namespace
directory contains only one file called 'tasks'. This is a read only
pseudo file that provides a list of PIDs of all tasks enclosed inside
the namespace.
We modify 'struct ns_common' so that each namespaces will be able to
own a pointer to the 'dentry' of its corresponding directory in
'namespacesfs'. This pointer will be used to couple the creation and
destruction of a namespace with the creation and removal of its
corresponding directory.
In the patch we also add generic helper methods for printing the content
of an 'idr' ('id to pointer' translation service) into synthetic files
from sequences of records (seq_file). These new definitions are used by
'namespacefs' when printing the PIDs of the tasks in each PID namespace.
Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@xxxxxxxxx>
---
fs/namespacefs/inode.c | 119 ++++++++++++++++++++++++++++++++++++
include/linux/idr-seq.h | 0
include/linux/namespacefs.h | 13 ++++
include/linux/ns_common.h | 4 ++
4 files changed, 136 insertions(+)
delete mode 100644 include/linux/idr-seq.h
diff --git a/fs/namespacefs/inode.c b/fs/namespacefs/inode.c
index 0f6293b0877d..012c1c43b44d 100644
--- a/fs/namespacefs/inode.c
+++ b/fs/namespacefs/inode.c
@@ -10,6 +10,8 @@
#include <linux/namei.h>
#include <linux/fsnotify.h>
#include <linux/magic.h>
+#include <linux/idr.h>
+#include <linux/seq_file.h>
static struct vfsmount *namespacefs_mount;
static int namespacefs_mount_count;
@@ -188,6 +190,123 @@ void namespacefs_remove_dir(struct dentry *dentry)
release_namespacefs();
}
+struct idr_seq_context {
+ struct idr *idr;
+ int index;
+};
+
+static void *idr_seq_get_next(struct idr_seq_context *idr_ctx, loff_t *pos)
+{
+ void *next = idr_get_next(idr_ctx->idr, &idr_ctx->index);
+
+ *pos = ++idr_ctx->index;
+ return next;
+}
+
+static void *idr_seq_start(struct seq_file *m, loff_t *pos)
+{
+ struct idr_seq_context *idr_ctx = m->private;
+
+ idr_lock(idr_ctx->idr);
+ idr_ctx->index = *pos;
+ return idr_seq_get_next(idr_ctx, pos);
+}
+
+static void *idr_seq_next(struct seq_file *m, void *v, loff_t *pos)
+{
+ return idr_seq_get_next(m->private, pos);
+}
+
+static void idr_seq_stop(struct seq_file *m, void *p)
+{
+ struct idr_seq_context *idr_ctx = m->private;
+
+ idr_unlock(idr_ctx->idr);
+}
+
+static int idr_seq_open(struct file *file, struct idr *idr,
+ const struct seq_operations *ops)
+{
+ struct idr_seq_context *idr_ctx;
+
+ idr_ctx = __seq_open_private(file, ops, sizeof(*idr_ctx));
+ if (!idr_ctx)
+ return -ENOMEM;
+
+ idr_ctx->idr = idr;
+
+ return 0;
+}
+
+static inline int pid_seq_show(struct seq_file *m, void *v)
+{
+ struct pid *pid = v;
+
+ seq_printf(m, "%d\n", pid_nr(pid));
+ return 0;
+}
+
+static const struct seq_operations pid_seq_ops = {
+ .start = idr_seq_start,
+ .next = idr_seq_next,
+ .stop = idr_seq_stop,
+ .show = pid_seq_show,
+};
+
+static int pid_seq_open(struct inode *inode, struct file *file)
+{
+ struct idr *idr = inode->i_private;
+
+ return idr_seq_open(file, idr, &pid_seq_ops);
+}
+
+static const struct file_operations tasks_fops = {
+ .open = pid_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release_private,
+};
+
+static int create_inode_dir(struct ns_common *ns, struct dentry *parent_dentry,
+ const struct user_namespace *user_ns)
+{
+ char *dir = kasprintf(GFP_KERNEL, "%u", ns->inum);
+
+ if (!dir)
+ return -ENOMEM;
+
+ ns->dentry = namespacefs_create_dir(dir, parent_dentry, user_ns);
+ kfree(dir);
+ if (IS_ERR(ns->dentry))
+ return PTR_ERR(ns->dentry);
+
+ return 0;
+}
+
+int namespacefs_create_pid_ns_dir(struct pid_namespace *ns)
+{
+ struct dentry *dentry;
+ int err;
+
+ err = create_inode_dir(&ns->ns, ns->parent->ns.dentry, ns->user_ns);
+ if (err)
+ return err;
+
+ dentry = namespacefs_create_file("tasks", ns->ns.dentry, ns->user_ns,
+ &tasks_fops, &ns->idr);
+ if (IS_ERR(dentry)) {
+ dput(ns->ns.dentry);
+ return PTR_ERR(dentry);
+ }
+
+ return 0;
+}
+
+void namespacefs_remove_pid_ns_dir(struct pid_namespace *ns)
+{
+ namespacefs_remove_dir(ns->ns.dentry);
+}
+
#define _NS_MOUNT_DIR "namespaces"
static int __init namespacefs_init(void)
diff --git a/include/linux/idr-seq.h b/include/linux/idr-seq.h
deleted file mode 100644
index e69de29bb2d1..000000000000
diff --git a/include/linux/namespacefs.h b/include/linux/namespacefs.h
index 44a760080df7..f41499a7635a 100644
--- a/include/linux/namespacefs.h
+++ b/include/linux/namespacefs.h
@@ -19,6 +19,8 @@ struct dentry *
namespacefs_create_dir(const char *name, struct dentry *parent,
const struct user_namespace *user_ns);
void namespacefs_remove_dir(struct dentry *dentry);
+int namespacefs_create_pid_ns_dir(struct pid_namespace *ns);
+void namespacefs_remove_pid_ns_dir(struct pid_namespace *ns);
#else
@@ -42,6 +44,17 @@ static inline void namespacefs_remove_dir(struct dentry *dentry)
{
}
+static inline int
+namespacefs_create_pid_ns_dir(struct pid_namespace *ns)
+{
+ return 0;
+}
+
+static inline void
+namespacefs_remove_pid_ns_dir(struct pid_namespace *ns)
+{
+}
+
#endif /* CONFIG_NAMESPACE_FS */
#endif
diff --git a/include/linux/ns_common.h b/include/linux/ns_common.h
index 0f1d024bd958..1dec75c51b2c 100644
--- a/include/linux/ns_common.h
+++ b/include/linux/ns_common.h
@@ -11,6 +11,10 @@ struct ns_common {
const struct proc_ns_operations *ops;
unsigned int inum;
refcount_t count;
+
+#ifdef CONFIG_NAMESPACE_FS
+ struct dentry *dentry;
+#endif /* CONFIG_NAMESPACE_FS */
};
#endif
--
2.33.1