From: Jason Baron <jasonbaron0@gmail.com>
To: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>,
Andy Lutomirski <luto@amacapital.net>,
Thomas Gleixner <tglx@linutronix.de>,
Mikulas Patocka <mpatocka@redhat.com>,
Paul Mackerras <paulus@samba.org>,
Arnaldo Carvalho de Melo <acme@kernel.org>,
Kees Cook <keescook@chromium.org>,
Andrea Arcangeli <aarcange@redhat.com>,
Vince Weaver <vince@deater.net>,
"hillf.zj" <hillf.zj@alibaba-inc.com>,
Valdis Kletnieks <Valdis.Kletnieks@vt.edu>,
"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
Steven Rostedt <rostedt@goodmis.org>
Subject: Re: Kernel broken on processors without performance counters
Date: Thu, 23 Jul 2015 10:19:52 -0400 [thread overview]
Message-ID: <55B0F808.2060302@gmail.com> (raw)
In-Reply-To: <20150723104215.GH25159@twins.programming.kicks-ass.net>
On 07/23/2015 06:42 AM, Peter Zijlstra wrote:
> On Wed, Jul 22, 2015 at 01:06:44PM -0400, Jason Baron wrote:
>> Ok,
>>
>> So we could add all 4 possible initial states, where the
>> branches would be:
>>
>> static_likely_init_true_branch(struct static_likely_init_true_key *key)
>> static_likely_init_false_branch(struct static_likely_init_false_key *key)
>> static_unlikely_init_false_branch(struct static_unlikely_init_false_key *key)
>> static_unlikely_init_true_branch(struct static_unlikely_init_true_key *key)
> I'm sorely tempted to go quote cypress hill here...
>
>
> And I realize part of the problem is that we're wanting to use jump
> labels before we can patch them. But surely we can do better.
>
> extern bool ____wrong_branch_error(void);
>
> struct static_key_true;
> struct static_key_false;
>
> #define static_branch_likely(x) \
> ({ \
> bool branch; \
> if (__builtin_types_compatible_p(typeof(x), struct static_key_true)) \
> branch = !arch_static_branch(&(x)->key); \
> else if (__builtin_types_compatible_p(typeof(x), struct static_key_false)) \
> branch = !arch_static_branch_jump(&(x)->key); \
> else \
> branch = ____wrong_branch_error(); \
> branch; \
> })
>
> #define static_branch_unlikely(x) \
> ({ \
> bool branch; \
> if (__builtin_types_compatible_p(typeof(x), struct static_key_true)) \
> branch = arch_static_branch(&(x)->key); \
> else if (__builtin_types_compatible_p(typeof(x), struct static_key_false)) \
> branch = arch_static_branch_jump(&(x)->key); \
> else \
> branch = ____wrong_branch_error(); \
> branch; \
> })
>
> Can't we make something like that work?
>
> So the immediate problem appears to be the 4 different key inits, which don't
> seem very supportive of this separation:
>
> +#define STATIC_KEY_LIKEY_INIT_TRUE ((struct static_unlikely_init_true_key) \
> + { .key.enabled = ATOMIC_INIT(1), \
> + .key.entries = (void *)JUMP_LABEL_TYPE_TRUE_BRANCH })
>
> +#define STATIC_KEY_LIKEY_INIT_FALSE ((struct static_unlikely_init_false_key) \
> + { .key.enabled = ATOMIC_INIT(0), \
> + .key.entries = (void *)JUMP_LABEL_TYPE_TRUE_BRANCH })
>
> +#define STATIC_KEY_UNLIKELY_INIT_TRUE ((struct static_unlikely_init_true_key) \
> + { .key.enabled = ATOMIC_INIT(1), \
> + .key.entries = (void *)JUMP_LABEL_TYPE_FALSE_BRANCH })
>
> +#define STATIC_KEY_UNLIKELY_INIT_FALSE ((struct static_unlikely_init_false_key) \
> + { .key.enabled = ATOMIC_INIT(0), \
> + .key.entries = (void *)JUMP_LABEL_TYPE_FALSE_BRANCH })
>
>
> But I think we can fix that by using a second __jump_table section, then
> we can augment the LABEL_TYPE_{TRUE,FALSE} thing with the section we
> find the jump_entry in.
>
> Then we can do:
>
> #define STATIC_KEY_TRUE_INIT (struct static_key_true) { .key = STATIC_KEY_INIT_TRUE, }
> #define STATIC_KEY_FALSE_INIT (struct static_key_false){ .key = STATIC_KEY_INIT_FALSE, }
>
> And invert the jump_label_type if we're in the second section.
>
> I think we'll need a second argument to the arch_static_branch*()
> functions to indicate which section it needs to go in.
>
>
> static __always_inline bool arch_static_branch(struct static_key *key, bool inv)
> {
> if (!inv) {
> asm_volatile_goto("1:"
> ".byte " __stringify(STATIC_KEY_INIT_NOP) "\n\t"
> ".pushsection __jump_table, \"aw\" \n\t"
> _ASM_ALIGN "\n\t"
> _ASM_PTR "1b, %l[l_yes], %c0 \n\t"
> ".popsection \n\t"
> : : "i" (key) : : l_yes);
> } else {
> asm_volatile_goto("1:"
> ".byte " __stringify(STATIC_KEY_INIT_NOP) "\n\t"
> ".pushsection __jump_table_inv, \"aw\" \n\t"
> _ASM_ALIGN "\n\t"
> _ASM_PTR "1b, %l[l_yes], %c0 \n\t"
> ".popsection \n\t"
> : : "i" (key) : : l_yes);
> }
> return false;
> l_yes:
> return true;
> }
>
> static __always_inline bool arch_static_branch_jump(struct static_key *key, bool inv)
> {
> if (!inv) {
> asm_volatile_goto("1:"
> "jmp %l[l_yes]\n\t"
> ".pushsection __jump_table, \"aw\" \n\t"
> _ASM_ALIGN "\n\t"
> _ASM_PTR "1b, %l[l_yes], %c0 \n\t"
> ".popsection \n\t"
> : : "i" (key) : : l_yes);
> } else {
> asm_volatile_goto("1:"
> "jmp %l[l_yes]\n\t"
> ".pushsection __jump_table_inv, \"aw\" \n\t"
> _ASM_ALIGN "\n\t"
> _ASM_PTR "1b, %l[l_yes], %c0 \n\t"
> ".popsection \n\t"
> : : "i" (key) : : l_yes);
> }
> return false;
> l_yes:
> return true;
> }
>
>
> And change the branch macros thusly:
>
>
> #define static_branch_likely(x) \
> ({ \
> bool branch; \
> if (__builtin_types_compatible_p(typeof(x), struct static_key_true)) \
> branch = !arch_static_branch(&(x)->key, false); \
> else if (__builtin_types_compatible_p(typeof(x), struct static_key_false)) \
> branch = !arch_static_branch_jump(&(x)->key, true); \
> else \
> branch = ____wrong_branch_error(); \
> branch; \
> })
>
> #define static_branch_unlikely(x) \
> ({ \
> bool branch; \
> if (__builtin_types_compatible_p(typeof(x), struct static_key_true)) \
> branch = arch_static_branch(&(x)->key, true); \
> else if (__builtin_types_compatible_p(typeof(x), struct static_key_false)) \
> branch = arch_static_branch_jump(&(x)->key, false); \
> else \
> branch = ____wrong_branch_error(); \
> branch; \
> })
>
In 'static_branch_unlikely()', I think arch_static_branch() and
arch_static_branch_jump() are reversed. Another way to do the 'inv'
thing is to simply have the likely() branches all be in one table and
the unlikely() in the other. Then, for example for a given _inc()
operation we would no-op all the likely() branches and jmp all the
unlikely().
> And I think it'll all work. Hmm?
Cool. This also gives an extra degree of freedom in that it allows keys to
be arbitrarily mixed with the likely/unlikely branch types. I'm not sure that's
come up as a use-case, but seems like it would be good. It also implies
that the LABEL_TYPE_{TRUE,FALSE}, is no longer associated with the key
b/c a key could be used in both and unlikely() or likely() branch. So that
would eventually go away, and the 'struct static_key()', I guess could point
to its relevant entries in both tables. Although, that means an extra
pointer in the 'struct static_key'. It may be simpler to simply add another
field to the jump table that specifies if the branch is likely/unlikely,
and then we are back to one table? IE arch_static_branch() could add
that field to the jump table.
Thanks,
-Jason
next prev parent reply other threads:[~2015-07-23 14:20 UTC|newest]
Thread overview: 54+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-07-08 15:17 Kernel broken on processors without performance counters Mikulas Patocka
2015-07-08 16:07 ` Peter Zijlstra
2015-07-08 16:54 ` Mikulas Patocka
2015-07-09 17:23 ` [PATCH] x86: Fix static_key in load_mm_cr4() Peter Zijlstra
2015-07-09 19:11 ` Mikulas Patocka
2015-07-10 8:27 ` [tip:perf/urgent] x86, perf: Fix static_key bug " tip-bot for Peter Zijlstra
2015-07-08 17:37 ` Kernel broken on processors without performance counters Andy Lutomirski
2015-07-08 20:04 ` Jason Baron
2015-07-09 0:36 ` Andy Lutomirski
2015-07-10 14:13 ` Peter Zijlstra
2015-07-10 15:29 ` Jason Baron
2015-07-21 8:21 ` Peter Zijlstra
2015-07-21 15:43 ` Thomas Gleixner
2015-07-21 15:49 ` Peter Zijlstra
2015-07-21 15:51 ` Andy Lutomirski
2015-07-21 16:12 ` Peter Zijlstra
2015-07-21 16:57 ` Jason Baron
2015-07-23 14:54 ` Steven Rostedt
2015-07-21 18:15 ` Borislav Petkov
2015-07-21 18:50 ` Jason Baron
2015-07-21 18:54 ` Andy Lutomirski
2015-07-21 19:00 ` Valdis.Kletnieks
2015-07-21 19:29 ` Andy Lutomirski
2015-07-21 23:49 ` Valdis.Kletnieks
2015-07-22 4:24 ` Borislav Petkov
2015-07-22 17:06 ` Jason Baron
2015-07-23 10:42 ` Peter Zijlstra
2015-07-23 10:53 ` Borislav Petkov
2015-07-23 14:19 ` Jason Baron [this message]
2015-07-23 14:33 ` Peter Zijlstra
2015-07-23 14:49 ` Peter Zijlstra
2015-07-23 19:14 ` Jason Baron
2015-07-24 10:56 ` Peter Zijlstra
2015-07-24 12:36 ` Peter Zijlstra
2015-07-24 14:15 ` Jason Baron
2015-07-23 14:58 ` Peter Zijlstra
2015-07-23 15:34 ` Steven Rostedt
2015-07-23 17:08 ` Peter Zijlstra
2015-07-23 17:18 ` Steven Rostedt
2015-07-23 17:33 ` Jason Baron
2015-07-23 18:12 ` Steven Rostedt
2015-07-23 19:02 ` Peter Zijlstra
2015-07-23 17:35 ` Andy Lutomirski
2015-07-23 17:54 ` Borislav Petkov
2015-07-23 19:02 ` Peter Zijlstra
2015-07-24 5:29 ` Borislav Petkov
2015-07-24 10:36 ` Peter Zijlstra
2015-07-22 20:43 ` Mikulas Patocka
2015-07-21 15:53 ` Thomas Gleixner
2015-07-21 15:54 ` Peter Zijlstra
2015-07-09 17:11 ` Peter Zijlstra
2015-07-09 19:15 ` Jason Baron
2015-07-14 9:35 ` Borislav Petkov
2015-07-14 12:43 ` Mikulas Patocka
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=55B0F808.2060302@gmail.com \
--to=jasonbaron0@gmail.com \
--cc=Valdis.Kletnieks@vt.edu \
--cc=aarcange@redhat.com \
--cc=acme@kernel.org \
--cc=bp@alien8.de \
--cc=hillf.zj@alibaba-inc.com \
--cc=keescook@chromium.org \
--cc=linux-kernel@vger.kernel.org \
--cc=luto@amacapital.net \
--cc=mpatocka@redhat.com \
--cc=paulus@samba.org \
--cc=peterz@infradead.org \
--cc=rostedt@goodmis.org \
--cc=tglx@linutronix.de \
--cc=vince@deater.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).