Re: [sched] c3a340f7e7: invalid_opcode:#[##]

2020-10-20 Thread Florian Fainelli
On 6/30/20 7:49 AM, Peter Zijlstra wrote:
> On Tue, Jun 30, 2020 at 02:46:28PM +0200, Peter Zijlstra wrote:
>> On Mon, Jun 29, 2020 at 08:31:27AM +0800, kernel test robot wrote:
>>> Greeting,
>>>
>>> FYI, we noticed the following commit (built with gcc-4.9):
>>>
>>> commit: c3a340f7e7eadac7662ab104ceb16432e5a4c6b2 ("sched: Have 
>>> sched_class_highest define by vmlinux.lds.h")
>>
>>> [1.840970] kernel BUG at kernel/sched/core.c:6652!
>>
>> W T H
>>
>> $ readelf -Wa defconfig-build/vmlinux | grep sched_class
>> 62931: c1e62d20 0 NOTYPE  GLOBAL DEFAULT2 __begin_sched_classes
>> 65736: c1e62f4096 OBJECT  GLOBAL DEFAULT2 stop_sched_class
>> 71813: c1e62dc096 OBJECT  GLOBAL DEFAULT2 fair_sched_class
>> 78689: c1e62d4096 OBJECT  GLOBAL DEFAULT2 idle_sched_class
>> 78953: c1e62fa0 0 NOTYPE  GLOBAL DEFAULT2 __end_sched_classes
>> 79090: c1e62e4096 OBJECT  GLOBAL DEFAULT2 rt_sched_class
>> 79431: c1e62ec096 OBJECT  GLOBAL DEFAULT2 dl_sched_class
>>
>> $ printf "%d\n" $((0xc1e62dc0 - 0xc1e62d40))
>> 128
>>
>> So even though the object is 96 bytes in size, has an explicit 32 byte
>> alignment, the array ends up with a stride of 128 bytes !?!?!
>>
>> Consistently so with GCC-4.9. Any other GCC I tried does the sane thing.
>>
>> Full patch included below.
>>
>> Anybody any clue wth 4.9 is doing crazy things like this?
>>
>> ---
> 
> This seems to make everything work, it builds and boots for 4.9 and
> builds x86_64-defconfig with clang11 (just to check a !GCC compiler).

Hi Peter,

This patch causes all files under kernel/sched/* that include sched.h to
be rebuilt whenever the value of CONFIG_BLK_DEV_INITRD. There are at
least two build systems (buildroot and OpenWrt) that toggle this
configuration value in order to produce a kernel image without an
initramfs, and one with.

On ARM we get all of these to be needlessly rebuilt:

  CC  kernel/sched/core.o
  CC  kernel/sched/loadavg.o
  CC  kernel/sched/clock.o
  CC  kernel/sched/cputime.o
  CC  kernel/sched/idle.o
  CC  kernel/sched/fair.o
  CC  kernel/sched/rt.o
  CC  kernel/sched/deadline.o
  CC  kernel/sched/wait.o
  CC  kernel/sched/wait_bit.o
  CC  kernel/sched/swait.o
  CC  kernel/sched/completion.o
  CC  kernel/sched/cpupri.o
  CC  kernel/sched/cpudeadline.o
  CC  kernel/sched/topology.o
  CC  kernel/sched/stop_task.o
  CC  kernel/sched/pelt.o
  CC  kernel/sched/debug.o
  CC  kernel/sched/cpufreq.o
  CC  kernel/sched/membarrier.o

Short of moving the STRUCT_ALIGNMENT to a separate header that would not
be subject to any configuration key change, can you think of a good way
to avoid these rebuilds, including for architectures like ARM that ship
their own vmlinux.lds.h? I would not say this is a bug, but it is
definitively an inconvenience.

Thanks!
-- 
Florian


Re: [sched] c3a340f7e7: invalid_opcode:#[##]

2020-06-30 Thread Peter Zijlstra
On Tue, Jun 30, 2020 at 02:46:28PM +0200, Peter Zijlstra wrote:
> On Mon, Jun 29, 2020 at 08:31:27AM +0800, kernel test robot wrote:
> > Greeting,
> > 
> > FYI, we noticed the following commit (built with gcc-4.9):
> > 
> > commit: c3a340f7e7eadac7662ab104ceb16432e5a4c6b2 ("sched: Have 
> > sched_class_highest define by vmlinux.lds.h")
> 
> > [1.840970] kernel BUG at kernel/sched/core.c:6652!
> 
> W T H
> 
> $ readelf -Wa defconfig-build/vmlinux | grep sched_class
> 62931: c1e62d20 0 NOTYPE  GLOBAL DEFAULT2 __begin_sched_classes
> 65736: c1e62f4096 OBJECT  GLOBAL DEFAULT2 stop_sched_class
> 71813: c1e62dc096 OBJECT  GLOBAL DEFAULT2 fair_sched_class
> 78689: c1e62d4096 OBJECT  GLOBAL DEFAULT2 idle_sched_class
> 78953: c1e62fa0 0 NOTYPE  GLOBAL DEFAULT2 __end_sched_classes
> 79090: c1e62e4096 OBJECT  GLOBAL DEFAULT2 rt_sched_class
> 79431: c1e62ec096 OBJECT  GLOBAL DEFAULT2 dl_sched_class
> 
> $ printf "%d\n" $((0xc1e62dc0 - 0xc1e62d40))
> 128
> 
> So even though the object is 96 bytes in size, has an explicit 32 byte
> alignment, the array ends up with a stride of 128 bytes !?!?!
> 
> Consistently so with GCC-4.9. Any other GCC I tried does the sane thing.
> 
> Full patch included below.
> 
> Anybody any clue wth 4.9 is doing crazy things like this?
> 
> ---

This seems to make everything work, it builds and boots for 4.9 and
builds x86_64-defconfig with clang11 (just to check a !GCC compiler).

diff --git a/include/asm-generic/vmlinux.lds.h 
b/include/asm-generic/vmlinux.lds.h
index 66fb84c3dc7ee..49a9aaa1e2424 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -108,6 +108,17 @@
 #define SBSS_MAIN .sbss
 #endif
 
+/*
+ * Align to a 32 byte boundary equal to the
+ * alignment gcc 4.5 uses for a struct
+ */
+#if __GNUC__ == 4 && __GNUC_MINOR__ == 9
+#define STRUCT_ALIGNMENT 64
+#else
+#define STRUCT_ALIGNMENT 32
+#endif
+#define STRUCT_ALIGN() . = ALIGN(STRUCT_ALIGNMENT)
+
 /*
  * The order of the sched class addresses are important, as they are
  * used to determine the order of the priority of each sched class in
@@ -123,13 +134,6 @@
*(__stop_sched_class)   \
__end_sched_classes = .;
 
-/*
- * Align to a 32 byte boundary equal to the
- * alignment gcc 4.5 uses for a struct
- */
-#define STRUCT_ALIGNMENT 32
-#define STRUCT_ALIGN() . = ALIGN(STRUCT_ALIGNMENT)
-
 /* The actual configuration determine if the init/exit sections
  * are handled as text/data or they can be discarded (which
  * often happens at runtime)
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 4165c06d1d7bd..33251d0ab62e7 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -67,6 +67,7 @@
 #include 
 
 #include 
+#include 
 
 #ifdef CONFIG_PARAVIRT
 # include 
@@ -1811,7 +1812,7 @@ struct sched_class {
 #ifdef CONFIG_FAIR_GROUP_SCHED
void (*task_change_group)(struct task_struct *p, int type);
 #endif
-} __aligned(32); /* STRUCT_ALIGN(), vmlinux.lds.h */
+} __aligned(STRUCT_ALIGNMENT); /* STRUCT_ALIGN(), vmlinux.lds.h */
 
 static inline void put_prev_task(struct rq *rq, struct task_struct *prev)
 {


Re: [sched] c3a340f7e7: invalid_opcode:#[##]

2020-06-30 Thread Peter Zijlstra
On Tue, Jun 30, 2020 at 04:02:31PM +0200, Peter Zijlstra wrote:
> On Tue, Jun 30, 2020 at 03:55:05PM +0200, Rasmus Villemoes wrote:
> 
> > > Consistently so with GCC-4.9. Any other GCC I tried does the sane thing.
> > 
> > Does that include gcc 4.8, or is it only "anything newer than 4.9"?
> 
> It includes 4.8 :-)
> 
> > so the section it was put in has an alignment of 64. The generated
> > assembly is indeed
> > 
> > .globl  fair_sched_class
> > .section__fair_sched_class,"a",@progbits
> > .align 64
> > 
> > /me goes brew coffee
> 
> Right.. so I now have the below patch, and with that I get:
> 
> 62931: c1e62c20 0 NOTYPE  GLOBAL DEFAULT2 __begin_sched_classes
> 65736: c1e62e40   128 OBJECT  GLOBAL DEFAULT2 stop_sched_class
> 71813: c1e62cc0   128 OBJECT  GLOBAL DEFAULT2 fair_sched_class
> 78689: c1e62c40   128 OBJECT  GLOBAL DEFAULT2 idle_sched_class
> 78953: c1e62ec0 0 NOTYPE  GLOBAL DEFAULT2 __end_sched_classes
> 79090: c1e62d40   128 OBJECT  GLOBAL DEFAULT2 rt_sched_class
> 79431: c1e62dc0   128 OBJECT  GLOBAL DEFAULT2 dl_sched_class
> 
> 
> Which has me stumped on __begin_sched_classes being on a 32byte edge
> (and crashes differently due to that).

