xref: /openbmc/linux/fs/tracefs/event_inode.c (revision ca2478a7d974f38d29d27acb42a952c7f168916e)
1c1504e51SAjay Kaher // SPDX-License-Identifier: GPL-2.0-only
2c1504e51SAjay Kaher /*
3c1504e51SAjay Kaher  *  event_inode.c - part of tracefs, a pseudo file system for activating tracing
4c1504e51SAjay Kaher  *
535ee34c0SSteven Rostedt (Google)  *  Copyright (C) 2020-23 VMware Inc, author: Steven Rostedt <rostedt@goodmis.org>
6c1504e51SAjay Kaher  *  Copyright (C) 2020-23 VMware Inc, author: Ajay Kaher <akaher@vmware.com>
735ee34c0SSteven Rostedt (Google)  *  Copyright (C) 2023 Google, author: Steven Rostedt <rostedt@goodmis.org>
8c1504e51SAjay Kaher  *
9c1504e51SAjay Kaher  *  eventfs is used to dynamically create inodes and dentries based on the
10c1504e51SAjay Kaher  *  meta data provided by the tracing system.
11c1504e51SAjay Kaher  *
12c1504e51SAjay Kaher  *  eventfs stores the meta-data of files/dirs and holds off on creating
13c1504e51SAjay Kaher  *  inodes/dentries of the files. When accessed, the eventfs will create the
14c1504e51SAjay Kaher  *  inodes/dentries in a just-in-time (JIT) manner. The eventfs will clean up
15c1504e51SAjay Kaher  *  and delete the inodes/dentries when they are no longer referenced.
16c1504e51SAjay Kaher  */
17c1504e51SAjay Kaher #include <linux/fsnotify.h>
18c1504e51SAjay Kaher #include <linux/fs.h>
19c1504e51SAjay Kaher #include <linux/namei.h>
20c1504e51SAjay Kaher #include <linux/workqueue.h>
21c1504e51SAjay Kaher #include <linux/security.h>
22c1504e51SAjay Kaher #include <linux/tracefs.h>
23c1504e51SAjay Kaher #include <linux/kref.h>
24c1504e51SAjay Kaher #include <linux/delay.h>
25c1504e51SAjay Kaher #include "internal.h"
26c1504e51SAjay Kaher 
27d2a632aeSSteven Rostedt (Google) /*
28d2a632aeSSteven Rostedt (Google)  * eventfs_mutex protects the eventfs_inode (ei) dentry. Any access
29d2a632aeSSteven Rostedt (Google)  * to the ei->dentry must be done under this mutex and after checking
30b1391e36SSteven Rostedt (Google)  * if ei->is_freed is not set. When ei->is_freed is set, the dentry
31b1391e36SSteven Rostedt (Google)  * is on its way to being freed after the last dput() is made on it.
32d2a632aeSSteven Rostedt (Google)  */
33c1504e51SAjay Kaher static DEFINE_MUTEX(eventfs_mutex);
34d2a632aeSSteven Rostedt (Google) 
354e8731d2SSteven Rostedt (Google) /* Choose something "unique" ;-) */
364e8731d2SSteven Rostedt (Google) #define EVENTFS_FILE_INODE_INO		0x12c4e37
379a187657SSteven Rostedt (Google) 
38e5c80b23SSteven Rostedt (Google) struct eventfs_root_inode {
39e5c80b23SSteven Rostedt (Google) 	struct eventfs_inode		ei;
4051a2049aSSteven Rostedt (Google) 	struct inode			*parent_inode;
41e5c80b23SSteven Rostedt (Google) 	struct dentry			*events_dir;
42e5c80b23SSteven Rostedt (Google) };
43e5c80b23SSteven Rostedt (Google) 
get_root_inode(struct eventfs_inode * ei)44e5c80b23SSteven Rostedt (Google) static struct eventfs_root_inode *get_root_inode(struct eventfs_inode *ei)
45e5c80b23SSteven Rostedt (Google) {
46e5c80b23SSteven Rostedt (Google) 	WARN_ON_ONCE(!ei->is_events);
47e5c80b23SSteven Rostedt (Google) 	return container_of(ei, struct eventfs_root_inode, ei);
48e5c80b23SSteven Rostedt (Google) }
49e5c80b23SSteven Rostedt (Google) 
509a187657SSteven Rostedt (Google) /* Just try to make something consistent and unique */
eventfs_dir_ino(struct eventfs_inode * ei)519a187657SSteven Rostedt (Google) static int eventfs_dir_ino(struct eventfs_inode *ei)
529a187657SSteven Rostedt (Google) {
534e84ead3SSteven Rostedt (Google) 	if (!ei->ino) {
549a187657SSteven Rostedt (Google) 		ei->ino = get_next_ino();
554e84ead3SSteven Rostedt (Google) 		/* Must not have the file inode number */
564e84ead3SSteven Rostedt (Google) 		if (ei->ino == EVENTFS_FILE_INODE_INO)
574e84ead3SSteven Rostedt (Google) 			ei->ino = get_next_ino();
584e84ead3SSteven Rostedt (Google) 	}
599a187657SSteven Rostedt (Google) 
609a187657SSteven Rostedt (Google) 	return ei->ino;
619a187657SSteven Rostedt (Google) }
624e8731d2SSteven Rostedt (Google) 
63d2a632aeSSteven Rostedt (Google) /*
64d2a632aeSSteven Rostedt (Google)  * The eventfs_inode (ei) itself is protected by SRCU. It is released from
65d2a632aeSSteven Rostedt (Google)  * its parent's list and will have is_freed set (under eventfs_mutex).
66b1391e36SSteven Rostedt (Google)  * After the SRCU grace period is over and the last dput() is called
67b1391e36SSteven Rostedt (Google)  * the ei is freed.
68d2a632aeSSteven Rostedt (Google)  */
6963940449SAjay Kaher DEFINE_STATIC_SRCU(eventfs_srcu);
7063940449SAjay Kaher 
7132f4c167SSteven Rostedt (Google) /* Mode is unsigned short, use the upper bits for flags */
7232f4c167SSteven Rostedt (Google) enum {
7332f4c167SSteven Rostedt (Google) 	EVENTFS_SAVE_MODE	= BIT(16),
7432f4c167SSteven Rostedt (Google) 	EVENTFS_SAVE_UID	= BIT(17),
7532f4c167SSteven Rostedt (Google) 	EVENTFS_SAVE_GID	= BIT(18),
7632f4c167SSteven Rostedt (Google) };
7732f4c167SSteven Rostedt (Google) 
7832f4c167SSteven Rostedt (Google) #define EVENTFS_MODE_MASK	(EVENTFS_SAVE_MODE - 1)
7932f4c167SSteven Rostedt (Google) 
free_ei_rcu(struct rcu_head * rcu)80281eaee3SSteven Rostedt (Google) static void free_ei_rcu(struct rcu_head *rcu)
81281eaee3SSteven Rostedt (Google) {
82281eaee3SSteven Rostedt (Google) 	struct eventfs_inode *ei = container_of(rcu, struct eventfs_inode, rcu);
83281eaee3SSteven Rostedt (Google) 	struct eventfs_root_inode *rei;
84281eaee3SSteven Rostedt (Google) 
85281eaee3SSteven Rostedt (Google) 	kfree(ei->entry_attrs);
86281eaee3SSteven Rostedt (Google) 	kfree_const(ei->name);
87281eaee3SSteven Rostedt (Google) 	if (ei->is_events) {
88281eaee3SSteven Rostedt (Google) 		rei = get_root_inode(ei);
89281eaee3SSteven Rostedt (Google) 		kfree(rei);
90281eaee3SSteven Rostedt (Google) 	} else {
91281eaee3SSteven Rostedt (Google) 		kfree(ei);
92281eaee3SSteven Rostedt (Google) 	}
93281eaee3SSteven Rostedt (Google) }
94281eaee3SSteven Rostedt (Google) 
955dfb0410SLinus Torvalds /*
965dfb0410SLinus Torvalds  * eventfs_inode reference count management.
975dfb0410SLinus Torvalds  *
985dfb0410SLinus Torvalds  * NOTE! We count only references from dentries, in the
995dfb0410SLinus Torvalds  * form 'dentry->d_fsdata'. There are also references from
1005dfb0410SLinus Torvalds  * directory inodes ('ti->private'), but the dentry reference
1015dfb0410SLinus Torvalds  * count is always a superset of the inode reference count.
1025dfb0410SLinus Torvalds  */
release_ei(struct kref * ref)1035dfb0410SLinus Torvalds static void release_ei(struct kref *ref)
1045dfb0410SLinus Torvalds {
1055dfb0410SLinus Torvalds 	struct eventfs_inode *ei = container_of(ref, struct eventfs_inode, kref);
10614aa4f3eSSteven Rostedt (Google) 	const struct eventfs_entry *entry;
1075c3ea7dfSSteven Rostedt (Google) 
1085c3ea7dfSSteven Rostedt (Google) 	WARN_ON_ONCE(!ei->is_freed);
1095c3ea7dfSSteven Rostedt (Google) 
11014aa4f3eSSteven Rostedt (Google) 	for (int i = 0; i < ei->nr_entries; i++) {
11114aa4f3eSSteven Rostedt (Google) 		entry = &ei->entries[i];
11214aa4f3eSSteven Rostedt (Google) 		if (entry->release)
11314aa4f3eSSteven Rostedt (Google) 			entry->release(entry->name, ei->data);
11414aa4f3eSSteven Rostedt (Google) 	}
11514aa4f3eSSteven Rostedt (Google) 
1162ef3d120SMathias Krause 	call_srcu(&eventfs_srcu, &ei->rcu, free_ei_rcu);
117e5c80b23SSteven Rostedt (Google) }
1185dfb0410SLinus Torvalds 
put_ei(struct eventfs_inode * ei)1195dfb0410SLinus Torvalds static inline void put_ei(struct eventfs_inode *ei)
1205dfb0410SLinus Torvalds {
1215dfb0410SLinus Torvalds 	if (ei)
1225dfb0410SLinus Torvalds 		kref_put(&ei->kref, release_ei);
1235dfb0410SLinus Torvalds }
1245dfb0410SLinus Torvalds 
free_ei(struct eventfs_inode * ei)1255c3ea7dfSSteven Rostedt (Google) static inline void free_ei(struct eventfs_inode *ei)
1265c3ea7dfSSteven Rostedt (Google) {
1275c3ea7dfSSteven Rostedt (Google) 	if (ei) {
1285c3ea7dfSSteven Rostedt (Google) 		ei->is_freed = 1;
1295c3ea7dfSSteven Rostedt (Google) 		put_ei(ei);
1305c3ea7dfSSteven Rostedt (Google) 	}
1315c3ea7dfSSteven Rostedt (Google) }
1325c3ea7dfSSteven Rostedt (Google) 
13314aa4f3eSSteven Rostedt (Google) /*
13414aa4f3eSSteven Rostedt (Google)  * Called when creation of an ei fails, do not call release() functions.
13514aa4f3eSSteven Rostedt (Google)  */
cleanup_ei(struct eventfs_inode * ei)13614aa4f3eSSteven Rostedt (Google) static inline void cleanup_ei(struct eventfs_inode *ei)
13714aa4f3eSSteven Rostedt (Google) {
13814aa4f3eSSteven Rostedt (Google) 	if (ei) {
13914aa4f3eSSteven Rostedt (Google) 		/* Set nr_entries to 0 to prevent release() function being called */
14014aa4f3eSSteven Rostedt (Google) 		ei->nr_entries = 0;
14114aa4f3eSSteven Rostedt (Google) 		free_ei(ei);
14214aa4f3eSSteven Rostedt (Google) 	}
14314aa4f3eSSteven Rostedt (Google) }
14414aa4f3eSSteven Rostedt (Google) 
get_ei(struct eventfs_inode * ei)1455dfb0410SLinus Torvalds static inline struct eventfs_inode *get_ei(struct eventfs_inode *ei)
1465dfb0410SLinus Torvalds {
1475dfb0410SLinus Torvalds 	if (ei)
1485dfb0410SLinus Torvalds 		kref_get(&ei->kref);
1495dfb0410SLinus Torvalds 	return ei;
1505dfb0410SLinus Torvalds }
1515dfb0410SLinus Torvalds 
15263940449SAjay Kaher static struct dentry *eventfs_root_lookup(struct inode *dir,
15363940449SAjay Kaher 					  struct dentry *dentry,
15463940449SAjay Kaher 					  unsigned int flags);
1551bfdd54aSSteven Rostedt (Google) static int eventfs_iterate(struct file *file, struct dir_context *ctx);
156c1504e51SAjay Kaher 
update_attr(struct eventfs_attr * attr,struct iattr * iattr)15732f4c167SSteven Rostedt (Google) static void update_attr(struct eventfs_attr *attr, struct iattr *iattr)
15832f4c167SSteven Rostedt (Google) {
15932f4c167SSteven Rostedt (Google) 	unsigned int ia_valid = iattr->ia_valid;
16032f4c167SSteven Rostedt (Google) 
16132f4c167SSteven Rostedt (Google) 	if (ia_valid & ATTR_MODE) {
16232f4c167SSteven Rostedt (Google) 		attr->mode = (attr->mode & ~EVENTFS_MODE_MASK) |
16332f4c167SSteven Rostedt (Google) 			(iattr->ia_mode & EVENTFS_MODE_MASK) |
16432f4c167SSteven Rostedt (Google) 			EVENTFS_SAVE_MODE;
16532f4c167SSteven Rostedt (Google) 	}
16632f4c167SSteven Rostedt (Google) 	if (ia_valid & ATTR_UID) {
16732f4c167SSteven Rostedt (Google) 		attr->mode |= EVENTFS_SAVE_UID;
16832f4c167SSteven Rostedt (Google) 		attr->uid = iattr->ia_uid;
16932f4c167SSteven Rostedt (Google) 	}
17032f4c167SSteven Rostedt (Google) 	if (ia_valid & ATTR_GID) {
17132f4c167SSteven Rostedt (Google) 		attr->mode |= EVENTFS_SAVE_GID;
17232f4c167SSteven Rostedt (Google) 		attr->gid = iattr->ia_gid;
17332f4c167SSteven Rostedt (Google) 	}
17432f4c167SSteven Rostedt (Google) }
17532f4c167SSteven Rostedt (Google) 
eventfs_set_attr(struct mnt_idmap * idmap,struct dentry * dentry,struct iattr * iattr)17632f4c167SSteven Rostedt (Google) static int eventfs_set_attr(struct mnt_idmap *idmap, struct dentry *dentry,
17732f4c167SSteven Rostedt (Google) 			    struct iattr *iattr)
17832f4c167SSteven Rostedt (Google) {
17932f4c167SSteven Rostedt (Google) 	const struct eventfs_entry *entry;
18032f4c167SSteven Rostedt (Google) 	struct eventfs_inode *ei;
18132f4c167SSteven Rostedt (Google) 	const char *name;
18232f4c167SSteven Rostedt (Google) 	int ret;
18332f4c167SSteven Rostedt (Google) 
18432f4c167SSteven Rostedt (Google) 	mutex_lock(&eventfs_mutex);
18532f4c167SSteven Rostedt (Google) 	ei = dentry->d_fsdata;
186c58673caSSteven Rostedt (Google) 	if (ei->is_freed) {
18732f4c167SSteven Rostedt (Google) 		/* Do not allow changes if the event is about to be removed. */
18832f4c167SSteven Rostedt (Google) 		mutex_unlock(&eventfs_mutex);
18932f4c167SSteven Rostedt (Google) 		return -ENODEV;
19032f4c167SSteven Rostedt (Google) 	}
19132f4c167SSteven Rostedt (Google) 
19232f4c167SSteven Rostedt (Google) 	/* Preallocate the children mode array if necessary */
19332f4c167SSteven Rostedt (Google) 	if (!(dentry->d_inode->i_mode & S_IFDIR)) {
19432f4c167SSteven Rostedt (Google) 		if (!ei->entry_attrs) {
1951f20155aSErick Archer 			ei->entry_attrs = kcalloc(ei->nr_entries, sizeof(*ei->entry_attrs),
1966586a12dSSteven Rostedt (Google) 						  GFP_NOFS);
19732f4c167SSteven Rostedt (Google) 			if (!ei->entry_attrs) {
19832f4c167SSteven Rostedt (Google) 				ret = -ENOMEM;
19932f4c167SSteven Rostedt (Google) 				goto out;
20032f4c167SSteven Rostedt (Google) 			}
20132f4c167SSteven Rostedt (Google) 		}
20232f4c167SSteven Rostedt (Google) 	}
20332f4c167SSteven Rostedt (Google) 
20432f4c167SSteven Rostedt (Google) 	ret = simple_setattr(idmap, dentry, iattr);
20532f4c167SSteven Rostedt (Google) 	if (ret < 0)
20632f4c167SSteven Rostedt (Google) 		goto out;
20732f4c167SSteven Rostedt (Google) 
20832f4c167SSteven Rostedt (Google) 	/*
20932f4c167SSteven Rostedt (Google) 	 * If this is a dir, then update the ei cache, only the file
21032f4c167SSteven Rostedt (Google) 	 * mode is saved in the ei->m_children, and the ownership is
21132f4c167SSteven Rostedt (Google) 	 * determined by the parent directory.
21232f4c167SSteven Rostedt (Google) 	 */
21332f4c167SSteven Rostedt (Google) 	if (dentry->d_inode->i_mode & S_IFDIR) {
21432f4c167SSteven Rostedt (Google) 		update_attr(&ei->attr, iattr);
21532f4c167SSteven Rostedt (Google) 
21632f4c167SSteven Rostedt (Google) 	} else {
21732f4c167SSteven Rostedt (Google) 		name = dentry->d_name.name;
21832f4c167SSteven Rostedt (Google) 
21932f4c167SSteven Rostedt (Google) 		for (int i = 0; i < ei->nr_entries; i++) {
22032f4c167SSteven Rostedt (Google) 			entry = &ei->entries[i];
22132f4c167SSteven Rostedt (Google) 			if (strcmp(name, entry->name) == 0) {
22232f4c167SSteven Rostedt (Google) 				update_attr(&ei->entry_attrs[i], iattr);
22332f4c167SSteven Rostedt (Google) 				break;
22432f4c167SSteven Rostedt (Google) 			}
22532f4c167SSteven Rostedt (Google) 		}
22632f4c167SSteven Rostedt (Google) 	}
22732f4c167SSteven Rostedt (Google)  out:
22832f4c167SSteven Rostedt (Google) 	mutex_unlock(&eventfs_mutex);
22932f4c167SSteven Rostedt (Google) 	return ret;
23032f4c167SSteven Rostedt (Google) }
23132f4c167SSteven Rostedt (Google) 
update_events_attr(struct eventfs_inode * ei,struct super_block * sb)232e26405d5SSteven Rostedt (Google) static void update_events_attr(struct eventfs_inode *ei, struct super_block *sb)
233628adb84SSteven Rostedt (Google) {
23451a2049aSSteven Rostedt (Google) 	struct eventfs_root_inode *rei;
23551a2049aSSteven Rostedt (Google) 	struct inode *parent;
236628adb84SSteven Rostedt (Google) 
23751a2049aSSteven Rostedt (Google) 	rei = get_root_inode(ei);
23851a2049aSSteven Rostedt (Google) 
23951a2049aSSteven Rostedt (Google) 	/* Use the parent inode permissions unless root set its permissions */
24051a2049aSSteven Rostedt (Google) 	parent = rei->parent_inode;
24151a2049aSSteven Rostedt (Google) 
24251a2049aSSteven Rostedt (Google) 	if (rei->ei.attr.mode & EVENTFS_SAVE_UID)
24351a2049aSSteven Rostedt (Google) 		ei->attr.uid = rei->ei.attr.uid;
24451a2049aSSteven Rostedt (Google) 	else
24551a2049aSSteven Rostedt (Google) 		ei->attr.uid = parent->i_uid;
24651a2049aSSteven Rostedt (Google) 
24751a2049aSSteven Rostedt (Google) 	if (rei->ei.attr.mode & EVENTFS_SAVE_GID)
24851a2049aSSteven Rostedt (Google) 		ei->attr.gid = rei->ei.attr.gid;
24951a2049aSSteven Rostedt (Google) 	else
25051a2049aSSteven Rostedt (Google) 		ei->attr.gid = parent->i_gid;
251628adb84SSteven Rostedt (Google) }
252628adb84SSteven Rostedt (Google) 
set_top_events_ownership(struct inode * inode)253628adb84SSteven Rostedt (Google) static void set_top_events_ownership(struct inode *inode)
254628adb84SSteven Rostedt (Google) {
255628adb84SSteven Rostedt (Google) 	struct tracefs_inode *ti = get_tracefs(inode);
256628adb84SSteven Rostedt (Google) 	struct eventfs_inode *ei = ti->private;
257628adb84SSteven Rostedt (Google) 
258628adb84SSteven Rostedt (Google) 	/* The top events directory doesn't get automatically updated */
259e26405d5SSteven Rostedt (Google) 	if (!ei || !ei->is_events)
260628adb84SSteven Rostedt (Google) 		return;
261628adb84SSteven Rostedt (Google) 
262e26405d5SSteven Rostedt (Google) 	update_events_attr(ei, inode->i_sb);
263628adb84SSteven Rostedt (Google) 
264628adb84SSteven Rostedt (Google) 	if (!(ei->attr.mode & EVENTFS_SAVE_UID))
265628adb84SSteven Rostedt (Google) 		inode->i_uid = ei->attr.uid;
266628adb84SSteven Rostedt (Google) 
267628adb84SSteven Rostedt (Google) 	if (!(ei->attr.mode & EVENTFS_SAVE_GID))
268628adb84SSteven Rostedt (Google) 		inode->i_gid = ei->attr.gid;
269628adb84SSteven Rostedt (Google) }
270628adb84SSteven Rostedt (Google) 
eventfs_get_attr(struct mnt_idmap * idmap,const struct path * path,struct kstat * stat,u32 request_mask,unsigned int flags)271628adb84SSteven Rostedt (Google) static int eventfs_get_attr(struct mnt_idmap *idmap,
272628adb84SSteven Rostedt (Google) 			    const struct path *path, struct kstat *stat,
273628adb84SSteven Rostedt (Google) 			    u32 request_mask, unsigned int flags)
274628adb84SSteven Rostedt (Google) {
275628adb84SSteven Rostedt (Google) 	struct dentry *dentry = path->dentry;
276628adb84SSteven Rostedt (Google) 	struct inode *inode = d_backing_inode(dentry);
277628adb84SSteven Rostedt (Google) 
278628adb84SSteven Rostedt (Google) 	set_top_events_ownership(inode);
279628adb84SSteven Rostedt (Google) 
280628adb84SSteven Rostedt (Google) 	generic_fillattr(idmap, request_mask, inode, stat);
281628adb84SSteven Rostedt (Google) 	return 0;
282628adb84SSteven Rostedt (Google) }
283628adb84SSteven Rostedt (Google) 
eventfs_permission(struct mnt_idmap * idmap,struct inode * inode,int mask)284628adb84SSteven Rostedt (Google) static int eventfs_permission(struct mnt_idmap *idmap,
285628adb84SSteven Rostedt (Google) 			      struct inode *inode, int mask)
286628adb84SSteven Rostedt (Google) {
287628adb84SSteven Rostedt (Google) 	set_top_events_ownership(inode);
288628adb84SSteven Rostedt (Google) 	return generic_permission(idmap, inode, mask);
289628adb84SSteven Rostedt (Google) }
290628adb84SSteven Rostedt (Google) 
291e26405d5SSteven Rostedt (Google) static const struct inode_operations eventfs_dir_inode_operations = {
29263940449SAjay Kaher 	.lookup		= eventfs_root_lookup,
29332f4c167SSteven Rostedt (Google) 	.setattr	= eventfs_set_attr,
294628adb84SSteven Rostedt (Google) 	.getattr	= eventfs_get_attr,
295628adb84SSteven Rostedt (Google) 	.permission	= eventfs_permission,
29632f4c167SSteven Rostedt (Google) };
29732f4c167SSteven Rostedt (Google) 
29832f4c167SSteven Rostedt (Google) static const struct inode_operations eventfs_file_inode_operations = {
29932f4c167SSteven Rostedt (Google) 	.setattr	= eventfs_set_attr,
300c1504e51SAjay Kaher };
301c1504e51SAjay Kaher 
302c1504e51SAjay Kaher static const struct file_operations eventfs_file_operations = {
30363940449SAjay Kaher 	.read		= generic_read_dir,
3041bfdd54aSSteven Rostedt (Google) 	.iterate_shared	= eventfs_iterate,
30563940449SAjay Kaher 	.llseek		= generic_file_llseek,
306c1504e51SAjay Kaher };
307c1504e51SAjay Kaher 
eventfs_set_attrs(struct eventfs_inode * ei,bool update_uid,kuid_t uid,bool update_gid,kgid_t gid,int level)3087ec535edSSteven Rostedt (Google) static void eventfs_set_attrs(struct eventfs_inode *ei, bool update_uid, kuid_t uid,
3097ec535edSSteven Rostedt (Google) 			      bool update_gid, kgid_t gid, int level)
3107ec535edSSteven Rostedt (Google) {
3117ec535edSSteven Rostedt (Google) 	struct eventfs_inode *ei_child;
3127ec535edSSteven Rostedt (Google) 
3137ec535edSSteven Rostedt (Google) 	/* Update events/<system>/<event> */
3147ec535edSSteven Rostedt (Google) 	if (WARN_ON_ONCE(level > 3))
3157ec535edSSteven Rostedt (Google) 		return;
3167ec535edSSteven Rostedt (Google) 
3177ec535edSSteven Rostedt (Google) 	if (update_uid) {
3187ec535edSSteven Rostedt (Google) 		ei->attr.mode &= ~EVENTFS_SAVE_UID;
3197ec535edSSteven Rostedt (Google) 		ei->attr.uid = uid;
3207ec535edSSteven Rostedt (Google) 	}
3217ec535edSSteven Rostedt (Google) 
3227ec535edSSteven Rostedt (Google) 	if (update_gid) {
3237ec535edSSteven Rostedt (Google) 		ei->attr.mode &= ~EVENTFS_SAVE_GID;
3247ec535edSSteven Rostedt (Google) 		ei->attr.gid = gid;
3257ec535edSSteven Rostedt (Google) 	}
3267ec535edSSteven Rostedt (Google) 
3277ec535edSSteven Rostedt (Google) 	list_for_each_entry(ei_child, &ei->children, list) {
3287ec535edSSteven Rostedt (Google) 		eventfs_set_attrs(ei_child, update_uid, uid, update_gid, gid, level + 1);
3297ec535edSSteven Rostedt (Google) 	}
3307ec535edSSteven Rostedt (Google) 
3317ec535edSSteven Rostedt (Google) 	if (!ei->entry_attrs)
3327ec535edSSteven Rostedt (Google) 		return;
3337ec535edSSteven Rostedt (Google) 
3347ec535edSSteven Rostedt (Google) 	for (int i = 0; i < ei->nr_entries; i++) {
3357ec535edSSteven Rostedt (Google) 		if (update_uid) {
3367ec535edSSteven Rostedt (Google) 			ei->entry_attrs[i].mode &= ~EVENTFS_SAVE_UID;
3377ec535edSSteven Rostedt (Google) 			ei->entry_attrs[i].uid = uid;
3387ec535edSSteven Rostedt (Google) 		}
3397ec535edSSteven Rostedt (Google) 		if (update_gid) {
3407ec535edSSteven Rostedt (Google) 			ei->entry_attrs[i].mode &= ~EVENTFS_SAVE_GID;
3417ec535edSSteven Rostedt (Google) 			ei->entry_attrs[i].gid = gid;
3427ec535edSSteven Rostedt (Google) 		}
3437ec535edSSteven Rostedt (Google) 	}
3447ec535edSSteven Rostedt (Google) 
3457ec535edSSteven Rostedt (Google) }
3467ec535edSSteven Rostedt (Google) 
3475f91fc82SSteven Rostedt (Google) /*
3485f91fc82SSteven Rostedt (Google)  * On a remount of tracefs, if UID or GID options are set, then
3495f91fc82SSteven Rostedt (Google)  * the mount point inode permissions should be used.
3505f91fc82SSteven Rostedt (Google)  * Reset the saved permission flags appropriately.
3515f91fc82SSteven Rostedt (Google)  */
eventfs_remount(struct tracefs_inode * ti,bool update_uid,bool update_gid)3525f91fc82SSteven Rostedt (Google) void eventfs_remount(struct tracefs_inode *ti, bool update_uid, bool update_gid)
3535f91fc82SSteven Rostedt (Google) {
3545f91fc82SSteven Rostedt (Google) 	struct eventfs_inode *ei = ti->private;
3555f91fc82SSteven Rostedt (Google) 
3567ec535edSSteven Rostedt (Google) 	/* Only the events directory does the updates */
3577ec535edSSteven Rostedt (Google) 	if (!ei || !ei->is_events || ei->is_freed)
3585f91fc82SSteven Rostedt (Google) 		return;
3595f91fc82SSteven Rostedt (Google) 
3607ec535edSSteven Rostedt (Google) 	eventfs_set_attrs(ei, update_uid, ti->vfs_inode.i_uid,
3617ec535edSSteven Rostedt (Google) 			  update_gid, ti->vfs_inode.i_gid, 0);
3625f91fc82SSteven Rostedt (Google) }
3635f91fc82SSteven Rostedt (Google) 
3641b4dfdb3SSteven Rostedt (Google) /* Return the evenfs_inode of the "events" directory */
eventfs_find_events(struct dentry * dentry)3651b4dfdb3SSteven Rostedt (Google) static struct eventfs_inode *eventfs_find_events(struct dentry *dentry)
3661b4dfdb3SSteven Rostedt (Google) {
3671b4dfdb3SSteven Rostedt (Google) 	struct eventfs_inode *ei;
3681b4dfdb3SSteven Rostedt (Google) 
3691b4dfdb3SSteven Rostedt (Google) 	do {
3704928d0e3SLinus Torvalds 		// The parent is stable because we do not do renames
3714928d0e3SLinus Torvalds 		dentry = dentry->d_parent;
3724928d0e3SLinus Torvalds 		// ... and directories always have d_fsdata
3734928d0e3SLinus Torvalds 		ei = dentry->d_fsdata;
3741b4dfdb3SSteven Rostedt (Google) 
3751b4dfdb3SSteven Rostedt (Google) 		/*
3761b4dfdb3SSteven Rostedt (Google) 		 * If the ei is being freed, the ownership of the children
3771b4dfdb3SSteven Rostedt (Google) 		 * doesn't matter.
3781b4dfdb3SSteven Rostedt (Google) 		 */
3795ade5fbdSHao Ge 		if (ei->is_freed)
3805ade5fbdSHao Ge 			return NULL;
3815ade5fbdSHao Ge 
3824928d0e3SLinus Torvalds 		// Walk upwards until you find the events inode
3831b4dfdb3SSteven Rostedt (Google) 	} while (!ei->is_events);
3841b4dfdb3SSteven Rostedt (Google) 
385e26405d5SSteven Rostedt (Google) 	update_events_attr(ei, dentry->d_sb);
386628adb84SSteven Rostedt (Google) 
3871b4dfdb3SSteven Rostedt (Google) 	return ei;
3881b4dfdb3SSteven Rostedt (Google) }
3891b4dfdb3SSteven Rostedt (Google) 
update_inode_attr(struct dentry * dentry,struct inode * inode,struct eventfs_attr * attr,umode_t mode)3904d12a83eSSteven Rostedt (Google) static void update_inode_attr(struct dentry *dentry, struct inode *inode,
3914d12a83eSSteven Rostedt (Google) 			      struct eventfs_attr *attr, umode_t mode)
39232f4c167SSteven Rostedt (Google) {
3931b4dfdb3SSteven Rostedt (Google) 	struct eventfs_inode *events_ei = eventfs_find_events(dentry);
3941b4dfdb3SSteven Rostedt (Google) 
3951b4dfdb3SSteven Rostedt (Google) 	if (!events_ei)
39632f4c167SSteven Rostedt (Google) 		return;
3971b4dfdb3SSteven Rostedt (Google) 
3981b4dfdb3SSteven Rostedt (Google) 	inode->i_mode = mode;
3991b4dfdb3SSteven Rostedt (Google) 	inode->i_uid = events_ei->attr.uid;
4001b4dfdb3SSteven Rostedt (Google) 	inode->i_gid = events_ei->attr.gid;
4011b4dfdb3SSteven Rostedt (Google) 
4021b4dfdb3SSteven Rostedt (Google) 	if (!attr)
4031b4dfdb3SSteven Rostedt (Google) 		return;
40432f4c167SSteven Rostedt (Google) 
40532f4c167SSteven Rostedt (Google) 	if (attr->mode & EVENTFS_SAVE_MODE)
40632f4c167SSteven Rostedt (Google) 		inode->i_mode = attr->mode & EVENTFS_MODE_MASK;
40732f4c167SSteven Rostedt (Google) 
40832f4c167SSteven Rostedt (Google) 	if (attr->mode & EVENTFS_SAVE_UID)
40932f4c167SSteven Rostedt (Google) 		inode->i_uid = attr->uid;
41032f4c167SSteven Rostedt (Google) 
41132f4c167SSteven Rostedt (Google) 	if (attr->mode & EVENTFS_SAVE_GID)
41232f4c167SSteven Rostedt (Google) 		inode->i_gid = attr->gid;
4131b4dfdb3SSteven Rostedt (Google) }
4141b4dfdb3SSteven Rostedt (Google) 
415c1504e51SAjay Kaher /**
41621faa3deSLinus Torvalds  * lookup_file - look up a file in the tracefs filesystem
41721faa3deSLinus Torvalds  * @dentry: the dentry to look up
418dc9ee9a8SSteven Rostedt (Google)  * @mode: the permission that the file should have.
41932f4c167SSteven Rostedt (Google)  * @attr: saved attributes changed by user
42063940449SAjay Kaher  * @data: something that the caller will want to get to later on.
42163940449SAjay Kaher  * @fop: struct file_operations that should be used for this file.
42263940449SAjay Kaher  *
42335ee34c0SSteven Rostedt (Google)  * This function creates a dentry that represents a file in the eventsfs_inode
42435ee34c0SSteven Rostedt (Google)  * directory. The inode.i_private pointer will point to @data in the open()
42535ee34c0SSteven Rostedt (Google)  * call.
42663940449SAjay Kaher  */
lookup_file(struct eventfs_inode * parent_ei,struct dentry * dentry,umode_t mode,struct eventfs_attr * attr,void * data,const struct file_operations * fop)4275dfb0410SLinus Torvalds static struct dentry *lookup_file(struct eventfs_inode *parent_ei,
4285dfb0410SLinus Torvalds 				  struct dentry *dentry,
42921faa3deSLinus Torvalds 				  umode_t mode,
43032f4c167SSteven Rostedt (Google) 				  struct eventfs_attr *attr,
43121faa3deSLinus Torvalds 				  void *data,
43263940449SAjay Kaher 				  const struct file_operations *fop)
43363940449SAjay Kaher {
434a3760079SAjay Kaher 	struct tracefs_inode *ti;
435a3760079SAjay Kaher 	struct inode *inode;
436a3760079SAjay Kaher 
437dc9ee9a8SSteven Rostedt (Google) 	if (!(mode & S_IFMT))
438dc9ee9a8SSteven Rostedt (Google) 		mode |= S_IFREG;
439a3760079SAjay Kaher 
440dc9ee9a8SSteven Rostedt (Google) 	if (WARN_ON_ONCE(!S_ISREG(mode)))
4415dfb0410SLinus Torvalds 		return ERR_PTR(-EIO);
442a3760079SAjay Kaher 
443a3760079SAjay Kaher 	inode = tracefs_get_inode(dentry->d_sb);
444a3760079SAjay Kaher 	if (unlikely(!inode))
44521faa3deSLinus Torvalds 		return ERR_PTR(-ENOMEM);
446a3760079SAjay Kaher 
44732f4c167SSteven Rostedt (Google) 	/* If the user updated the directory's attributes, use them */
4484d12a83eSSteven Rostedt (Google) 	update_inode_attr(dentry, inode, attr, mode);
44932f4c167SSteven Rostedt (Google) 
45032f4c167SSteven Rostedt (Google) 	inode->i_op = &eventfs_file_inode_operations;
451a3760079SAjay Kaher 	inode->i_fop = fop;
452a3760079SAjay Kaher 	inode->i_private = data;
453a3760079SAjay Kaher 
4544e8731d2SSteven Rostedt (Google) 	/* All files will have the same inode number */
4554e8731d2SSteven Rostedt (Google) 	inode->i_ino = EVENTFS_FILE_INODE_INO;
4564e8731d2SSteven Rostedt (Google) 
457a3760079SAjay Kaher 	ti = get_tracefs(inode);
458a3760079SAjay Kaher 	ti->flags |= TRACEFS_EVENT_INODE;
45921faa3deSLinus Torvalds 
4605dfb0410SLinus Torvalds 	// Files have their parent's ei as their fsdata
4615dfb0410SLinus Torvalds 	dentry->d_fsdata = get_ei(parent_ei);
4625dfb0410SLinus Torvalds 
46321faa3deSLinus Torvalds 	d_add(dentry, inode);
4645dfb0410SLinus Torvalds 	return NULL;
46563940449SAjay Kaher };
46663940449SAjay Kaher 
46763940449SAjay Kaher /**
46821faa3deSLinus Torvalds  * lookup_dir_entry - look up a dir in the tracefs filesystem
46921faa3deSLinus Torvalds  * @dentry: the directory to look up
47032f4c167SSteven Rostedt (Google)  * @ei: the eventfs_inode that represents the directory to create
47163940449SAjay Kaher  *
47221faa3deSLinus Torvalds  * This function will look up a dentry for a directory represented by
47335ee34c0SSteven Rostedt (Google)  * a eventfs_inode.
47463940449SAjay Kaher  */
lookup_dir_entry(struct dentry * dentry,struct eventfs_inode * pei,struct eventfs_inode * ei)47521faa3deSLinus Torvalds static struct dentry *lookup_dir_entry(struct dentry *dentry,
47621faa3deSLinus Torvalds 	struct eventfs_inode *pei, struct eventfs_inode *ei)
47763940449SAjay Kaher {
478a3760079SAjay Kaher 	struct tracefs_inode *ti;
479a3760079SAjay Kaher 	struct inode *inode;
480a3760079SAjay Kaher 
481a3760079SAjay Kaher 	inode = tracefs_get_inode(dentry->d_sb);
482a3760079SAjay Kaher 	if (unlikely(!inode))
48321faa3deSLinus Torvalds 		return ERR_PTR(-ENOMEM);
484a3760079SAjay Kaher 
48532f4c167SSteven Rostedt (Google) 	/* If the user updated the directory's attributes, use them */
4864d12a83eSSteven Rostedt (Google) 	update_inode_attr(dentry, inode, &ei->attr,
4874d12a83eSSteven Rostedt (Google) 			  S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO);
48832f4c167SSteven Rostedt (Google) 
489e26405d5SSteven Rostedt (Google) 	inode->i_op = &eventfs_dir_inode_operations;
490a3760079SAjay Kaher 	inode->i_fop = &eventfs_file_operations;
491a3760079SAjay Kaher 
4924e8731d2SSteven Rostedt (Google) 	/* All directories will have the same inode number */
4939a187657SSteven Rostedt (Google) 	inode->i_ino = eventfs_dir_ino(ei);
4944e8731d2SSteven Rostedt (Google) 
495a3760079SAjay Kaher 	ti = get_tracefs(inode);
496a3760079SAjay Kaher 	ti->flags |= TRACEFS_EVENT_INODE;
497d1bcde94SLinus Torvalds 	/* Only directories have ti->private set to an ei, not files */
498d1bcde94SLinus Torvalds 	ti->private = ei;
499a3760079SAjay Kaher 
5005dfb0410SLinus Torvalds 	dentry->d_fsdata = get_ei(ei);
50121faa3deSLinus Torvalds 
50221faa3deSLinus Torvalds 	d_add(dentry, inode);
5035dfb0410SLinus Torvalds 	return NULL;
50463940449SAjay Kaher }
50563940449SAjay Kaher 
init_ei(struct eventfs_inode * ei,const char * name)506e5c80b23SSteven Rostedt (Google) static inline struct eventfs_inode *init_ei(struct eventfs_inode *ei, const char *name)
507e5c80b23SSteven Rostedt (Google) {
508e5c80b23SSteven Rostedt (Google) 	ei->name = kstrdup_const(name, GFP_KERNEL);
509e5c80b23SSteven Rostedt (Google) 	if (!ei->name)
510e5c80b23SSteven Rostedt (Google) 		return NULL;
511e5c80b23SSteven Rostedt (Google) 	kref_init(&ei->kref);
512e5c80b23SSteven Rostedt (Google) 	return ei;
513e5c80b23SSteven Rostedt (Google) }
514e5c80b23SSteven Rostedt (Google) 
alloc_ei(const char * name)5155dfb0410SLinus Torvalds static inline struct eventfs_inode *alloc_ei(const char *name)
5166e2a3352SSteven Rostedt (Google) {
5175dfb0410SLinus Torvalds 	struct eventfs_inode *ei = kzalloc(sizeof(*ei), GFP_KERNEL);
518e5c80b23SSteven Rostedt (Google) 	struct eventfs_inode *result;
5195dfb0410SLinus Torvalds 
5205dfb0410SLinus Torvalds 	if (!ei)
5215dfb0410SLinus Torvalds 		return NULL;
5225dfb0410SLinus Torvalds 
523e5c80b23SSteven Rostedt (Google) 	result = init_ei(ei, name);
524e5c80b23SSteven Rostedt (Google) 	if (!result)
5256e2a3352SSteven Rostedt (Google) 		kfree(ei);
526e5c80b23SSteven Rostedt (Google) 
527e5c80b23SSteven Rostedt (Google) 	return result;
5285dfb0410SLinus Torvalds }
529e5c80b23SSteven Rostedt (Google) 
alloc_root_ei(const char * name)530e5c80b23SSteven Rostedt (Google) static inline struct eventfs_inode *alloc_root_ei(const char *name)
531e5c80b23SSteven Rostedt (Google) {
532e5c80b23SSteven Rostedt (Google) 	struct eventfs_root_inode *rei = kzalloc(sizeof(*rei), GFP_KERNEL);
533e5c80b23SSteven Rostedt (Google) 	struct eventfs_inode *ei;
534e5c80b23SSteven Rostedt (Google) 
535e5c80b23SSteven Rostedt (Google) 	if (!rei)
536e5c80b23SSteven Rostedt (Google) 		return NULL;
537e5c80b23SSteven Rostedt (Google) 
538e5c80b23SSteven Rostedt (Google) 	rei->ei.is_events = 1;
539e5c80b23SSteven Rostedt (Google) 	ei = init_ei(&rei->ei, name);
540e5c80b23SSteven Rostedt (Google) 	if (!ei)
541e5c80b23SSteven Rostedt (Google) 		kfree(rei);
542e5c80b23SSteven Rostedt (Google) 
5435dfb0410SLinus Torvalds 	return ei;
5446e2a3352SSteven Rostedt (Google) }
5456e2a3352SSteven Rostedt (Google) 
54663940449SAjay Kaher /**
547c4619205SLinus Torvalds  * eventfs_d_release - dentry is going away
54835ee34c0SSteven Rostedt (Google)  * @dentry: dentry which has the reference to remove.
54963940449SAjay Kaher  *
55035ee34c0SSteven Rostedt (Google)  * Remove the association between a dentry from an eventfs_inode.
55163940449SAjay Kaher  */
eventfs_d_release(struct dentry * dentry)552c4619205SLinus Torvalds void eventfs_d_release(struct dentry *dentry)
55363940449SAjay Kaher {
5545dfb0410SLinus Torvalds 	put_ei(dentry->d_fsdata);
55563940449SAjay Kaher }
55663940449SAjay Kaher 
55763940449SAjay Kaher /**
55821faa3deSLinus Torvalds  * lookup_file_dentry - create a dentry for a file of an eventfs_inode
55935ee34c0SSteven Rostedt (Google)  * @ei: the eventfs_inode that the file will be created under
5605dfb0410SLinus Torvalds  * @idx: the index into the entry_attrs[] of the @ei
56135ee34c0SSteven Rostedt (Google)  * @parent: The parent dentry of the created file.
56235ee34c0SSteven Rostedt (Google)  * @name: The name of the file to create
56335ee34c0SSteven Rostedt (Google)  * @mode: The mode of the file.
56435ee34c0SSteven Rostedt (Google)  * @data: The data to use to set the inode of the file with on open()
56535ee34c0SSteven Rostedt (Google)  * @fops: The fops of the file to be created.
56663940449SAjay Kaher  *
56735ee34c0SSteven Rostedt (Google)  * Create a dentry for a file of an eventfs_inode @ei and place it into the
568ee699b54SSteven Rostedt (Google)  * address located at @e_dentry.
56963940449SAjay Kaher  */
57063940449SAjay Kaher static struct dentry *
lookup_file_dentry(struct dentry * dentry,struct eventfs_inode * ei,int idx,umode_t mode,void * data,const struct file_operations * fops)57121faa3deSLinus Torvalds lookup_file_dentry(struct dentry *dentry,
57221faa3deSLinus Torvalds 		   struct eventfs_inode *ei, int idx,
57321faa3deSLinus Torvalds 		   umode_t mode, void *data,
574ee699b54SSteven Rostedt (Google) 		   const struct file_operations *fops)
57563940449SAjay Kaher {
57632f4c167SSteven Rostedt (Google) 	struct eventfs_attr *attr = NULL;
57763940449SAjay Kaher 
57832f4c167SSteven Rostedt (Google) 	if (ei->entry_attrs)
57932f4c167SSteven Rostedt (Google) 		attr = &ei->entry_attrs[idx];
58032f4c167SSteven Rostedt (Google) 
5815dfb0410SLinus Torvalds 	return lookup_file(ei, dentry, mode, attr, data, fops);
58263940449SAjay Kaher }
58363940449SAjay Kaher 
58463940449SAjay Kaher /**
58563940449SAjay Kaher  * eventfs_root_lookup - lookup routine to create file/dir
58663940449SAjay Kaher  * @dir: in which a lookup is being done
58763940449SAjay Kaher  * @dentry: file/dir dentry
58835ee34c0SSteven Rostedt (Google)  * @flags: Just passed to simple_lookup()
58963940449SAjay Kaher  *
59035ee34c0SSteven Rostedt (Google)  * Used to create dynamic file/dir with-in @dir, search with-in @ei
59135ee34c0SSteven Rostedt (Google)  * list, if @dentry found go ahead and create the file/dir
59263940449SAjay Kaher  */
59335ee34c0SSteven Rostedt (Google) 
eventfs_root_lookup(struct inode * dir,struct dentry * dentry,unsigned int flags)59463940449SAjay Kaher static struct dentry *eventfs_root_lookup(struct inode *dir,
59563940449SAjay Kaher 					  struct dentry *dentry,
59663940449SAjay Kaher 					  unsigned int flags)
59763940449SAjay Kaher {
59835ee34c0SSteven Rostedt (Google) 	struct eventfs_inode *ei_child;
59963940449SAjay Kaher 	struct tracefs_inode *ti;
60063940449SAjay Kaher 	struct eventfs_inode *ei;
60135ee34c0SSteven Rostedt (Google) 	const char *name = dentry->d_name.name;
6025dfb0410SLinus Torvalds 	struct dentry *result = NULL;
60363940449SAjay Kaher 
60463940449SAjay Kaher 	ti = get_tracefs(dir);
60563940449SAjay Kaher 	if (!(ti->flags & TRACEFS_EVENT_INODE))
60621faa3deSLinus Torvalds 		return ERR_PTR(-EIO);
60763940449SAjay Kaher 
60835ee34c0SSteven Rostedt (Google) 	mutex_lock(&eventfs_mutex);
60935ee34c0SSteven Rostedt (Google) 
61021faa3deSLinus Torvalds 	ei = ti->private;
61121faa3deSLinus Torvalds 	if (!ei || ei->is_freed)
61235ee34c0SSteven Rostedt (Google) 		goto out;
61335ee34c0SSteven Rostedt (Google) 
61421faa3deSLinus Torvalds 	list_for_each_entry(ei_child, &ei->children, list) {
61535ee34c0SSteven Rostedt (Google) 		if (strcmp(ei_child->name, name) != 0)
61663940449SAjay Kaher 			continue;
61721faa3deSLinus Torvalds 		if (ei_child->is_freed)
61853cd8c57SBeau Belgrave 			goto out;
6195dfb0410SLinus Torvalds 		result = lookup_dir_entry(dentry, ei, ei_child);
62035ee34c0SSteven Rostedt (Google) 		goto out;
621ee699b54SSteven Rostedt (Google) 	}
62235ee34c0SSteven Rostedt (Google) 
62321faa3deSLinus Torvalds 	for (int i = 0; i < ei->nr_entries; i++) {
62421faa3deSLinus Torvalds 		void *data;
62521faa3deSLinus Torvalds 		umode_t mode;
62621faa3deSLinus Torvalds 		const struct file_operations *fops;
62721faa3deSLinus Torvalds 		const struct eventfs_entry *entry = &ei->entries[i];
62821faa3deSLinus Torvalds 
62921faa3deSLinus Torvalds 		if (strcmp(name, entry->name) != 0)
63035ee34c0SSteven Rostedt (Google) 			continue;
63121faa3deSLinus Torvalds 
63221faa3deSLinus Torvalds 		data = ei->data;
63321faa3deSLinus Torvalds 		if (entry->callback(name, &mode, &data, &fops) <= 0)
63453cd8c57SBeau Belgrave 			goto out;
63521faa3deSLinus Torvalds 
6365dfb0410SLinus Torvalds 		result = lookup_file_dentry(dentry, ei, i, mode, data, fops);
63721faa3deSLinus Torvalds 		goto out;
63835ee34c0SSteven Rostedt (Google) 	}
63935ee34c0SSteven Rostedt (Google)  out:
64021faa3deSLinus Torvalds 	mutex_unlock(&eventfs_mutex);
6415dfb0410SLinus Torvalds 	return result;
64263940449SAjay Kaher }
64363940449SAjay Kaher 
6441bfdd54aSSteven Rostedt (Google) /*
6451bfdd54aSSteven Rostedt (Google)  * Walk the children of a eventfs_inode to fill in getdents().
64663940449SAjay Kaher  */
eventfs_iterate(struct file * file,struct dir_context * ctx)6471bfdd54aSSteven Rostedt (Google) static int eventfs_iterate(struct file *file, struct dir_context *ctx)
64863940449SAjay Kaher {
64935ee34c0SSteven Rostedt (Google) 	const struct file_operations *fops;
6501bfdd54aSSteven Rostedt (Google) 	struct inode *f_inode = file_inode(file);
65135ee34c0SSteven Rostedt (Google) 	const struct eventfs_entry *entry;
65235ee34c0SSteven Rostedt (Google) 	struct eventfs_inode *ei_child;
65363940449SAjay Kaher 	struct tracefs_inode *ti;
65463940449SAjay Kaher 	struct eventfs_inode *ei;
6551bfdd54aSSteven Rostedt (Google) 	const char *name;
65635ee34c0SSteven Rostedt (Google) 	umode_t mode;
65763940449SAjay Kaher 	int idx;
6581bfdd54aSSteven Rostedt (Google) 	int ret = -EINVAL;
6591bfdd54aSSteven Rostedt (Google) 	int ino;
6601bfdd54aSSteven Rostedt (Google) 	int i, r, c;
6611bfdd54aSSteven Rostedt (Google) 
6621bfdd54aSSteven Rostedt (Google) 	if (!dir_emit_dots(file, ctx))
6631bfdd54aSSteven Rostedt (Google) 		return 0;
66463940449SAjay Kaher 
66563940449SAjay Kaher 	ti = get_tracefs(f_inode);
66663940449SAjay Kaher 	if (!(ti->flags & TRACEFS_EVENT_INODE))
66763940449SAjay Kaher 		return -EINVAL;
66863940449SAjay Kaher 
6691bfdd54aSSteven Rostedt (Google) 	c = ctx->pos - 2;
670ef36b4f9SSteven Rostedt (Google) 
67163940449SAjay Kaher 	idx = srcu_read_lock(&eventfs_srcu);
672ef36b4f9SSteven Rostedt (Google) 
67335ee34c0SSteven Rostedt (Google) 	mutex_lock(&eventfs_mutex);
67435ee34c0SSteven Rostedt (Google) 	ei = READ_ONCE(ti->private);
675c55d11eaSSteven Rostedt (Google) 	if (ei && ei->is_freed)
676c55d11eaSSteven Rostedt (Google) 		ei = NULL;
67735ee34c0SSteven Rostedt (Google) 	mutex_unlock(&eventfs_mutex);
67835ee34c0SSteven Rostedt (Google) 
679c55d11eaSSteven Rostedt (Google) 	if (!ei)
6801bfdd54aSSteven Rostedt (Google) 		goto out;
68135ee34c0SSteven Rostedt (Google) 
6821bfdd54aSSteven Rostedt (Google) 	/*
6831bfdd54aSSteven Rostedt (Google) 	 * Need to create the dentries and inodes to have a consistent
6841bfdd54aSSteven Rostedt (Google) 	 * inode number.
6851bfdd54aSSteven Rostedt (Google) 	 */
686e638899fSSteven Rostedt (Google) 	ret = 0;
687e638899fSSteven Rostedt (Google) 
688e638899fSSteven Rostedt (Google) 	/* Start at 'c' to jump over already read entries */
689e638899fSSteven Rostedt (Google) 	for (i = c; i < ei->nr_entries; i++, ctx->pos++) {
6901bfdd54aSSteven Rostedt (Google) 		void *cdata = ei->data;
6911bfdd54aSSteven Rostedt (Google) 
69235ee34c0SSteven Rostedt (Google) 		entry = &ei->entries[i];
69335ee34c0SSteven Rostedt (Google) 		name = entry->name;
6941bfdd54aSSteven Rostedt (Google) 
6951a6edfc7SSteven Rostedt (Google) 		mutex_lock(&eventfs_mutex);
69698102764SSteven Rostedt (Google) 		/* If ei->is_freed then just bail here, nothing more to do */
69798102764SSteven Rostedt (Google) 		if (ei->is_freed) {
69898102764SSteven Rostedt (Google) 			mutex_unlock(&eventfs_mutex);
699e638899fSSteven Rostedt (Google) 			goto out;
70098102764SSteven Rostedt (Google) 		}
70135ee34c0SSteven Rostedt (Google) 		r = entry->callback(name, &mode, &cdata, &fops);
7021a6edfc7SSteven Rostedt (Google) 		mutex_unlock(&eventfs_mutex);
70335ee34c0SSteven Rostedt (Google) 		if (r <= 0)
70435ee34c0SSteven Rostedt (Google) 			continue;
7051bfdd54aSSteven Rostedt (Google) 
706c55d11eaSSteven Rostedt (Google) 		ino = EVENTFS_FILE_INODE_INO;
7071bfdd54aSSteven Rostedt (Google) 
7081bfdd54aSSteven Rostedt (Google) 		if (!dir_emit(ctx, name, strlen(name), ino, DT_REG))
709e638899fSSteven Rostedt (Google) 			goto out;
710ef36b4f9SSteven Rostedt (Google) 	}
711f3f41f44SSteven Rostedt (Google) 
712e638899fSSteven Rostedt (Google) 	/* Subtract the skipped entries above */
713e638899fSSteven Rostedt (Google) 	c -= min((unsigned int)c, (unsigned int)ei->nr_entries);
714e638899fSSteven Rostedt (Google) 
715f3f41f44SSteven Rostedt (Google) 	list_for_each_entry_srcu(ei_child, &ei->children, list,
716f3f41f44SSteven Rostedt (Google) 				 srcu_read_lock_held(&eventfs_srcu)) {
717f3f41f44SSteven Rostedt (Google) 
718f3f41f44SSteven Rostedt (Google) 		if (c > 0) {
719f3f41f44SSteven Rostedt (Google) 			c--;
720f3f41f44SSteven Rostedt (Google) 			continue;
721f3f41f44SSteven Rostedt (Google) 		}
722f3f41f44SSteven Rostedt (Google) 
723f3f41f44SSteven Rostedt (Google) 		ctx->pos++;
724f3f41f44SSteven Rostedt (Google) 
725f3f41f44SSteven Rostedt (Google) 		if (ei_child->is_freed)
726f3f41f44SSteven Rostedt (Google) 			continue;
727f3f41f44SSteven Rostedt (Google) 
728f3f41f44SSteven Rostedt (Google) 		name = ei_child->name;
729f3f41f44SSteven Rostedt (Google) 
7309a187657SSteven Rostedt (Google) 		ino = eventfs_dir_ino(ei_child);
731f3f41f44SSteven Rostedt (Google) 
732f3f41f44SSteven Rostedt (Google) 		if (!dir_emit(ctx, name, strlen(name), ino, DT_DIR))
733f3f41f44SSteven Rostedt (Google) 			goto out_dec;
734f3f41f44SSteven Rostedt (Google) 	}
7351bfdd54aSSteven Rostedt (Google) 	ret = 1;
7361bfdd54aSSteven Rostedt (Google)  out:
73763940449SAjay Kaher 	srcu_read_unlock(&eventfs_srcu, idx);
738ef36b4f9SSteven Rostedt (Google) 
739ef36b4f9SSteven Rostedt (Google) 	return ret;
74082820a2dSSteven Rostedt (Google) 
74182820a2dSSteven Rostedt (Google)  out_dec:
74282820a2dSSteven Rostedt (Google) 	/* Incremented ctx->pos without adding something, reset it */
74382820a2dSSteven Rostedt (Google) 	ctx->pos--;
74482820a2dSSteven Rostedt (Google) 	goto out;
74563940449SAjay Kaher }
74663940449SAjay Kaher 
74763940449SAjay Kaher /**
74835ee34c0SSteven Rostedt (Google)  * eventfs_create_dir - Create the eventfs_inode for this directory
74935ee34c0SSteven Rostedt (Google)  * @name: The name of the directory to create.
75035ee34c0SSteven Rostedt (Google)  * @parent: The eventfs_inode of the parent directory.
75135ee34c0SSteven Rostedt (Google)  * @entries: A list of entries that represent the files under this directory
75235ee34c0SSteven Rostedt (Google)  * @size: The number of @entries
75335ee34c0SSteven Rostedt (Google)  * @data: The default data to pass to the files (an entry may override it).
754c1504e51SAjay Kaher  *
75535ee34c0SSteven Rostedt (Google)  * This function creates the descriptor to represent a directory in the
75635ee34c0SSteven Rostedt (Google)  * eventfs. This descriptor is an eventfs_inode, and it is returned to be
75735ee34c0SSteven Rostedt (Google)  * used to create other children underneath.
75835ee34c0SSteven Rostedt (Google)  *
75935ee34c0SSteven Rostedt (Google)  * The @entries is an array of eventfs_entry structures which has:
76035ee34c0SSteven Rostedt (Google)  *	const char		 *name
76135ee34c0SSteven Rostedt (Google)  *	eventfs_callback	callback;
76235ee34c0SSteven Rostedt (Google)  *
76335ee34c0SSteven Rostedt (Google)  * The name is the name of the file, and the callback is a pointer to a function
76435ee34c0SSteven Rostedt (Google)  * that will be called when the file is reference (either by lookup or by
76535ee34c0SSteven Rostedt (Google)  * reading a directory). The callback is of the prototype:
76635ee34c0SSteven Rostedt (Google)  *
76735ee34c0SSteven Rostedt (Google)  *    int callback(const char *name, umode_t *mode, void **data,
76835ee34c0SSteven Rostedt (Google)  *		   const struct file_operations **fops);
76935ee34c0SSteven Rostedt (Google)  *
77035ee34c0SSteven Rostedt (Google)  * When a file needs to be created, this callback will be called with
77135ee34c0SSteven Rostedt (Google)  *   name = the name of the file being created (so that the same callback
77235ee34c0SSteven Rostedt (Google)  *          may be used for multiple files).
77335ee34c0SSteven Rostedt (Google)  *   mode = a place to set the file's mode
77435ee34c0SSteven Rostedt (Google)  *   data = A pointer to @data, and the callback may replace it, which will
77535ee34c0SSteven Rostedt (Google)  *         cause the file created to pass the new data to the open() call.
77635ee34c0SSteven Rostedt (Google)  *   fops = the fops to use for the created file.
7771a6edfc7SSteven Rostedt (Google)  *
7781a6edfc7SSteven Rostedt (Google)  * NB. @callback is called while holding internal locks of the eventfs
7791a6edfc7SSteven Rostedt (Google)  *     system. The callback must not call any code that might also call into
7801a6edfc7SSteven Rostedt (Google)  *     the tracefs or eventfs system or it will risk creating a deadlock.
781c1504e51SAjay Kaher  */
eventfs_create_dir(const char * name,struct eventfs_inode * parent,const struct eventfs_entry * entries,int size,void * data)78235ee34c0SSteven Rostedt (Google) struct eventfs_inode *eventfs_create_dir(const char *name, struct eventfs_inode *parent,
78335ee34c0SSteven Rostedt (Google) 					 const struct eventfs_entry *entries,
78435ee34c0SSteven Rostedt (Google) 					 int size, void *data)
785c1504e51SAjay Kaher {
78635ee34c0SSteven Rostedt (Google) 	struct eventfs_inode *ei;
787c1504e51SAjay Kaher 
78835ee34c0SSteven Rostedt (Google) 	if (!parent)
78935ee34c0SSteven Rostedt (Google) 		return ERR_PTR(-EINVAL);
79035ee34c0SSteven Rostedt (Google) 
7915dfb0410SLinus Torvalds 	ei = alloc_ei(name);
79235ee34c0SSteven Rostedt (Google) 	if (!ei)
793c1504e51SAjay Kaher 		return ERR_PTR(-ENOMEM);
794c1504e51SAjay Kaher 
79535ee34c0SSteven Rostedt (Google) 	ei->entries = entries;
79635ee34c0SSteven Rostedt (Google) 	ei->nr_entries = size;
79735ee34c0SSteven Rostedt (Google) 	ei->data = data;
79835ee34c0SSteven Rostedt (Google) 	INIT_LIST_HEAD(&ei->children);
799d2a632aeSSteven Rostedt (Google) 	INIT_LIST_HEAD(&ei->list);
80035ee34c0SSteven Rostedt (Google) 
80135ee34c0SSteven Rostedt (Google) 	mutex_lock(&eventfs_mutex);
802ca2d3b2cSLinus Torvalds 	if (!parent->is_freed)
80335ee34c0SSteven Rostedt (Google) 		list_add_tail(&ei->list, &parent->children);
80435ee34c0SSteven Rostedt (Google) 	mutex_unlock(&eventfs_mutex);
80535ee34c0SSteven Rostedt (Google) 
806d2a632aeSSteven Rostedt (Google) 	/* Was the parent freed? */
807d2a632aeSSteven Rostedt (Google) 	if (list_empty(&ei->list)) {
80814aa4f3eSSteven Rostedt (Google) 		cleanup_ei(ei);
809b59603a1SMathias Krause 		ei = ERR_PTR(-EBUSY);
810d2a632aeSSteven Rostedt (Google) 	}
81135ee34c0SSteven Rostedt (Google) 	return ei;
812c1504e51SAjay Kaher }
813c1504e51SAjay Kaher 
814c1504e51SAjay Kaher /**
81535ee34c0SSteven Rostedt (Google)  * eventfs_create_events_dir - create the top level events directory
81635ee34c0SSteven Rostedt (Google)  * @name: The name of the top level directory to create.
81735ee34c0SSteven Rostedt (Google)  * @parent: Parent dentry for this file in the tracefs directory.
81835ee34c0SSteven Rostedt (Google)  * @entries: A list of entries that represent the files under this directory
81935ee34c0SSteven Rostedt (Google)  * @size: The number of @entries
82035ee34c0SSteven Rostedt (Google)  * @data: The default data to pass to the files (an entry may override it).
821c1504e51SAjay Kaher  *
822c1504e51SAjay Kaher  * This function creates the top of the trace event directory.
8231a6edfc7SSteven Rostedt (Google)  *
8241a6edfc7SSteven Rostedt (Google)  * See eventfs_create_dir() for use of @entries.
825c1504e51SAjay Kaher  */
eventfs_create_events_dir(const char * name,struct dentry * parent,const struct eventfs_entry * entries,int size,void * data)82635ee34c0SSteven Rostedt (Google) struct eventfs_inode *eventfs_create_events_dir(const char *name, struct dentry *parent,
82735ee34c0SSteven Rostedt (Google) 						const struct eventfs_entry *entries,
82835ee34c0SSteven Rostedt (Google) 						int size, void *data)
829c1504e51SAjay Kaher {
830c1504e51SAjay Kaher 	struct dentry *dentry = tracefs_start_creating(name, parent);
831e5c80b23SSteven Rostedt (Google) 	struct eventfs_root_inode *rei;
832c1504e51SAjay Kaher 	struct eventfs_inode *ei;
833c1504e51SAjay Kaher 	struct tracefs_inode *ti;
834c1504e51SAjay Kaher 	struct inode *inode;
8351b4dfdb3SSteven Rostedt (Google) 	kuid_t uid;
8361b4dfdb3SSteven Rostedt (Google) 	kgid_t gid;
837c1504e51SAjay Kaher 
838e2470945SSteven Rostedt (Google) 	if (security_locked_down(LOCKDOWN_TRACEFS))
839e2470945SSteven Rostedt (Google) 		return NULL;
840e2470945SSteven Rostedt (Google) 
841c1504e51SAjay Kaher 	if (IS_ERR(dentry))
84217e4e4d2SNathan Chancellor 		return ERR_CAST(dentry);
843c1504e51SAjay Kaher 
844e5c80b23SSteven Rostedt (Google) 	ei = alloc_root_ei(name);
845c1504e51SAjay Kaher 	if (!ei)
8465dfb0410SLinus Torvalds 		goto fail;
84735ee34c0SSteven Rostedt (Google) 
848c1504e51SAjay Kaher 	inode = tracefs_get_inode(dentry->d_sb);
84935ee34c0SSteven Rostedt (Google) 	if (unlikely(!inode))
85035ee34c0SSteven Rostedt (Google) 		goto fail;
85135ee34c0SSteven Rostedt (Google) 
8525dfb0410SLinus Torvalds 	// Note: we have a ref to the dentry from tracefs_start_creating()
853e5c80b23SSteven Rostedt (Google) 	rei = get_root_inode(ei);
854e5c80b23SSteven Rostedt (Google) 	rei->events_dir = dentry;
85551a2049aSSteven Rostedt (Google) 	rei->parent_inode = d_inode(dentry->d_sb->s_root);
856e5c80b23SSteven Rostedt (Google) 
85735ee34c0SSteven Rostedt (Google) 	ei->entries = entries;
85835ee34c0SSteven Rostedt (Google) 	ei->nr_entries = size;
85935ee34c0SSteven Rostedt (Google) 	ei->data = data;
86035ee34c0SSteven Rostedt (Google) 
8611b4dfdb3SSteven Rostedt (Google) 	/* Save the ownership of this directory */
8621b4dfdb3SSteven Rostedt (Google) 	uid = d_inode(dentry->d_parent)->i_uid;
8631b4dfdb3SSteven Rostedt (Google) 	gid = d_inode(dentry->d_parent)->i_gid;
8641b4dfdb3SSteven Rostedt (Google) 
8651b4dfdb3SSteven Rostedt (Google) 	ei->attr.uid = uid;
8661b4dfdb3SSteven Rostedt (Google) 	ei->attr.gid = gid;
8671b4dfdb3SSteven Rostedt (Google) 
86851a2049aSSteven Rostedt (Google) 	/*
86951a2049aSSteven Rostedt (Google) 	 * When the "events" directory is created, it takes on the
87051a2049aSSteven Rostedt (Google) 	 * permissions of its parent. But can be reset on remount.
87151a2049aSSteven Rostedt (Google) 	 */
87251a2049aSSteven Rostedt (Google) 	ei->attr.mode |= EVENTFS_SAVE_UID | EVENTFS_SAVE_GID;
87351a2049aSSteven Rostedt (Google) 
87435ee34c0SSteven Rostedt (Google) 	INIT_LIST_HEAD(&ei->children);
87535ee34c0SSteven Rostedt (Google) 	INIT_LIST_HEAD(&ei->list);
876c1504e51SAjay Kaher 
877c1504e51SAjay Kaher 	ti = get_tracefs(inode);
878e26405d5SSteven Rostedt (Google) 	ti->flags |= TRACEFS_EVENT_INODE;
879c1504e51SAjay Kaher 	ti->private = ei;
880c1504e51SAjay Kaher 
881c1504e51SAjay Kaher 	inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
8821b4dfdb3SSteven Rostedt (Google) 	inode->i_uid = uid;
8831b4dfdb3SSteven Rostedt (Google) 	inode->i_gid = gid;
884e26405d5SSteven Rostedt (Google) 	inode->i_op = &eventfs_dir_inode_operations;
885c1504e51SAjay Kaher 	inode->i_fop = &eventfs_file_operations;
886c1504e51SAjay Kaher 
8875dfb0410SLinus Torvalds 	dentry->d_fsdata = get_ei(ei);
888fb9b8eeaSSteven Rostedt (Google) 
889a49e9c72SSteven Rostedt (Google) 	/*
890a49e9c72SSteven Rostedt (Google) 	 * Keep all eventfs directories with i_nlink == 1.
891a49e9c72SSteven Rostedt (Google) 	 * Due to the dynamic nature of the dentry creations and not
892a49e9c72SSteven Rostedt (Google) 	 * wanting to add a pointer to the parent eventfs_inode in the
893a49e9c72SSteven Rostedt (Google) 	 * eventfs_inode structure, keeping the i_nlink in sync with the
894a49e9c72SSteven Rostedt (Google) 	 * number of directories would cause too much complexity for
895a49e9c72SSteven Rostedt (Google) 	 * something not worth much. Keeping directory links at 1
896a49e9c72SSteven Rostedt (Google) 	 * tells userspace not to trust the link number.
897a49e9c72SSteven Rostedt (Google) 	 */
898c1504e51SAjay Kaher 	d_instantiate(dentry, inode);
899a49e9c72SSteven Rostedt (Google) 	/* The dentry of the "events" parent does keep track though */
900c1504e51SAjay Kaher 	inc_nlink(dentry->d_parent->d_inode);
901c1504e51SAjay Kaher 	fsnotify_mkdir(dentry->d_parent->d_inode, dentry);
90235ee34c0SSteven Rostedt (Google) 	tracefs_end_creating(dentry);
90335ee34c0SSteven Rostedt (Google) 
90435ee34c0SSteven Rostedt (Google) 	return ei;
90535ee34c0SSteven Rostedt (Google) 
90635ee34c0SSteven Rostedt (Google)  fail:
90714aa4f3eSSteven Rostedt (Google) 	cleanup_ei(ei);
90835ee34c0SSteven Rostedt (Google) 	tracefs_failed_creating(dentry);
90935ee34c0SSteven Rostedt (Google) 	return ERR_PTR(-ENOMEM);
910c1504e51SAjay Kaher }
911c1504e51SAjay Kaher 
9125bdcd5f5SAjay Kaher /**
9135bdcd5f5SAjay Kaher  * eventfs_remove_rec - remove eventfs dir or file from list
91435ee34c0SSteven Rostedt (Google)  * @ei: eventfs_inode to be removed.
915773cd7dfSSteven Rostedt (Google)  * @level: prevent recursion from going more than 3 levels deep.
9165bdcd5f5SAjay Kaher  *
917773cd7dfSSteven Rostedt (Google)  * This function recursively removes eventfs_inodes which
918773cd7dfSSteven Rostedt (Google)  * contains info of files and/or directories.
9195bdcd5f5SAjay Kaher  */
eventfs_remove_rec(struct eventfs_inode * ei,int level)92074a9e56bSSteven Rostedt (Google) static void eventfs_remove_rec(struct eventfs_inode *ei, int level)
9215bdcd5f5SAjay Kaher {
92235ee34c0SSteven Rostedt (Google) 	struct eventfs_inode *ei_child;
9235bdcd5f5SAjay Kaher 
9245bdcd5f5SAjay Kaher 	/*
9255bdcd5f5SAjay Kaher 	 * Check recursion depth. It should never be greater than 3:
9265bdcd5f5SAjay Kaher 	 * 0 - events/
9275bdcd5f5SAjay Kaher 	 * 1 - events/group/
9285bdcd5f5SAjay Kaher 	 * 2 - events/group/event/
9295bdcd5f5SAjay Kaher 	 * 3 - events/group/event/file
9305bdcd5f5SAjay Kaher 	 */
9315bdcd5f5SAjay Kaher 	if (WARN_ON_ONCE(level > 3))
9325bdcd5f5SAjay Kaher 		return;
9335bdcd5f5SAjay Kaher 
9345bdcd5f5SAjay Kaher 	/* search for nested folders or files */
9355dfb0410SLinus Torvalds 	list_for_each_entry(ei_child, &ei->children, list)
93674a9e56bSSteven Rostedt (Google) 		eventfs_remove_rec(ei_child, level + 1);
93774a9e56bSSteven Rostedt (Google) 
938*05e08297SSteven Rostedt 	list_del_rcu(&ei->list);
9395c3ea7dfSSteven Rostedt (Google) 	free_ei(ei);
9405bdcd5f5SAjay Kaher }
9415bdcd5f5SAjay Kaher 
94235ee34c0SSteven Rostedt (Google) /**
943843879a6SJiapeng Chong  * eventfs_remove_dir - remove eventfs dir or file from list
94435ee34c0SSteven Rostedt (Google)  * @ei: eventfs_inode to be removed.
94535ee34c0SSteven Rostedt (Google)  *
94635ee34c0SSteven Rostedt (Google)  * This function acquire the eventfs_mutex lock and call eventfs_remove_rec()
94735ee34c0SSteven Rostedt (Google)  */
eventfs_remove_dir(struct eventfs_inode * ei)94835ee34c0SSteven Rostedt (Google) void eventfs_remove_dir(struct eventfs_inode *ei)
94935ee34c0SSteven Rostedt (Google) {
95035ee34c0SSteven Rostedt (Google) 	if (!ei)
95135ee34c0SSteven Rostedt (Google) 		return;
95235ee34c0SSteven Rostedt (Google) 
95335ee34c0SSteven Rostedt (Google) 	mutex_lock(&eventfs_mutex);
95474a9e56bSSteven Rostedt (Google) 	eventfs_remove_rec(ei, 0);
955c58673caSSteven Rostedt (Google) 	mutex_unlock(&eventfs_mutex);
9565bdcd5f5SAjay Kaher }
9575bdcd5f5SAjay Kaher 
9585bdcd5f5SAjay Kaher /**
959bceba0d3SSteven Rostedt (Google)  * eventfs_remove_events_dir - remove the top level eventfs directory
960bceba0d3SSteven Rostedt (Google)  * @ei: the event_inode returned by eventfs_create_events_dir().
9615bdcd5f5SAjay Kaher  *
962bceba0d3SSteven Rostedt (Google)  * This function removes the events main directory
9635bdcd5f5SAjay Kaher  */
eventfs_remove_events_dir(struct eventfs_inode * ei)964bceba0d3SSteven Rostedt (Google) void eventfs_remove_events_dir(struct eventfs_inode *ei)
9655bdcd5f5SAjay Kaher {
966e5c80b23SSteven Rostedt (Google) 	struct eventfs_root_inode *rei;
96774a9e56bSSteven Rostedt (Google) 	struct dentry *dentry;
9685bdcd5f5SAjay Kaher 
969e5c80b23SSteven Rostedt (Google) 	rei = get_root_inode(ei);
970e5c80b23SSteven Rostedt (Google) 	dentry = rei->events_dir;
9715dfb0410SLinus Torvalds 	if (!dentry)
9725dfb0410SLinus Torvalds 		return;
9735dfb0410SLinus Torvalds 
974e5c80b23SSteven Rostedt (Google) 	rei->events_dir = NULL;
975bceba0d3SSteven Rostedt (Google) 	eventfs_remove_dir(ei);
9765bdcd5f5SAjay Kaher 
97774a9e56bSSteven Rostedt (Google) 	/*
97874a9e56bSSteven Rostedt (Google) 	 * Matches the dget() done by tracefs_start_creating()
97974a9e56bSSteven Rostedt (Google) 	 * in eventfs_create_events_dir() when it the dentry was
98074a9e56bSSteven Rostedt (Google) 	 * created. In other words, it's a normal dentry that
98174a9e56bSSteven Rostedt (Google) 	 * sticks around while the other ei->dentry are created
98274a9e56bSSteven Rostedt (Google) 	 * and destroyed dynamically.
98374a9e56bSSteven Rostedt (Google) 	 */
9845dfb0410SLinus Torvalds 	d_invalidate(dentry);
985601daf7eSSteven Rostedt (Google) 	dput(dentry);
9865bdcd5f5SAjay Kaher }
987