jump_label_inc may return before the code is patched
PATCH 1/1 jump_label_inc may return before the code is patched
If cpu A calls jump_label_inc() just after atomic_add_return() is called by cpu B, atomic_inc_not_zero() will return value greater then zero and jump_label_inc() will return to a caller before jump_label_update() finishes its job on cpu B.
kernel/jump_label.c +2 -1
@@ -66,8 +66,9 @@ void jump_label_inc(struct jump_label_key *key)return ;jump_label_lock (); -if (atomic_add_return (1 , &key->enabled) ==1 ) +if (atomic_read (&key->enabled) ==0 )jump_label_update (key,JUMP_LABEL_ENABLE ); +atomic_inc (&key->enabled);jump_label_unlock (); }
--
Gleb.
Quoted 11 lines · Gleb Natapov
If cpu A calls
jump_label_inc()just afteratomic_add_return()is called by cpu B,atomic_inc_not_zero()will return value greater then zero andjump_label_inc()will return to a caller beforejump_label_update()finishes its job on cpu B.Signed-off-by Gleb Natapov <[email protected]>kernel/jump_label.c +0
-0
kernel/jump_label.c void jump_label_inc(struct jump_label_key *key) · line 74
Quoted 10 lines
kernel/jump_label.c +2
-1@@ -66,8 +66,9 @@ void jump_label_inc(struct jump_label_key *key)return ;jump_label_lock (); -if (atomic_add_return (1 , &key->enabled) ==1 ) +if (atomic_read (&key->enabled) ==0 )jump_label_update (key,JUMP_LABEL_ENABLE ); +atomic_inc (&key->enabled);jump_label_unlock (); }
agreed, we shouldn't return before the update happens...did this cause any actual problem in practice? Or just observed from code inspection?
Thanks,
-Jason
Quoted 14 lines · Jason Baron
Quoted 13 lines · Gleb Natapov
If cpu A calls
jump_label_inc()just afteratomic_add_return()is called by cpu B,atomic_inc_not_zero()will return value greater then zero andjump_label_inc()will return to a caller beforejump_label_update()finishes its job on cpu B.Signed-off-by Gleb Natapov <[email protected]>kernel/jump_label.c +0
-0@@ -66,8 +66,9 @@ void jump_label_inc(struct jump_label_key *key)return ;
Quoted 12 lines
kernel/jump_label.c void jump_label_inc(struct jump_label_key *key) · line 74
Quoted 8 lines
kernel/jump_label.c +2
-1jump_label_lock (); -if (atomic_add_return (1 , &key->enabled) ==1 ) +if (atomic_read (&key->enabled) ==0 )jump_label_update (key,JUMP_LABEL_ENABLE ); +atomic_inc (&key->enabled);jump_label_unlock (); }agreed, we shouldn't return before the update happens...did this cause any actual problem in practice? Or just observed from code inspection?
It did. I am debugging strange oopses in perf code that happen when I create and destroy hw events on multiple cpus in parallel. At some point I started to suspect that jump labels are not working properly and printks confirmed that sometimes static_branch() is not taken when ->enabled is not zero. I compiled kernel without jump label support and, as far as my testing goes, oopses disappeared. Then I found the bug by looking at the code. Strangely enough this patch alone didn't fix oopses yet, so some other problems are probably lurking somewhere. I am going on vocation till next week. Will debug furtherer upon return.
Quoted 5 lines
Acked-by Jason Baron <[email protected]>Thanks,
-Jason
--
Gleb.
Quoted 4 lines · Gleb Natapov
If cpu A calls
jump_label_inc()just afteratomic_add_return()is called by cpu B,atomic_inc_not_zero()will return value greater then zero andjump_label_inc()will return to a caller beforejump_label_update()finishes its job on cpu B.
OK, I see what you are saying. There's a race here that jump_label_inc may return before jump labels are actually activated. I have no issue with this change. This guarantees that jump labels will be active on return of jump_label_inc().
I'm assuming that jump_label_update() does memory barries, as it does modify code, and would be itself a synchronization point.
-- Steve
Quoted 19 lines
Signed-off-by Gleb Natapov <[email protected]>kernel/jump_label.c +2
-2@@ -66,8 +66,9 @@ void jump_label_inc(struct jump_label_key *key)return ;jump_label_lock (); -if (atomic_add_return (1 , &key->enabled) ==1 ) +if (atomic_read (&key->enabled) ==0 )jump_label_update (key,JUMP_LABEL_ENABLE ); +atomic_inc (&key->enabled);jump_label_unlock (); } --Gleb.
Quoted 11 lines · Steven Rostedt
Quoted 4 lines · Gleb Natapov
If cpu A calls
jump_label_inc()just afteratomic_add_return()is called by cpu B,atomic_inc_not_zero()will return value greater then zero andjump_label_inc()will return to a caller beforejump_label_update()finishes its job on cpu B.OK, I see what you are saying. There's a race here that
jump_label_incmay return before jump labels are actually activated. I have no issue with this change. This guarantees that jump labels will be active on return ofjump_label_inc().
Quoted 5 lines
I'm assuming that
jump_label_update()does memory barries, as it does modify code, and would be itself a synchronization point.Acked-by Steven Rostedt <[email protected]>
So through what tree this should go to Linus' git?
Quoted 19 lines
-- Steve
Quoted 17 lines
Signed-off-by Gleb Natapov <[email protected]>kernel/jump_label.c +2
-1@@ -66,8 +66,9 @@ void jump_label_inc(struct jump_label_key *key)return ;jump_label_lock (); -if (atomic_add_return (1 , &key->enabled) ==1 ) +if (atomic_read (&key->enabled) ==0 )jump_label_update (key,JUMP_LABEL_ENABLE ); +atomic_inc (&key->enabled);jump_label_unlock (); }
Quoted 3 lines
Quoted 2 lines
--
Gleb.
--
Gleb.
Steven Rostedt
reviewerQuoted 12 lines · Gleb Natapov
Quoted 11 lines · Steven Rostedt
Quoted 4 lines · Gleb Natapov
If cpu A calls
jump_label_inc()just afteratomic_add_return()is called by cpu B,atomic_inc_not_zero()will return value greater then zero andjump_label_inc()will return to a caller beforejump_label_update()finishes its job on cpu B.OK, I see what you are saying. There's a race here that
jump_label_incmay return before jump labels are actually activated. I have no issue with this change. This guarantees that jump labels will be active on return ofjump_label_inc().
Quoted 6 lines
Quoted 5 lines
I'm assuming that
jump_label_update()does memory barries, as it does modify code, and would be itself a synchronization point.Acked-by Steven Rostedt <[email protected]>So through what tree this should go to Linus' git?
I'll pull it in. I'm currently scrambling around getting back up to speed after a 11 day conference spree.
-- Steve
[tip:perf/core] jump_label: jump_label_inc may return before the code is patched
In reply to Gleb NatapovCommit-ID: c8452afb7426f7e21388492f40227582e3e83879 Gitweb: http://git.kernel.org/tip/c8452afb7426f7e21388492f40227582e3e83879 Author: Gleb Natapov <[email protected]> AuthorDate: Tue, 18 Oct 2011 19:55:51 +0200 Committer: Steven Rostedt <[email protected]> CommitDate: Mon, 7 Nov 2011 11:02:34 -0500
jump_label: jump_label_inc may return before the code is patched
If cpu A calls jump_label_inc() just after atomic_add_return() is called by cpu B, atomic_inc_not_zero() will return value greater then zero and jump_label_inc() will return to a caller before jump_label_update() finishes its job on cpu B.
--- kernel/jump_label.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-)
kernel/jump_label.c +2 -1
@@ -66,8 +66,9 @@ void jump_label_inc(struct jump_label_key *key)return ;jump_label_lock (); -if (atomic_add_return (1 , &key->enabled) ==1 ) +if (atomic_read (&key->enabled) ==0 )jump_label_update (key,JUMP_LABEL_ENABLE ); +atomic_inc (&key->enabled);jump_label_unlock (); }
[tip:perf/core] jump_label: jump_label_inc may return before the code is patched
In reply to Gleb NatapovCommit-ID: bbbf7af4bf8fc69bc751818cf30521080fa47dcb Gitweb: http://git.kernel.org/tip/bbbf7af4bf8fc69bc751818cf30521080fa47dcb Author: Gleb Natapov <[email protected]> AuthorDate: Tue, 18 Oct 2011 19:55:51 +0200 Committer: Steven Rostedt <[email protected]> CommitDate: Mon, 5 Dec 2011 13:28:46 -0500
jump_label: jump_label_inc may return before the code is patched
If cpu A calls jump_label_inc() just after atomic_add_return() is called by cpu B, atomic_inc_not_zero() will return value greater then zero and jump_label_inc() will return to a caller before jump_label_update() finishes its job on cpu B.
--- kernel/jump_label.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-)
kernel/jump_label.c +2 -1
@@ -66,8 +66,9 @@ void jump_label_inc(struct jump_label_key *key)return ;jump_label_lock (); -if (atomic_add_return (1 , &key->enabled) ==1 ) +if (atomic_read (&key->enabled) ==0 )jump_label_update (key,JUMP_LABEL_ENABLE ); +atomic_inc (&key->enabled);jump_label_unlock (); }