Re: [linus:master] [eventfs] 852e46e239: BUG:unable_to_handle_page_fault_for_address
From: Steven Rostedt <rostedt@goodmis.org>
Date: 2024-01-31 15:58:34
Also in:
lkml, oe-lkp
Subsystem:
filesystems (vfs and infrastructure), the rest, tracing · Maintainers:
Alexander Viro, Christian Brauner, Linus Torvalds, Steven Rostedt, Masami Hiramatsu
On Tue, 30 Jan 2024 11:54:56 -0800 Linus Torvalds [off-list ref] wrote:
If you do run the full tracefs tests on the whole series, and there are no other major problems, I'll happily take it all for 6.8. And yes, even mark it for stable. I think the other bugs are much harder to hit, but I do think they exist. And code deletion is always good. So give it the full test attention, and *if* it all still looks good and there are no new subtle issues that crop up, let's just put this saga behind us asap.
BTW, I ran my full test suite on your patches with the below updates and it all passed. Note, I did not run the "bisectable" portion of my test. That is, the part that runs tests on each patch in the series. Because I know that fails. I just ran the tests on the last applied patch. I can break up and clean up the patches so that they are bisectable, and if that passes the bisectable portion of my tests, I can still send them to you for 6.8. I think this does fix a lot of hidden bugs, and would like all this to go back to 6.6 when the eventfs was first introduced. -- Steve
diff --git a/fs/tracefs/event_inode.c b/fs/tracefs/event_inode.c
index acdc797bd9c0..31cbe38739fa 100644
--- a/fs/tracefs/event_inode.c
+++ b/fs/tracefs/event_inode.c@@ -74,7 +74,8 @@ static void release_ei(struct kref *ref) { struct eventfs_inode *ei = container_of(ref, struct eventfs_inode, kref); kfree(ei->entry_attrs); - kfree(ei); + kfree_const(ei->name); + kfree_rcu(ei, rcu); } static inline void put_ei(struct eventfs_inode *ei)
@@ -348,8 +349,7 @@ static struct dentry *lookup_file(struct eventfs_inode *parent_ei, inode->i_ino = EVENTFS_FILE_INODE_INO; ti = get_tracefs(inode); - ti->flags = TRACEFS_EVENT_INODE; - ti->private = NULL; // Directories have 'ei', files not + ti->flags |= TRACEFS_EVENT_INODE; // Files have their parent's ei as their fsdata dentry->d_fsdata = get_ei(parent_ei);
@@ -388,7 +388,8 @@ static struct dentry *lookup_dir_entry(struct dentry *dentry, inode->i_ino = eventfs_dir_ino(ei); ti = get_tracefs(inode); - ti->flags = TRACEFS_EVENT_INODE; + ti->flags |= TRACEFS_EVENT_INODE; + /* Only directories have ti->private set to an ei, not files */ ti->private = ei; dentry->d_fsdata = get_ei(ei);
@@ -402,17 +403,20 @@ static struct dentry *lookup_dir_entry(struct dentry *dentry, static inline struct eventfs_inode *alloc_ei(const char *name) { - int namesize = strlen(name) + 1; - struct eventfs_inode *ei = kzalloc(sizeof(*ei) + namesize, GFP_KERNEL); + struct eventfs_inode *ei = kzalloc(sizeof(*ei), GFP_KERNEL); - if (ei) { - memcpy((char *)ei->name, name, namesize); - kref_init(&ei->kref); + if (!ei) + return NULL; + + ei->name = kstrdup_const(name, GFP_KERNEL); + if (!ei->name) { + kfree(ei); + return NULL; } + kref_init(&ei->kref); return ei; } - /** * eventfs_d_release - dentry is going away * @dentry: dentry which has the reference to remove.
@@ -750,7 +754,7 @@ struct eventfs_inode *eventfs_create_events_dir(const char *name, struct dentry INIT_LIST_HEAD(&ei->list); ti = get_tracefs(inode); - ti->flags = TRACEFS_EVENT_INODE | TRACEFS_EVENT_TOP_INODE; + ti->flags |= TRACEFS_EVENT_INODE | TRACEFS_EVENT_TOP_INODE; ti->private = ei; inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
@@ -847,5 +851,6 @@ void eventfs_remove_events_dir(struct eventfs_inode *ei) * sticks around while the other ei->dentry are created * and destroyed dynamically. */ + d_invalidate(dentry); dput(dentry); }
diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c
index 64122787e5d0..cf90ea86baf8 100644
--- a/fs/tracefs/inode.c
+++ b/fs/tracefs/inode.c@@ -38,8 +38,6 @@ static struct inode *tracefs_alloc_inode(struct super_block *sb) if (!ti) return NULL; - ti->flags = 0; - return &ti->vfs_inode; }
@@ -506,75 +504,6 @@ struct dentry *tracefs_end_creating(struct dentry *dentry) return dentry; } -/** - * eventfs_start_creating - start the process of creating a dentry - * @name: Name of the file created for the dentry - * @parent: The parent dentry where this dentry will be created - * - * This is a simple helper function for the dynamically created eventfs - * files. When the directory of the eventfs files are accessed, their - * dentries are created on the fly. This function is used to start that - * process. - */ -struct dentry *eventfs_start_creating(const char *name, struct dentry *parent) -{ - struct dentry *dentry; - int error; - - /* Must always have a parent. */ - if (WARN_ON_ONCE(!parent)) - return ERR_PTR(-EINVAL); - - error = simple_pin_fs(&trace_fs_type, &tracefs_mount, - &tracefs_mount_count); - if (error) - return ERR_PTR(error); - - if (unlikely(IS_DEADDIR(parent->d_inode))) - dentry = ERR_PTR(-ENOENT); - else - dentry = lookup_one_len(name, parent, strlen(name)); - - if (!IS_ERR(dentry) && dentry->d_inode) { - dput(dentry); - dentry = ERR_PTR(-EEXIST); - } - - if (IS_ERR(dentry)) - simple_release_fs(&tracefs_mount, &tracefs_mount_count); - - return dentry; -} - -/** - * eventfs_failed_creating - clean up a failed eventfs dentry creation - * @dentry: The dentry to clean up - * - * If after calling eventfs_start_creating(), a failure is detected, the - * resources created by eventfs_start_creating() needs to be cleaned up. In - * that case, this function should be called to perform that clean up. - */ -struct dentry *eventfs_failed_creating(struct dentry *dentry) -{ - dput(dentry); - simple_release_fs(&tracefs_mount, &tracefs_mount_count); - return NULL; -} - -/** - * eventfs_end_creating - Finish the process of creating a eventfs dentry - * @dentry: The dentry that has successfully been created. - * - * This function is currently just a place holder to match - * eventfs_start_creating(). In case any synchronization needs to be added, - * this function will be used to implement that without having to modify - * the callers of eventfs_start_creating(). - */ -struct dentry *eventfs_end_creating(struct dentry *dentry) -{ - return dentry; -} - /* Find the inode that this will use for default */ static struct inode *instance_inode(struct dentry *parent, struct inode *inode) {
@@ -788,6 +717,7 @@ static void init_once(void *foo) { struct tracefs_inode *ti = (struct tracefs_inode *) foo; + memset(ti, 0, sizeof(*ti)); inode_init_once(&ti->vfs_inode); }
diff --git a/fs/tracefs/internal.h b/fs/tracefs/internal.h
index d4194466b643..ca1ccc86986f 100644
--- a/fs/tracefs/internal.h
+++ b/fs/tracefs/internal.h@@ -46,6 +46,7 @@ struct eventfs_inode { struct kref kref; struct list_head list; const struct eventfs_entry *entries; + const char *name; struct list_head children; struct dentry *events_dir; struct eventfs_attr *entry_attrs;
@@ -64,7 +65,6 @@ struct eventfs_inode { struct llist_node llist; struct rcu_head rcu; }; - const char name[]; }; static inline struct tracefs_inode *get_tracefs(const struct inode *inode)
@@ -76,9 +76,6 @@ struct dentry *tracefs_start_creating(const char *name, struct dentry *parent); struct dentry *tracefs_end_creating(struct dentry *dentry); struct dentry *tracefs_failed_creating(struct dentry *dentry); struct inode *tracefs_get_inode(struct super_block *sb); -struct dentry *eventfs_start_creating(const char *name, struct dentry *parent); -struct dentry *eventfs_failed_creating(struct dentry *dentry); -struct dentry *eventfs_end_creating(struct dentry *dentry); void eventfs_d_release(struct dentry *dentry);