OK, when I look at defconfig-build/arch/x86/kernel/vmlinux.lds I get:

. = ALIGN(32); *(__dummy_sched_class) __begin_sched_classes = .;

So I'm thinking the GCC_VERSION thing works for sched.h but not for
arch//x86/kernel/vmlinux.lds.S, lovely. Let me try and figure out why.


Re: [sched] c3a340f7e7: invalid_opcode:#[##]

2020-06-30 Thread Peter Zijlstra
On Tue, Jun 30, 2020 at 04:02:31PM +0200, Peter Zijlstra wrote:
> On Tue, Jun 30, 2020 at 03:55:05PM +0200, Rasmus Villemoes wrote:
> 
> > > Consistently so with GCC-4.9. Any other GCC I tried does the sane thing.
> > 
> > Does that include gcc 4.8, or is it only "anything newer than 4.9"?
> 
> It includes 4.8 :-)
> 
> > so the section it was put in has an alignment of 64. The generated
> > assembly is indeed
> > 
> > .globl  fair_sched_class
> > .section__fair_sched_class,"a",@progbits
> > .align 64
> > 
> > /me goes brew coffee
> 
> Right.. so I now have the below patch, and with that I get:
> 
> 62931: c1e62c20 0 NOTYPE  GLOBAL DEFAULT2 __begin_sched_classes
> 65736: c1e62e40   128 OBJECT  GLOBAL DEFAULT2 stop_sched_class
> 71813: c1e62cc0   128 OBJECT  GLOBAL DEFAULT2 fair_sched_class
> 78689: c1e62c40   128 OBJECT  GLOBAL DEFAULT2 idle_sched_class
> 78953: c1e62ec0 0 NOTYPE  GLOBAL DEFAULT2 __end_sched_classes
> 79090: c1e62d40   128 OBJECT  GLOBAL DEFAULT2 rt_sched_class
> 79431: c1e62dc0   128 OBJECT  GLOBAL DEFAULT2 dl_sched_class
> 
> 
> Which has me stumped on __begin_sched_classes being on a 32byte edge
> (and crashes differently due to that).
> 
> Argh!!

Steve suggested adding a dummy variable before the lot and this actually
works... But this just cannot be right :-(


---
diff --git a/include/asm-generic/vmlinux.lds.h 
b/include/asm-generic/vmlinux.lds.h
index 66fb84c3dc7ee..9c0ee5cf73a50 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -108,6 +108,17 @@
 #define SBSS_MAIN .sbss
 #endif
 
+/*
+ * Align to a 32 byte boundary equal to the
+ * alignment gcc 4.5 uses for a struct
+ */
+#if GCC_VERSION >= 40900 && GCC_VERSION < 5
+#define STRUCT_ALIGNMENT 64
+#else
+#define STRUCT_ALIGNMENT 32
+#endif
+#define STRUCT_ALIGN() . = ALIGN(STRUCT_ALIGNMENT)
+
 /*
  * The order of the sched class addresses are important, as they are
  * used to determine the order of the priority of each sched class in
@@ -115,6 +126,7 @@
  */
 #define SCHED_DATA \
STRUCT_ALIGN(); \
+   *(__dummy_sched_class)  \
__begin_sched_classes = .;  \
*(__idle_sched_class)   \
*(__fair_sched_class)   \
@@ -123,13 +135,6 @@
*(__stop_sched_class)   \
__end_sched_classes = .;
 
-/*
- * Align to a 32 byte boundary equal to the
- * alignment gcc 4.5 uses for a struct
- */
-#define STRUCT_ALIGNMENT 32
-#define STRUCT_ALIGN() . = ALIGN(STRUCT_ALIGNMENT)
-
 /* The actual configuration determine if the init/exit sections
  * are handled as text/data or they can be discarded (which
  * often happens at runtime)
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 81640fe0eae8f..f8535a3438819 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -6641,6 +6641,9 @@ static struct kmem_cache *task_group_cache __read_mostly;
 DECLARE_PER_CPU(cpumask_var_t, load_balance_mask);
 DECLARE_PER_CPU(cpumask_var_t, select_idle_mask);
 
+const struct sched_class dummy_sched_class
+   __attribute__((section("__dummy_sched_class")));
+
 void __init sched_init(void)
 {
unsigned long ptr = 0;
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 4165c06d1d7bd..33251d0ab62e7 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -67,6 +67,7 @@
 #include 
 
 #include 
+#include 
 
 #ifdef CONFIG_PARAVIRT
 # include 
@@ -1811,7 +1812,7 @@ struct sched_class {
 #ifdef CONFIG_FAIR_GROUP_SCHED
void (*task_change_group)(struct task_struct *p, int type);
 #endif
-} __aligned(32); /* STRUCT_ALIGN(), vmlinux.lds.h */
+} __aligned(STRUCT_ALIGNMENT); /* STRUCT_ALIGN(), vmlinux.lds.h */
 
 static inline void put_prev_task(struct rq *rq, struct task_struct *prev)
 {


Re: [sched] c3a340f7e7: invalid_opcode:#[##]

2020-06-30 Thread Peter Zijlstra
On Tue, Jun 30, 2020 at 03:55:05PM +0200, Rasmus Villemoes wrote:

> > Consistently so with GCC-4.9. Any other GCC I tried does the sane thing.
> 
> Does that include gcc 4.8, or is it only "anything newer than 4.9"?

It includes 4.8 :-)

> so the section it was put in has an alignment of 64. The generated
> assembly is indeed
> 
> .globl  fair_sched_class
> .section__fair_sched_class,"a",@progbits
> .align 64
> 
> /me goes brew coffee

Right.. so I now have the below patch, and with that I get:

62931: c1e62c20 0 NOTYPE  GLOBAL DEFAULT2 __begin_sched_classes
65736: c1e62e40   128 OBJECT  GLOBAL DEFAULT2 stop_sched_class
71813: c1e62cc0   128 OBJECT  GLOBAL DEFAULT2 fair_sched_class
78689: c1e62c40   128 OBJECT  GLOBAL DEFAULT2 idle_sched_class
78953: c1e62ec0 0 NOTYPE  GLOBAL DEFAULT2 __end_sched_classes
79090: c1e62d40   128 OBJECT  GLOBAL DEFAULT2 rt_sched_class
79431: c1e62dc0   128 OBJECT  GLOBAL DEFAULT2 dl_sched_class


Which has me stumped on __begin_sched_classes being on a 32byte edge
(and crashes differently due to that).

Argh!!



diff --git a/include/asm-generic/vmlinux.lds.h 
b/include/asm-generic/vmlinux.lds.h
index 66fb84c3dc7ee..b4704fb12b2dd 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -108,6 +108,17 @@
 #define SBSS_MAIN .sbss
 #endif
 
