tracefs fixes for v7.1:

- Use list_add_tail_rcu() for walking eventfs children
 
   The children link list is protected by SRCU and list walkers can walk the
   list with only using SRCU. Using just list_add_tail() on weakly ordered
   architectures can cause issues. Instead use list_add_tail_rcu().
 
 - Hold eventfs_mutex and SRCU for remount walk events
 
   The trace_apply_options() walks the tracefs_inodes where some are eventfs
   inodes and eventfs_remount() is called which in turn calls
   eventfs_set_attr(). This walk only holds normal RCU read locks, but the
   eventfs_mutex and SRCU should be held. Add a eventfs_remount_(un)lock()
   helpers to take the necessary locks before iterating the list.
 -----BEGIN PGP SIGNATURE-----
 
 iIoEABYKADIWIQRRSw7ePDh/lE+zeZMp5XQQmuv6qgUCaekrdRQccm9zdGVkdEBn
 b29kbWlzLm9yZwAKCRAp5XQQmuv6ql43AP9evY7U3aOAfPV9Zz6UEZe37Px4rDf5
 7R8Udq3BxI4c0AEArooS0KILZsWnGYFfgq2KbJM4Wq4j5xHcj9VBp95WvQM=
 =1RCW
 -----END PGP SIGNATURE-----

Merge tag 'tracefs-v7.1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace

Pull tracefs fixes from Steven Rostedt:

 - Use list_add_tail_rcu() for walking eventfs children

   The linked list of children is protected by SRCU and list walkers can
   walk the list with only using SRCU. Using just list_add_tail() on
   weakly ordered architectures can cause issues. Instead use
   list_add_tail_rcu().

 - Hold eventfs_mutex and SRCU for remount walk events

   The trace_apply_options() walks the tracefs_inodes where some are
   eventfs inodes and eventfs_remount() is called which in turn calls
   eventfs_set_attr(). This walk only holds normal RCU read locks, but
   the eventfs_mutex and SRCU should be held.

   Add a eventfs_remount_(un)lock() helpers to take the necessary locks
   before iterating the list.

* tag 'tracefs-v7.1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace:
  eventfs: Hold eventfs_mutex and SRCU when remount walks events
  eventfs: Use list_add_tail_rcu() for SRCU-protected children list
This commit is contained in:
Linus Torvalds 2026-04-22 15:09:01 -07:00
commit 2e68039281
3 changed files with 22 additions and 2 deletions

View File

@ -244,6 +244,8 @@ static void eventfs_set_attrs(struct eventfs_inode *ei, bool update_uid, kuid_t
{
struct eventfs_inode *ei_child;
lockdep_assert_held(&eventfs_mutex);
/* Update events/<system>/<event> */
if (WARN_ON_ONCE(level > 3))
return;
@ -706,7 +708,7 @@ struct eventfs_inode *eventfs_create_dir(const char *name, struct eventfs_inode
scoped_guard(mutex, &eventfs_mutex) {
if (!parent->is_freed)
list_add_tail(&ei->list, &parent->children);
list_add_tail_rcu(&ei->list, &parent->children);
}
/* Was the parent freed? */
if (list_empty(&ei->list)) {
@ -886,3 +888,15 @@ void eventfs_remove_events_dir(struct eventfs_inode *ei)
d_invalidate(dentry);
d_make_discardable(dentry);
}
int eventfs_remount_lock(void)
{
mutex_lock(&eventfs_mutex);
return srcu_read_lock(&eventfs_srcu);
}
void eventfs_remount_unlock(int srcu_idx)
{
srcu_read_unlock(&eventfs_srcu, srcu_idx);
mutex_unlock(&eventfs_mutex);
}

View File

@ -313,6 +313,7 @@ static int tracefs_apply_options(struct super_block *sb, bool remount)
struct inode *inode = d_inode(sb->s_root);
struct tracefs_inode *ti;
bool update_uid, update_gid;
int srcu_idx;
umode_t tmp_mode;
/*
@ -337,6 +338,7 @@ static int tracefs_apply_options(struct super_block *sb, bool remount)
update_uid = fsi->opts & BIT(Opt_uid);
update_gid = fsi->opts & BIT(Opt_gid);
srcu_idx = eventfs_remount_lock();
rcu_read_lock();
list_for_each_entry_rcu(ti, &tracefs_inodes, list) {
if (update_uid) {
@ -358,6 +360,7 @@ static int tracefs_apply_options(struct super_block *sb, bool remount)
eventfs_remount(ti, update_uid, update_gid);
}
rcu_read_unlock();
eventfs_remount_unlock(srcu_idx);
}
return 0;
@ -403,7 +406,7 @@ static int tracefs_drop_inode(struct inode *inode)
* This inode is being freed and cannot be used for
* eventfs. Clear the flag so that it doesn't call into
* eventfs during the remount flag updates. The eventfs_inode
* gets freed after an RCU cycle, so the content will still
* gets freed after an SRCU cycle, so the content will still
* be safe if the iteration is going on now.
*/
ti->flags &= ~TRACEFS_EVENT_INODE;

View File

@ -76,4 +76,7 @@ struct inode *tracefs_get_inode(struct super_block *sb);
void eventfs_remount(struct tracefs_inode *ti, bool update_uid, bool update_gid);
void eventfs_d_release(struct dentry *dentry);
int eventfs_remount_lock(void);
void eventfs_remount_unlock(int srcu_idx);
#endif /* _TRACEFS_INTERNAL_H */