@@ -24,6 +24,11 @@
#define TRACEFS_DEFAULT_MODE 0700
+enum tracefs_dir_type {
+ TRACEFS_DIR_INSTANCES,
+ TRACEFS_DIR_NAMESPACES,
+};
+
static struct vfsmount *tracefs_mount;
static int tracefs_mount_count;
static bool tracefs_registered;
@@ -50,6 +55,8 @@ static const struct file_operations tracefs_file_operations = {
static struct tracefs_dir_ops {
int (*mkdir)(const char *name);
int (*rmdir)(const char *name);
+ int (*ns_mkdir)(const char *name);
+ int (*ns_rmdir)(const char *name);
} tracefs_ops __ro_after_init;
static char *get_dname(struct dentry *dentry)
@@ -67,9 +74,8 @@ static char *get_dname(struct dentry *dentry)
return name;
}
-static int tracefs_syscall_mkdir(struct user_namespace *mnt_userns,
- struct inode *inode, struct dentry *dentry,
- umode_t mode)
+static int tracefs_syscall_mkdir_core(int type, struct inode *inode,
+ struct dentry *dentry)
{
char *name;
int ret;
@@ -84,7 +90,22 @@ static int tracefs_syscall_mkdir(struct user_namespace *mnt_userns,
* mkdir routine to handle races.
*/
inode_unlock(inode);
- ret = tracefs_ops.mkdir(name);
+
+ switch (type) {
+ case TRACEFS_DIR_INSTANCES:
+ ret = tracefs_ops.mkdir(name);
+ break;
+
+ case TRACEFS_DIR_NAMESPACES:
+ ret = tracefs_ops.ns_mkdir(name);
+ break;
+
+ default:
+ pr_debug("tracefs: unknown mkdir type '%d'\n", type);
+ ret = -ENOENT;
+ break;
+ }
+
inode_lock(inode);
kfree(name);
@@ -92,7 +113,24 @@ static int tracefs_syscall_mkdir(struct user_namespace *mnt_userns,
return ret;
}
-static int tracefs_syscall_rmdir(struct inode *inode, struct dentry *dentry)
+static int tracefs_syscall_mkdir(struct user_namespace *mnt_userns,
+ struct inode *inode, struct dentry *dentry,
+ umode_t mode)
+{
+ return tracefs_syscall_mkdir_core(TRACEFS_DIR_INSTANCES,
+ inode, dentry);
+}
+
+static int tracefs_syscall_ns_mkdir(struct user_namespace *mnt_userns,
+ struct inode *inode, struct dentry *dentry,
+ umode_t mode)
+{
+ return tracefs_syscall_mkdir_core(TRACEFS_DIR_NAMESPACES,
+ inode, dentry);
+}
+
+static int tracefs_syscall_rmdir_core(int type, struct inode *inode,
+ struct dentry *dentry)
{
char *name;
int ret;
@@ -111,7 +149,20 @@ static int tracefs_syscall_rmdir(struct inode *inode, struct dentry *dentry)
inode_unlock(inode);
inode_unlock(d_inode(dentry));
- ret = tracefs_ops.rmdir(name);
+ switch (type) {
+ case TRACEFS_DIR_INSTANCES:
+ ret = tracefs_ops.rmdir(name);
+ break;
+
+ case TRACEFS_DIR_NAMESPACES:
+ ret = tracefs_ops.ns_rmdir(name);
+ break;
+
+ default:
+ pr_debug("tracefs: unknown rmdir type '%d'\n", type);
+ ret = -ENOENT;
+ break;
+ }
inode_lock_nested(inode, I_MUTEX_PARENT);
inode_lock(d_inode(dentry));
@@ -121,12 +172,30 @@ static int tracefs_syscall_rmdir(struct inode *inode, struct dentry *dentry)
return ret;
}
+static int tracefs_syscall_rmdir(struct inode *inode, struct dentry *dentry)
+{
+ return tracefs_syscall_rmdir_core(TRACEFS_DIR_INSTANCES,
+ inode, dentry);
+}
+
+static int tracefs_syscall_ns_rmdir(struct inode *inode, struct dentry *dentry)
+{
+ return tracefs_syscall_rmdir_core(TRACEFS_DIR_NAMESPACES,
+ inode, dentry);
+}
+
static const struct inode_operations tracefs_dir_inode_operations = {
.lookup = simple_lookup,
.mkdir = tracefs_syscall_mkdir,
.rmdir = tracefs_syscall_rmdir,
};
+static const struct inode_operations tracefs_dir_inode_ns_operations = {
+ .lookup = simple_lookup,
+ .mkdir = tracefs_syscall_ns_mkdir,
+ .rmdir = tracefs_syscall_ns_rmdir,
+};
+
static struct inode *tracefs_get_inode(struct super_block *sb)
{
struct inode *inode = new_inode(sb);
@@ -554,7 +623,7 @@ struct dentry *tracefs_create_dir(const char *name, struct dentry *parent)
* Only one instances directory is allowed.
*
* The instances directory is special as it allows for mkdir and rmdir to
- * to be done by userspace. When a mkdir or rmdir is performed, the inode
+ * be done by userspace. When a mkdir or rmdir is performed, the inode
* locks are released and the methods passed in (@mkdir and @rmdir) are
* called without locks and with the name of the directory being created
* within the instances directory.
@@ -582,6 +651,44 @@ __init struct dentry *tracefs_create_instance_dir(const char *name,
return dentry;
}
+/**
+ * tracefs_create_namespace_dir - create the tracing namespaces directory
+ * @name: The name of the namespaces directory to create
+ * @parent: The parent directory that the namespaces directory will exist
+ * @mkdir: The function to call when a mkdir is performed.
+ * @rmdir: The function to call when a rmdir is performed.
+ *
+ * Only one namespaces directory is allowed.
+ *
+ * The namespaces directory is special as it allows for mkdir and rmdir to
+ * be done by userspace. When a mkdir or rmdir is performed, the inode
+ * locks are released and the methods passed in (@mkdir and @rmdir) are
+ * called without locks and with the name of the directory being created
+ * within the namespaces directory.
+ *
+ * Returns the dentry of the namespaces directory.
+ */
+__init struct dentry *tracefs_create_namespace_dir(const char *name,
+ struct dentry *parent,
+ int (*mkdir)(const char *name),
+ int (*rmdir)(const char *name))
+{
+ struct dentry *dentry;
+
+ /* Only allow one instance of the namespaces directory. */
+ if (WARN_ON(tracefs_ops.ns_mkdir || tracefs_ops.ns_rmdir))
+ return NULL;
+
+ dentry = __create_dir(name, parent, &tracefs_dir_inode_ns_operations);
+ if (!dentry)
+ return NULL;
+
+ tracefs_ops.ns_mkdir = mkdir;
+ tracefs_ops.ns_rmdir = rmdir;
+
+ return dentry;
+}
+
static void remove_one(struct dentry *victim)
{
simple_release_fs(&tracefs_mount, &tracefs_mount_count);
@@ -33,6 +33,11 @@ struct dentry *tracefs_create_instance_dir(const char *name, struct dentry *pare
int (*mkdir)(const char *name),
int (*rmdir)(const char *name));
+struct dentry *tracefs_create_namespace_dir(const char *name,
+ struct dentry *parent,
+ int (*mkdir)(const char *name),
+ int (*rmdir)(const char *name));
+
bool tracefs_initialized(void);
#endif /* CONFIG_TRACING */
Some tracing systems require a group or namespace isolation, such as user_events. The namespace directory in tracefs is a singleton like the instances directory. It also acts like the instances directory in that user-mode processes can create a directory within the namespace if they have appropriate permissions. This change only covers adding the ability for a tracing system to create the namespace directory. A system for adding and managing namespaces will reside within another tracing API. Link: https://lore.kernel.org/all/20220312010140.1880-1-beaub@linux.microsoft.com/ Signed-off-by: Beau Belgrave <beaub@linux.microsoft.com> --- fs/tracefs/inode.c | 121 +++++++++++++++++++++++++++++++++++++--- include/linux/tracefs.h | 5 ++ 2 files changed, 119 insertions(+), 7 deletions(-)