+/*
+ * Align to a 32 byte boundary equal to the
+ * alignment gcc 4.5 uses for a struct
+ */
+#if GCC_VERSION >= 40900 && GCC_VERSION < 5
+#define STRUCT_ALIGNMENT 64
+#else
+#define STRUCT_ALIGNMENT 32
+#endif
+#define STRUCT_ALIGN() . = ALIGN(STRUCT_ALIGNMENT)
+
 /*
  * The order of the sched class addresses are important, as they are
  * used to determine the order of the priority of each sched class in
@@ -123,13 +134,6 @@
*(__stop_sched_class)   \
__end_sched_classes = .;
 
-/*
- * Align to a 32 byte boundary equal to the
- * alignment gcc 4.5 uses for a struct
- */
-#define STRUCT_ALIGNMENT 32
-#define STRUCT_ALIGN() . = ALIGN(STRUCT_ALIGNMENT)
-
 /* The actual configuration determine if the init/exit sections
  * are handled as text/data or they can be discarded (which
  * often happens at runtime)
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 4165c06d1d7bd..33251d0ab62e7 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -67,6 +67,7 @@
 #include 
 
 #include 
+#include 
 
 #ifdef CONFIG_PARAVIRT
 # include 
@@ -1811,7 +1812,7 @@ struct sched_class {
 #ifdef CONFIG_FAIR_GROUP_SCHED
void (*task_change_group)(struct task_struct *p, int type);
 #endif
-} __aligned(32); /* STRUCT_ALIGN(), vmlinux.lds.h */
+} __aligned(STRUCT_ALIGNMENT); /* STRUCT_ALIGN(), vmlinux.lds.h */
 
 static inline void put_prev_task(struct rq *rq, struct task_struct *prev)
 {


Re: [sched] c3a340f7e7: invalid_opcode:#[##]

2020-06-30 Thread Rasmus Villemoes
On 30/06/2020 14.46, Peter Zijlstra wrote:
> On Mon, Jun 29, 2020 at 08:31:27AM +0800, kernel test robot wrote:
>> Greeting,
>>
>> FYI, we noticed the following commit (built with gcc-4.9):
>>
>> commit: c3a340f7e7eadac7662ab104ceb16432e5a4c6b2 ("sched: Have 
>> sched_class_highest define by vmlinux.lds.h")
> 
>> [1.840970] kernel BUG at kernel/sched/core.c:6652!
> 
> W T H
> 
> $ readelf -Wa defconfig-build/vmlinux | grep sched_class
> 62931: c1e62d20 0 NOTYPE  GLOBAL DEFAULT2 __begin_sched_classes
> 65736: c1e62f4096 OBJECT  GLOBAL DEFAULT2 stop_sched_class
> 71813: c1e62dc096 OBJECT  GLOBAL DEFAULT2 fair_sched_class
> 78689: c1e62d4096 OBJECT  GLOBAL DEFAULT2 idle_sched_class
> 78953: c1e62fa0 0 NOTYPE  GLOBAL DEFAULT2 __end_sched_classes
> 79090: c1e62e4096 OBJECT  GLOBAL DEFAULT2 rt_sched_class
> 79431: c1e62ec096 OBJECT  GLOBAL DEFAULT2 dl_sched_class
> 
> $ printf "%d\n" $((0xc1e62dc0 - 0xc1e62d40))
> 128
> 
> So even though the object is 96 bytes in size, has an explicit 32 byte
> alignment, the array ends up with a stride of 128 bytes !?!?!
> 
> Consistently so with GCC-4.9. Any other GCC I tried does the sane thing.

Does that include gcc 4.8, or is it only "anything newer than 4.9"?

>
> Full patch included below.
> 
> Anybody any clue wth 4.9 is doing crazy things like this?

Perhaps
https://gcc.gnu.org/onlinedocs/gcc-4.9.4/gcc/Variable-Attributes.html#Variable-Attributes:

  When used on a struct, or struct member, the aligned attribute can
only increase the alignment; in order to decrease it, the packed
attribute must be specified as well. When used as part of a typedef, the
aligned attribute can both increase and decrease alignment, and
specifying the packed attribute generates a warning.

is part of the explanation. But this is seriously weird. I don't know
which .config you or the buildbot used, but I took an i386_defconfig
with SMP=n to get a small enough struct sched_class (and disable
retpoline stuff), added

diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 81640fe0eae8..53c0d3ba62ba 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -71,6 +71,13 @@ unsigned int sysctl_sched_rt_period = 100;

 __read_mostly int scheduler_running;

+void foo(void)
+{
+   extern void bar(int);
+   bar(sizeof(struct sched_class));
+   bar(_Alignof(struct sched_class));
+}
+
 /*
  * part of the period that we allow rt tasks to run in us.
  * default: 0.95s

and apparently _Alignof is only 16:

 2c90 :
2c90:   55  push   %ebp
2c91:   b8 60 00 00 00  mov$0x60,%eax
2c96:   89 e5   mov%esp,%ebp
2c98:   e8 fc ff ff ff  call   2c99 
2c99: R_386_PC32bar
2c9d:   b8 10 00 00 00  mov$0x10,%eax
2ca2:   e8 fc ff ff ff  call   2ca3 
2ca3: R_386_PC32bar

Neverthess, readelf -S --wide kernel/sched/fair.o:

Section Headers:
  [Nr] Name  TypeAddr OffSize   ES Flg
Lk Inf Al

  [35] __fair_sched_class PROGBITS 002980 60 00   A
0   0 64

so the section it was put in has an alignment of 64. The generated
assembly is indeed

.globl  fair_sched_class
.section__fair_sched_class,"a",@progbits
.align 64

/me goes brew coffee


Re: [sched] c3a340f7e7: invalid_opcode:#[##]

2020-06-30 Thread Peter Zijlstra
On Mon, Jun 29, 2020 at 08:31:27AM +0800, kernel test robot wrote:
> Greeting,
> 
> FYI, we noticed the following commit (built with gcc-4.9):
> 
> commit: c3a340f7e7eadac7662ab104ceb16432e5a4c6b2 ("sched: Have 
> sched_class_highest define by vmlinux.lds.h")

> [1.840970] kernel BUG at kernel/sched/core.c:6652!

W T H

$ readelf -Wa defconfig-build/vmlinux | grep sched_class
62931: c1e62d20 0 NOTYPE  GLOBAL DEFAULT2 __begin_sched_classes
65736: c1e62f4096 OBJECT  GLOBAL DEFAULT2 stop_sched_class
71813: c1e62dc096 OBJECT  GLOBAL DEFAULT2 fair_sched_class
78689: c1e62d4096 OBJECT  GLOBAL DEFAULT2 idle_sched_class
78953: c1e62fa0 0 NOTYPE  GLOBAL DEFAULT2 __end_sched_classes
79090: c1e62e4096 OBJECT  GLOBAL DEFAULT2 rt_sched_class
79431: c1e62ec096 OBJECT  GLOBAL DEFAULT2 dl_sched_class

$ printf "%d\n" $((0xc1e62dc0 - 0xc1e62d40))
128

So even though the object is 96 bytes in size, has an explicit 32 byte
alignment, the array ends up with a stride of 128 bytes !?!?!

Consistently so with GCC-4.9. Any other GCC I tried does the sane thing.

Full patch included below.

Anybody any clue wth 4.9 is doing crazy things like this?

---
commit c3a340f7e7eadac7662ab104ceb16432e5a4c6b2
Author: Steven Rostedt (VMware) 
Date:   Thu Dec 19 16:44:53 2019 -0500

sched: Have sched_class_highest define by vmlinux.lds.h

Now that the sched_class descriptors are defined by the linker script, and
this needs to be aware of the existance of stop_sched_class when SMP is
enabled or not, as it is used as the "highest" priority when defined. Move
the declaration of sched_class_highest to the same location in the linker
script that inserts stop_sched_class, and this will also make it easier to
see what should be defined as the highest class, as this linker script
location defines the priorities as well.

Signed-off-by: Steven Rostedt (VMware) 
Signed-off-by: Peter Zijlstra (Intel) 
Link: https://lkml.kernel.org/r/20191219214558.682913...@goodmis.org

diff --git a/include/asm-generic/vmlinux.lds.h 
b/include/asm-generic/vmlinux.lds.h
index 2186d7b01af6..66fb84c3dc7e 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -114,11 +114,14 @@
  * relation to each other.
  */
 #define SCHED_DATA \
+   STRUCT_ALIGN(); \
+   __begin_sched_classes = .;  \
*(__idle_sched_class)   \
*(__fair_sched_class)   \
*(__rt_sched_class) \
*(__dl_sched_class) \
-   *(__stop_sched_class)
+   *(__stop_sched_class)   \
+   __end_sched_classes = .;
 
 /*
  * Align to a 32 byte boundary equal to the
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 0208b71bef80..81640fe0eae8 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -6646,6 +6646,14 @@ void __init sched_init(void)
unsigned long ptr = 0;
int i;
 
+   /* Make sure the linker didn't screw up */
+   BUG_ON(_sched_class + 1 != _sched_class ||
+  _sched_class + 1 != _sched_class ||
+  _sched_class + 1   != _sched_class);
+#ifdef CONFIG_SMP
+   BUG_ON(_sched_class + 1 != _sched_class);
+#endif
+
wait_bit_init();
 
 #ifdef CONFIG_FAIR_GROUP_SCHED
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 336887607b3d..4165c06d1d7b 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -1811,7 +1811,7 @@ struct sched_class {
 #ifdef CONFIG_FAIR_GROUP_SCHED
void (*task_change_group)(struct task_struct *p, int type);
 #endif
-};
+} __aligned(32); /* STRUCT_ALIGN(), vmlinux.lds.h */
 
 static inline void put_prev_task(struct rq *rq, struct task_struct *prev)
 {
@@ -1825,17 +1825,18 @@ static inline void set_next_task(struct rq *rq, struct 
task_struct *next)
next->sched_class->set_next_task(rq, next, false);
 }
 
-#ifdef CONFIG_SMP
-#define sched_class_highest (_sched_class)
-#else
-#define sched_class_highest (_sched_class)
-#endif
+/* Defined in include/asm-generic/vmlinux.lds.h */
+extern struct sched_class __begin_sched_classes[];
+extern struct sched_class __end_sched_classes[];
+
+#define sched_class_highest (__end_sched_classes - 1)
+#define sched_class_lowest  (__begin_sched_classes - 1)
 
 #define for_class_range(class, _from, _to) \
-   for (class = (_from); class != (_to); class = class->next)
+   for (class = (_from); class != (_to); class--)
 
 #define for_each_class(class) \
-   for_class_range(class, sched_class_highest, NULL)
+   for_class_range(class, sched_class_highest, sched_class_lowest)
 
 extern const struct sched_class stop_sched_class;
 extern const struct sched_class dl_sched_class;