Skip to content

Commit c1504e5

Browse files
akaherrostedt
authored andcommitted
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>
1 parent 2c6b6b1 commit c1504e5

File tree

4 files changed

+227
-0
lines changed

4 files changed

+227
-0
lines changed

fs/tracefs/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# SPDX-License-Identifier: GPL-2.0-only
22
tracefs-objs := inode.o
3+
tracefs-objs += event_inode.o
34

45
obj-$(CONFIG_TRACING) += tracefs.o
56

fs/tracefs/event_inode.c

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* event_inode.c - part of tracefs, a pseudo file system for activating tracing
4+
*
5+
* Copyright (C) 2020-23 VMware Inc, author: Steven Rostedt (VMware) <rostedt@goodmis.org>
6+
* Copyright (C) 2020-23 VMware Inc, author: Ajay Kaher <akaher@vmware.com>
7+
*
8+
* eventfs is used to dynamically create inodes and dentries based on the
9+
* meta data provided by the tracing system.
10+
*
11+
* eventfs stores the meta-data of files/dirs and holds off on creating
12+
* inodes/dentries of the files. When accessed, the eventfs will create the
13+
* inodes/dentries in a just-in-time (JIT) manner. The eventfs will clean up
14+
* and delete the inodes/dentries when they are no longer referenced.
15+
*/
16+
#include <linux/fsnotify.h>
17+
#include <linux/fs.h>
18+
#include <linux/namei.h>
19+
#include <linux/workqueue.h>
20+
#include <linux/security.h>
21+
#include <linux/tracefs.h>
22+
#include <linux/kref.h>
23+
#include <linux/delay.h>
24+
#include "internal.h"
25+
26+
struct eventfs_inode {
27+
struct list_head e_top_files;
28+
};
29+
30+
/**
31+
* struct eventfs_file - hold the properties of the eventfs files and
32+
* directories.
33+
* @name: the name of the file or directory to create
34+
* @list: file or directory to be added to parent directory
35+
* @ei: list of files and directories within directory
36+
* @fop: file_operations for file or directory
37+
* @iop: inode_operations for file or directory
38+
* @data: something that the caller will want to get to later on
39+
* @mode: the permission that the file or directory should have
40+
*/
41+
struct eventfs_file {
42+
const char *name;
43+
struct list_head list;
44+
struct eventfs_inode *ei;
45+
const struct file_operations *fop;
46+
const struct inode_operations *iop;
47+
void *data;
48+
umode_t mode;
49+
};
50+
51+
static DEFINE_MUTEX(eventfs_mutex);
52+
53+
static const struct inode_operations eventfs_root_dir_inode_operations = {
54+
};
55+
56+
static const struct file_operations eventfs_file_operations = {
57+
};
58+
59+
/**
60+
* eventfs_prepare_ef - helper function to prepare eventfs_file
61+
* @name: the name of the file/directory to create.
62+
* @mode: the permission that the file should have.
63+
* @fop: struct file_operations that should be used for this file/directory.
64+
* @iop: struct inode_operations that should be used for this file/directory.
65+
* @data: something that the caller will want to get to later on. The
66+
* inode.i_private pointer will point to this value on the open() call.
67+
*
68+
* This function allocates and fills the eventfs_file structure.
69+
*/
70+
static struct eventfs_file *eventfs_prepare_ef(const char *name, umode_t mode,
71+
const struct file_operations *fop,
72+
const struct inode_operations *iop,
73+
void *data)
74+
{
75+
struct eventfs_file *ef;
76+
77+
ef = kzalloc(sizeof(*ef), GFP_KERNEL);
78+
if (!ef)
79+
return ERR_PTR(-ENOMEM);
80+
81+
ef->name = kstrdup(name, GFP_KERNEL);
82+
if (!ef->name) {
83+
kfree(ef);
84+
return ERR_PTR(-ENOMEM);
85+
}
86+
87+
if (S_ISDIR(mode)) {
88+
ef->ei = kzalloc(sizeof(*ef->ei), GFP_KERNEL);
89+
if (!ef->ei) {
90+
kfree(ef->name);
91+
kfree(ef);
92+
return ERR_PTR(-ENOMEM);
93+
}
94+
INIT_LIST_HEAD(&ef->ei->e_top_files);
95+
} else {
96+
ef->ei = NULL;
97+
}
98+
99+
ef->iop = iop;
100+
ef->fop = fop;
101+
ef->mode = mode;
102+
ef->data = data;
103+
return ef;
104+
}
105+
106+
/**
107+
* eventfs_create_events_dir - create the trace event structure
108+
* @name: the name of the directory to create.
109+
* @parent: parent dentry for this file. This should be a directory dentry
110+
* if set. If this parameter is NULL, then the directory will be
111+
* created in the root of the tracefs filesystem.
112+
*
113+
* This function creates the top of the trace event directory.
114+
*/
115+
struct dentry *eventfs_create_events_dir(const char *name,
116+
struct dentry *parent)
117+
{
118+
struct dentry *dentry = tracefs_start_creating(name, parent);
119+
struct eventfs_inode *ei;
120+
struct tracefs_inode *ti;
121+
struct inode *inode;
122+
123+
if (IS_ERR(dentry))
124+
return dentry;
125+
126+
ei = kzalloc(sizeof(*ei), GFP_KERNEL);
127+
if (!ei)
128+
return ERR_PTR(-ENOMEM);
129+
inode = tracefs_get_inode(dentry->d_sb);
130+
if (unlikely(!inode)) {
131+
kfree(ei);
132+
tracefs_failed_creating(dentry);
133+
return ERR_PTR(-ENOMEM);
134+
}
135+
136+
INIT_LIST_HEAD(&ei->e_top_files);
137+
138+
ti = get_tracefs(inode);
139+
ti->flags |= TRACEFS_EVENT_INODE;
140+
ti->private = ei;
141+
142+
inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
143+
inode->i_op = &eventfs_root_dir_inode_operations;
144+
inode->i_fop = &eventfs_file_operations;
145+
146+
/* directory inodes start off with i_nlink == 2 (for "." entry) */
147+
inc_nlink(inode);
148+
d_instantiate(dentry, inode);
149+
inc_nlink(dentry->d_parent->d_inode);
150+
fsnotify_mkdir(dentry->d_parent->d_inode, dentry);
151+
return tracefs_end_creating(dentry);
152+
}
153+
154+
/**
155+
* eventfs_add_subsystem_dir - add eventfs subsystem_dir to list to create later
156+
* @name: the name of the file to create.
157+
* @parent: parent dentry for this dir.
158+
*
159+
* This function adds eventfs subsystem dir to list.
160+
* And all these dirs are created on the fly when they are looked up,
161+
* and the dentry and inodes will be removed when they are done.
162+
*/
163+
struct eventfs_file *eventfs_add_subsystem_dir(const char *name,
164+
struct dentry *parent)
165+
{
166+
struct tracefs_inode *ti_parent;
167+
struct eventfs_inode *ei_parent;
168+
struct eventfs_file *ef;
169+
170+
if (!parent)
171+
return ERR_PTR(-EINVAL);
172+
173+
ti_parent = get_tracefs(parent->d_inode);
174+
ei_parent = ti_parent->private;
175+
176+
ef = eventfs_prepare_ef(name, S_IFDIR, NULL, NULL, NULL);
177+
if (IS_ERR(ef))
178+
return ef;
179+
180+
mutex_lock(&eventfs_mutex);
181+
list_add_tail(&ef->list, &ei_parent->e_top_files);
182+
mutex_unlock(&eventfs_mutex);
183+
return ef;
184+
}
185+
186+
/**
187+
* eventfs_add_dir - add eventfs dir to list to create later
188+
* @name: the name of the file to create.
189+
* @ef_parent: parent eventfs_file for this dir.
190+
*
191+
* This function adds eventfs dir to list.
192+
* And all these dirs are created on the fly when they are looked up,
193+
* and the dentry and inodes will be removed when they are done.
194+
*/
195+
struct eventfs_file *eventfs_add_dir(const char *name,
196+
struct eventfs_file *ef_parent)
197+
{
198+
struct eventfs_file *ef;
199+
200+
if (!ef_parent)
201+
return ERR_PTR(-EINVAL);
202+
203+
ef = eventfs_prepare_ef(name, S_IFDIR, NULL, NULL, NULL);
204+
if (IS_ERR(ef))
205+
return ef;
206+
207+
mutex_lock(&eventfs_mutex);
208+
list_add_tail(&ef->list, &ef_parent->ei->e_top_files);
209+
mutex_unlock(&eventfs_mutex);
210+
return ef;
211+
}

fs/tracefs/internal.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
#ifndef _TRACEFS_INTERNAL_H
33
#define _TRACEFS_INTERNAL_H
44

5+
enum {
6+
TRACEFS_EVENT_INODE = BIT(1),
7+
};
8+
59
struct tracefs_inode {
610
unsigned long flags;
711
void *private;

include/linux/tracefs.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,17 @@ struct file_operations;
2121

2222
#ifdef CONFIG_TRACING
2323

24+
struct eventfs_file;
25+
26+
struct dentry *eventfs_create_events_dir(const char *name,
27+
struct dentry *parent);
28+
29+
struct eventfs_file *eventfs_add_subsystem_dir(const char *name,
30+
struct dentry *parent);
31+
32+
struct eventfs_file *eventfs_add_dir(const char *name,
33+
struct eventfs_file *ef_parent);
34+
2435
struct dentry *tracefs_create_file(const char *name, umode_t mode,
2536
struct dentry *parent, void *data,
2637
const struct file_operations *fops);

0 commit comments

Comments
 (0)