Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+22 -2
+15 -1
fs/tracefs/event_inode.c
··· 244 244 { 245 245 struct eventfs_inode *ei_child; 246 246 247 + lockdep_assert_held(&eventfs_mutex); 248 + 247 249 /* Update events/<system>/<event> */ 248 250 if (WARN_ON_ONCE(level > 3)) 249 251 return; ··· 708 706 709 707 scoped_guard(mutex, &eventfs_mutex) { 710 708 if (!parent->is_freed) 711 - list_add_tail(&ei->list, &parent->children); 709 + list_add_tail_rcu(&ei->list, &parent->children); 712 710 } 713 711 /* Was the parent freed? */ 714 712 if (list_empty(&ei->list)) { ··· 887 885 */ 888 886 d_invalidate(dentry); 889 887 d_make_discardable(dentry); 888 + } 889 + 890 + int eventfs_remount_lock(void) 891 + { 892 + mutex_lock(&eventfs_mutex); 893 + return srcu_read_lock(&eventfs_srcu); 894 + } 895 + 896 + void eventfs_remount_unlock(int srcu_idx) 897 + { 898 + srcu_read_unlock(&eventfs_srcu, srcu_idx); 899 + mutex_unlock(&eventfs_mutex); 890 900 }
+4 -1
fs/tracefs/inode.c
··· 313 313 struct inode *inode = d_inode(sb->s_root); 314 314 struct tracefs_inode *ti; 315 315 bool update_uid, update_gid; 316 + int srcu_idx; 316 317 umode_t tmp_mode; 317 318 318 319 /* ··· 338 337 update_uid = fsi->opts & BIT(Opt_uid); 339 338 update_gid = fsi->opts & BIT(Opt_gid); 340 339 340 + srcu_idx = eventfs_remount_lock(); 341 341 rcu_read_lock(); 342 342 list_for_each_entry_rcu(ti, &tracefs_inodes, list) { 343 343 if (update_uid) { ··· 360 358 eventfs_remount(ti, update_uid, update_gid); 361 359 } 362 360 rcu_read_unlock(); 361 + eventfs_remount_unlock(srcu_idx); 363 362 } 364 363 365 364 return 0; ··· 406 403 * This inode is being freed and cannot be used for 407 404 * eventfs. Clear the flag so that it doesn't call into 408 405 * eventfs during the remount flag updates. The eventfs_inode 409 - * gets freed after an RCU cycle, so the content will still 406 + * gets freed after an SRCU cycle, so the content will still 410 407 * be safe if the iteration is going on now. 411 408 */ 412 409 ti->flags &= ~TRACEFS_EVENT_INODE;
+3
fs/tracefs/internal.h
··· 76 76 void eventfs_remount(struct tracefs_inode *ti, bool update_uid, bool update_gid); 77 77 void eventfs_d_release(struct dentry *dentry); 78 78 79 + int eventfs_remount_lock(void); 80 + void eventfs_remount_unlock(int srcu_idx); 81 + 79 82 #endif /* _TRACEFS_INTERNAL_H */