From: "Steven Rostedt (Google)" <rost...@goodmis.org>

Only the root "events" directory stores a dentry. There's no reason to
hold a dentry pointer for every eventfs_inode as it is never set except
for the root "events" eventfs_inode.

Create a eventfs_root_inode structure that holds the events_dir dentry.
The "events" eventfs_inode *is* special, let it have its own descriptor.

Signed-off-by: Steven Rostedt (Google) <rost...@goodmis.org>
---
 fs/tracefs/event_inode.c | 65 +++++++++++++++++++++++++++++++++-------
 fs/tracefs/internal.h    |  2 --
 2 files changed, 55 insertions(+), 12 deletions(-)

diff --git a/fs/tracefs/event_inode.c b/fs/tracefs/event_inode.c
index 1a831ba1042b..c50d089c9a7f 100644
--- a/fs/tracefs/event_inode.c
+++ b/fs/tracefs/event_inode.c
@@ -35,6 +35,17 @@ static DEFINE_MUTEX(eventfs_mutex);
 /* Choose something "unique" ;-) */
 #define EVENTFS_FILE_INODE_INO         0x12c4e37
 
+struct eventfs_root_inode {
+       struct eventfs_inode            ei;
+       struct dentry                   *events_dir;
+};
+
+static struct eventfs_root_inode *get_root_inode(struct eventfs_inode *ei)
+{
+       WARN_ON_ONCE(!ei->is_events);
+       return container_of(ei, struct eventfs_root_inode, ei);
+}
+
 /* Just try to make something consistent and unique */
 static int eventfs_dir_ino(struct eventfs_inode *ei)
 {
@@ -73,12 +84,18 @@ enum {
 static void release_ei(struct kref *ref)
 {
        struct eventfs_inode *ei = container_of(ref, struct eventfs_inode, 
kref);
+       struct eventfs_root_inode *rei;
 
        WARN_ON_ONCE(!ei->is_freed);
 
        kfree(ei->entry_attrs);
        kfree_const(ei->name);
-       kfree_rcu(ei, rcu);
+       if (ei->is_events) {
+               rei = get_root_inode(ei);
+               kfree_rcu(rei, ei.rcu);
+       } else {
+               kfree_rcu(ei, rcu);
+       }
 }
 
 static inline void put_ei(struct eventfs_inode *ei)
@@ -408,19 +425,43 @@ static struct dentry *lookup_dir_entry(struct dentry 
*dentry,
        return NULL;
 }
 
+static inline struct eventfs_inode *init_ei(struct eventfs_inode *ei, const 
char *name)
+{
+       ei->name = kstrdup_const(name, GFP_KERNEL);
+       if (!ei->name)
+               return NULL;
+       kref_init(&ei->kref);
+       return ei;
+}
+
 static inline struct eventfs_inode *alloc_ei(const char *name)
 {
        struct eventfs_inode *ei = kzalloc(sizeof(*ei), GFP_KERNEL);
+       struct eventfs_inode *result;
 
        if (!ei)
                return NULL;
 
-       ei->name = kstrdup_const(name, GFP_KERNEL);
-       if (!ei->name) {
+       result = init_ei(ei, name);
+       if (!result)
                kfree(ei);
+
+       return result;
+}
+
+static inline struct eventfs_inode *alloc_root_ei(const char *name)
+{
+       struct eventfs_root_inode *rei = kzalloc(sizeof(*rei), GFP_KERNEL);
+       struct eventfs_inode *ei;
+
+       if (!rei)
                return NULL;
-       }
-       kref_init(&ei->kref);
+
+       rei->ei.is_events = 1;
+       ei = init_ei(&rei->ei, name);
+       if (!ei)
+               kfree(rei);
+
        return ei;
 }
 
@@ -710,6 +751,7 @@ struct eventfs_inode *eventfs_create_events_dir(const char 
*name, struct dentry
                                                int size, void *data)
 {
        struct dentry *dentry = tracefs_start_creating(name, parent);
+       struct eventfs_root_inode *rei;
        struct eventfs_inode *ei;
        struct tracefs_inode *ti;
        struct inode *inode;
@@ -722,7 +764,7 @@ struct eventfs_inode *eventfs_create_events_dir(const char 
*name, struct dentry
        if (IS_ERR(dentry))
                return ERR_CAST(dentry);
 
-       ei = alloc_ei(name);
+       ei = alloc_root_ei(name);
        if (!ei)
                goto fail;
 
@@ -731,10 +773,11 @@ struct eventfs_inode *eventfs_create_events_dir(const 
char *name, struct dentry
                goto fail;
 
        // Note: we have a ref to the dentry from tracefs_start_creating()
-       ei->events_dir = dentry;
+       rei = get_root_inode(ei);
+       rei->events_dir = dentry;
+
        ei->entries = entries;
        ei->nr_entries = size;
-       ei->is_events = 1;
        ei->data = data;
 
        /* Save the ownership of this directory */
@@ -845,13 +888,15 @@ void eventfs_remove_dir(struct eventfs_inode *ei)
  */
 void eventfs_remove_events_dir(struct eventfs_inode *ei)
 {
+       struct eventfs_root_inode *rei;
        struct dentry *dentry;
 
-       dentry = ei->events_dir;
+       rei = get_root_inode(ei);
+       dentry = rei->events_dir;
        if (!dentry)
                return;
 
-       ei->events_dir = NULL;
+       rei->events_dir = NULL;
        eventfs_remove_dir(ei);
 
        /*
diff --git a/fs/tracefs/internal.h b/fs/tracefs/internal.h
index beb3dcd0e434..15c26f9aaad4 100644
--- a/fs/tracefs/internal.h
+++ b/fs/tracefs/internal.h
@@ -36,7 +36,6 @@ struct eventfs_attr {
  * @children:  link list into the child eventfs_inode
  * @entries:   the array of entries representing the files in the directory
  * @name:      the name of the directory to create
- * @events_dir: the dentry of the events directory
  * @entry_attrs: Saved mode and ownership of the @d_children
  * @data:      The private data to pass to the callbacks
  * @attr:      Saved mode and ownership of eventfs_inode itself
@@ -54,7 +53,6 @@ struct eventfs_inode {
        struct list_head                children;
        const struct eventfs_entry      *entries;
        const char                      *name;
-       struct dentry                   *events_dir;
        struct eventfs_attr             *entry_attrs;
        void                            *data;
        struct eventfs_attr             attr;
-- 
2.43.0



Reply via email to