Commit 3e0fea09 authored by Linus Torvalds's avatar Linus Torvalds Committed by Steven Rostedt (Google)

tracing/user_events: Split up mm alloc and attach

When a new mm is being created in a fork() path it currently is
allocated and then attached in one go. This leaves the mm exposed out to
the tracing register callbacks while any parent enabler locations are
copied in. This should not happen.

Split up mm alloc and attach as unique operations. When duplicating
enablers, first alloc, then duplicate, and only upon success, attach.
This prevents any timing window outside of the event_reg mutex for
enablement walking. This allows for dropping RCU requirement for
enablement walking in later patches.

Link: https://lkml.kernel.org/r/20230519230741.669-2-beaub@linux.microsoft.com
Link: https://lore.kernel.org/linux-trace-kernel/CAHk-=whTBvXJuoi_kACo3qi5WZUmRrhyA-_=rRFsycTytmB6qw@mail.gmail.com/Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
[ change log written by Beau Belgrave ]
Signed-off-by: default avatarBeau Belgrave <beaub@linux.microsoft.com>
Signed-off-by: default avatarSteven Rostedt (Google) <rostedt@goodmis.org>
parent 632478a0
...@@ -539,10 +539,9 @@ static struct user_event_mm *user_event_mm_get_all(struct user_event *user) ...@@ -539,10 +539,9 @@ static struct user_event_mm *user_event_mm_get_all(struct user_event *user)
return found; return found;
} }
static struct user_event_mm *user_event_mm_create(struct task_struct *t) static struct user_event_mm *user_event_mm_alloc(struct task_struct *t)
{ {
struct user_event_mm *user_mm; struct user_event_mm *user_mm;
unsigned long flags;
user_mm = kzalloc(sizeof(*user_mm), GFP_KERNEL_ACCOUNT); user_mm = kzalloc(sizeof(*user_mm), GFP_KERNEL_ACCOUNT);
...@@ -554,12 +553,6 @@ static struct user_event_mm *user_event_mm_create(struct task_struct *t) ...@@ -554,12 +553,6 @@ static struct user_event_mm *user_event_mm_create(struct task_struct *t)
refcount_set(&user_mm->refcnt, 1); refcount_set(&user_mm->refcnt, 1);
refcount_set(&user_mm->tasks, 1); refcount_set(&user_mm->tasks, 1);
spin_lock_irqsave(&user_event_mms_lock, flags);
list_add_rcu(&user_mm->link, &user_event_mms);
spin_unlock_irqrestore(&user_event_mms_lock, flags);
t->user_event_mm = user_mm;
/* /*
* The lifetime of the memory descriptor can slightly outlast * The lifetime of the memory descriptor can slightly outlast
* the task lifetime if a ref to the user_event_mm is taken * the task lifetime if a ref to the user_event_mm is taken
...@@ -573,6 +566,17 @@ static struct user_event_mm *user_event_mm_create(struct task_struct *t) ...@@ -573,6 +566,17 @@ static struct user_event_mm *user_event_mm_create(struct task_struct *t)
return user_mm; return user_mm;
} }
static void user_event_mm_attach(struct user_event_mm *user_mm, struct task_struct *t)
{
unsigned long flags;
spin_lock_irqsave(&user_event_mms_lock, flags);
list_add_rcu(&user_mm->link, &user_event_mms);
spin_unlock_irqrestore(&user_event_mms_lock, flags);
t->user_event_mm = user_mm;
}
static struct user_event_mm *current_user_event_mm(void) static struct user_event_mm *current_user_event_mm(void)
{ {
struct user_event_mm *user_mm = current->user_event_mm; struct user_event_mm *user_mm = current->user_event_mm;
...@@ -580,10 +584,12 @@ static struct user_event_mm *current_user_event_mm(void) ...@@ -580,10 +584,12 @@ static struct user_event_mm *current_user_event_mm(void)
if (user_mm) if (user_mm)
goto inc; goto inc;
user_mm = user_event_mm_create(current); user_mm = user_event_mm_alloc(current);
if (!user_mm) if (!user_mm)
goto error; goto error;
user_event_mm_attach(user_mm, current);
inc: inc:
refcount_inc(&user_mm->refcnt); refcount_inc(&user_mm->refcnt);
error: error:
...@@ -671,7 +677,7 @@ void user_event_mm_remove(struct task_struct *t) ...@@ -671,7 +677,7 @@ void user_event_mm_remove(struct task_struct *t)
void user_event_mm_dup(struct task_struct *t, struct user_event_mm *old_mm) void user_event_mm_dup(struct task_struct *t, struct user_event_mm *old_mm)
{ {
struct user_event_mm *mm = user_event_mm_create(t); struct user_event_mm *mm = user_event_mm_alloc(t);
struct user_event_enabler *enabler; struct user_event_enabler *enabler;
if (!mm) if (!mm)
...@@ -685,10 +691,11 @@ void user_event_mm_dup(struct task_struct *t, struct user_event_mm *old_mm) ...@@ -685,10 +691,11 @@ void user_event_mm_dup(struct task_struct *t, struct user_event_mm *old_mm)
rcu_read_unlock(); rcu_read_unlock();
user_event_mm_attach(mm, t);
return; return;
error: error:
rcu_read_unlock(); rcu_read_unlock();
user_event_mm_remove(t); user_event_mm_destroy(mm);
} }
static bool current_user_event_enabler_exists(unsigned long uaddr, static bool current_user_event_enabler_exists(unsigned long uaddr,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment