Re: [sched] c3a340f7e7: invalid_opcode:#[##]
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:#[##]
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:#[##]
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:#[##]
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:#[##]
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:#[##]
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:#[##]
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;