mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	eventfs: Implement eventfs dir creation functions
Add eventfs_file structure which will hold the properties of the eventfs files and directories. Add following functions to create the directories in eventfs: eventfs_create_events_dir() will create the top level "events" directory within the tracefs file system. eventfs_add_subsystem_dir() creates an eventfs_file descriptor with the given name of the subsystem. eventfs_add_dir() creates an eventfs_file descriptor with the given name of the directory and attached to a eventfs_file of a subsystem. Add tracefs_inode structure to hold the inodes, flags and pointers to private data used by eventfs. Link: https://lkml.kernel.org/r/1690568452-46553-5-git-send-email-akaher@vmware.com Signed-off-by: Ajay Kaher <akaher@vmware.com> Co-developed-by: Steven Rostedt (VMware) <rostedt@goodmis.org> Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org> Tested-by: Ching-lin Yu <chinglinyu@google.com> Reported-by: kernel test robot <lkp@intel.com> Closes: https://lore.kernel.org/oe-lkp/202305051619.9a469a9a-yujie.liu@intel.com Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
This commit is contained in:
		
							parent
							
								
									2c6b6b1029
								
							
						
					
					
						commit
						c1504e5102
					
				
					 4 changed files with 227 additions and 0 deletions
				
			
		| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
# SPDX-License-Identifier: GPL-2.0-only
 | 
					# SPDX-License-Identifier: GPL-2.0-only
 | 
				
			||||||
tracefs-objs	:= inode.o
 | 
					tracefs-objs	:= inode.o
 | 
				
			||||||
 | 
					tracefs-objs	+= event_inode.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
obj-$(CONFIG_TRACING)	+= tracefs.o
 | 
					obj-$(CONFIG_TRACING)	+= tracefs.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										211
									
								
								fs/tracefs/event_inode.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										211
									
								
								fs/tracefs/event_inode.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,211 @@
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: GPL-2.0-only
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  event_inode.c - part of tracefs, a pseudo file system for activating tracing
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2020-23 VMware Inc, author: Steven Rostedt (VMware) <rostedt@goodmis.org>
 | 
				
			||||||
 | 
					 *  Copyright (C) 2020-23 VMware Inc, author: Ajay Kaher <akaher@vmware.com>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  eventfs is used to dynamically create inodes and dentries based on the
 | 
				
			||||||
 | 
					 *  meta data provided by the tracing system.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  eventfs stores the meta-data of files/dirs and holds off on creating
 | 
				
			||||||
 | 
					 *  inodes/dentries of the files. When accessed, the eventfs will create the
 | 
				
			||||||
 | 
					 *  inodes/dentries in a just-in-time (JIT) manner. The eventfs will clean up
 | 
				
			||||||
 | 
					 *  and delete the inodes/dentries when they are no longer referenced.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#include <linux/fsnotify.h>
 | 
				
			||||||
 | 
					#include <linux/fs.h>
 | 
				
			||||||
 | 
					#include <linux/namei.h>
 | 
				
			||||||
 | 
					#include <linux/workqueue.h>
 | 
				
			||||||
 | 
					#include <linux/security.h>
 | 
				
			||||||
 | 
					#include <linux/tracefs.h>
 | 
				
			||||||
 | 
					#include <linux/kref.h>
 | 
				
			||||||
 | 
					#include <linux/delay.h>
 | 
				
			||||||
 | 
					#include "internal.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct eventfs_inode {
 | 
				
			||||||
 | 
						struct list_head	e_top_files;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * struct eventfs_file - hold the properties of the eventfs files and
 | 
				
			||||||
 | 
					 *                       directories.
 | 
				
			||||||
 | 
					 * @name:	the name of the file or directory to create
 | 
				
			||||||
 | 
					 * @list:	file or directory to be added to parent directory
 | 
				
			||||||
 | 
					 * @ei:		list of files and directories within directory
 | 
				
			||||||
 | 
					 * @fop:	file_operations for file or directory
 | 
				
			||||||
 | 
					 * @iop:	inode_operations for file or directory
 | 
				
			||||||
 | 
					 * @data:	something that the caller will want to get to later on
 | 
				
			||||||
 | 
					 * @mode:	the permission that the file or directory should have
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct eventfs_file {
 | 
				
			||||||
 | 
						const char			*name;
 | 
				
			||||||
 | 
						struct list_head		list;
 | 
				
			||||||
 | 
						struct eventfs_inode		*ei;
 | 
				
			||||||
 | 
						const struct file_operations	*fop;
 | 
				
			||||||
 | 
						const struct inode_operations	*iop;
 | 
				
			||||||
 | 
						void				*data;
 | 
				
			||||||
 | 
						umode_t				mode;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static DEFINE_MUTEX(eventfs_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct inode_operations eventfs_root_dir_inode_operations = {
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct file_operations eventfs_file_operations = {
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * eventfs_prepare_ef - helper function to prepare eventfs_file
 | 
				
			||||||
 | 
					 * @name: the name of the file/directory to create.
 | 
				
			||||||
 | 
					 * @mode: the permission that the file should have.
 | 
				
			||||||
 | 
					 * @fop: struct file_operations that should be used for this file/directory.
 | 
				
			||||||
 | 
					 * @iop: struct inode_operations that should be used for this file/directory.
 | 
				
			||||||
 | 
					 * @data: something that the caller will want to get to later on. The
 | 
				
			||||||
 | 
					 *        inode.i_private pointer will point to this value on the open() call.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This function allocates and fills the eventfs_file structure.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static struct eventfs_file *eventfs_prepare_ef(const char *name, umode_t mode,
 | 
				
			||||||
 | 
										const struct file_operations *fop,
 | 
				
			||||||
 | 
										const struct inode_operations *iop,
 | 
				
			||||||
 | 
										void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct eventfs_file *ef;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ef = kzalloc(sizeof(*ef), GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!ef)
 | 
				
			||||||
 | 
							return ERR_PTR(-ENOMEM);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ef->name = kstrdup(name, GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!ef->name) {
 | 
				
			||||||
 | 
							kfree(ef);
 | 
				
			||||||
 | 
							return ERR_PTR(-ENOMEM);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (S_ISDIR(mode)) {
 | 
				
			||||||
 | 
							ef->ei = kzalloc(sizeof(*ef->ei), GFP_KERNEL);
 | 
				
			||||||
 | 
							if (!ef->ei) {
 | 
				
			||||||
 | 
								kfree(ef->name);
 | 
				
			||||||
 | 
								kfree(ef);
 | 
				
			||||||
 | 
								return ERR_PTR(-ENOMEM);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							INIT_LIST_HEAD(&ef->ei->e_top_files);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							ef->ei = NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ef->iop = iop;
 | 
				
			||||||
 | 
						ef->fop = fop;
 | 
				
			||||||
 | 
						ef->mode = mode;
 | 
				
			||||||
 | 
						ef->data = data;
 | 
				
			||||||
 | 
						return ef;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * eventfs_create_events_dir - create the trace event structure
 | 
				
			||||||
 | 
					 * @name: the name of the directory to create.
 | 
				
			||||||
 | 
					 * @parent: parent dentry for this file.  This should be a directory dentry
 | 
				
			||||||
 | 
					 *          if set.  If this parameter is NULL, then the directory will be
 | 
				
			||||||
 | 
					 *          created in the root of the tracefs filesystem.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This function creates the top of the trace event directory.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct dentry *eventfs_create_events_dir(const char *name,
 | 
				
			||||||
 | 
										 struct dentry *parent)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct dentry *dentry = tracefs_start_creating(name, parent);
 | 
				
			||||||
 | 
						struct eventfs_inode *ei;
 | 
				
			||||||
 | 
						struct tracefs_inode *ti;
 | 
				
			||||||
 | 
						struct inode *inode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (IS_ERR(dentry))
 | 
				
			||||||
 | 
							return dentry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ei = kzalloc(sizeof(*ei), GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!ei)
 | 
				
			||||||
 | 
							return ERR_PTR(-ENOMEM);
 | 
				
			||||||
 | 
						inode = tracefs_get_inode(dentry->d_sb);
 | 
				
			||||||
 | 
						if (unlikely(!inode)) {
 | 
				
			||||||
 | 
							kfree(ei);
 | 
				
			||||||
 | 
							tracefs_failed_creating(dentry);
 | 
				
			||||||
 | 
							return ERR_PTR(-ENOMEM);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						INIT_LIST_HEAD(&ei->e_top_files);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ti = get_tracefs(inode);
 | 
				
			||||||
 | 
						ti->flags |= TRACEFS_EVENT_INODE;
 | 
				
			||||||
 | 
						ti->private = ei;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
 | 
				
			||||||
 | 
						inode->i_op = &eventfs_root_dir_inode_operations;
 | 
				
			||||||
 | 
						inode->i_fop = &eventfs_file_operations;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* directory inodes start off with i_nlink == 2 (for "." entry) */
 | 
				
			||||||
 | 
						inc_nlink(inode);
 | 
				
			||||||
 | 
						d_instantiate(dentry, inode);
 | 
				
			||||||
 | 
						inc_nlink(dentry->d_parent->d_inode);
 | 
				
			||||||
 | 
						fsnotify_mkdir(dentry->d_parent->d_inode, dentry);
 | 
				
			||||||
 | 
						return tracefs_end_creating(dentry);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * eventfs_add_subsystem_dir - add eventfs subsystem_dir to list to create later
 | 
				
			||||||
 | 
					 * @name: the name of the file to create.
 | 
				
			||||||
 | 
					 * @parent: parent dentry for this dir.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This function adds eventfs subsystem dir to list.
 | 
				
			||||||
 | 
					 * And all these dirs are created on the fly when they are looked up,
 | 
				
			||||||
 | 
					 * and the dentry and inodes will be removed when they are done.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct eventfs_file *eventfs_add_subsystem_dir(const char *name,
 | 
				
			||||||
 | 
										       struct dentry *parent)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct tracefs_inode *ti_parent;
 | 
				
			||||||
 | 
						struct eventfs_inode *ei_parent;
 | 
				
			||||||
 | 
						struct eventfs_file *ef;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!parent)
 | 
				
			||||||
 | 
							return ERR_PTR(-EINVAL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ti_parent = get_tracefs(parent->d_inode);
 | 
				
			||||||
 | 
						ei_parent = ti_parent->private;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ef = eventfs_prepare_ef(name, S_IFDIR, NULL, NULL, NULL);
 | 
				
			||||||
 | 
						if (IS_ERR(ef))
 | 
				
			||||||
 | 
							return ef;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&eventfs_mutex);
 | 
				
			||||||
 | 
						list_add_tail(&ef->list, &ei_parent->e_top_files);
 | 
				
			||||||
 | 
						mutex_unlock(&eventfs_mutex);
 | 
				
			||||||
 | 
						return ef;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * eventfs_add_dir - add eventfs dir to list to create later
 | 
				
			||||||
 | 
					 * @name: the name of the file to create.
 | 
				
			||||||
 | 
					 * @ef_parent: parent eventfs_file for this dir.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This function adds eventfs dir to list.
 | 
				
			||||||
 | 
					 * And all these dirs are created on the fly when they are looked up,
 | 
				
			||||||
 | 
					 * and the dentry and inodes will be removed when they are done.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct eventfs_file *eventfs_add_dir(const char *name,
 | 
				
			||||||
 | 
									     struct eventfs_file *ef_parent)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct eventfs_file *ef;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!ef_parent)
 | 
				
			||||||
 | 
							return ERR_PTR(-EINVAL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ef = eventfs_prepare_ef(name, S_IFDIR, NULL, NULL, NULL);
 | 
				
			||||||
 | 
						if (IS_ERR(ef))
 | 
				
			||||||
 | 
							return ef;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&eventfs_mutex);
 | 
				
			||||||
 | 
						list_add_tail(&ef->list, &ef_parent->ei->e_top_files);
 | 
				
			||||||
 | 
						mutex_unlock(&eventfs_mutex);
 | 
				
			||||||
 | 
						return ef;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,10 @@
 | 
				
			||||||
#ifndef _TRACEFS_INTERNAL_H
 | 
					#ifndef _TRACEFS_INTERNAL_H
 | 
				
			||||||
#define _TRACEFS_INTERNAL_H
 | 
					#define _TRACEFS_INTERNAL_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
						TRACEFS_EVENT_INODE     = BIT(1),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct tracefs_inode {
 | 
					struct tracefs_inode {
 | 
				
			||||||
	unsigned long           flags;
 | 
						unsigned long           flags;
 | 
				
			||||||
	void                    *private;
 | 
						void                    *private;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,6 +21,17 @@ struct file_operations;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_TRACING
 | 
					#ifdef CONFIG_TRACING
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct eventfs_file;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct dentry *eventfs_create_events_dir(const char *name,
 | 
				
			||||||
 | 
										 struct dentry *parent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct eventfs_file *eventfs_add_subsystem_dir(const char *name,
 | 
				
			||||||
 | 
										       struct dentry *parent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct eventfs_file *eventfs_add_dir(const char *name,
 | 
				
			||||||
 | 
									     struct eventfs_file *ef_parent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct dentry *tracefs_create_file(const char *name, umode_t mode,
 | 
					struct dentry *tracefs_create_file(const char *name, umode_t mode,
 | 
				
			||||||
				   struct dentry *parent, void *data,
 | 
									   struct dentry *parent, void *data,
 | 
				
			||||||
				   const struct file_operations *fops);
 | 
									   const struct file_operations *fops);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue