Commit 2e680392 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
parents 66a7974a 07004a8c
Loading
Loading
Loading
Loading
+15 −1
Original line number Diff line number Diff line
@@ -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);
}
+4 −1
Original line number Diff line number Diff line
@@ -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;
+3 −0
Original line number Diff line number Diff line
@@ -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 */