zswap: only use CPU notifier when HOTPLUG_CPU=y
Subsystems (3)
PATCH v2 1/1 zswap: only use CPU notifier when HOTPLUG_CPU=y
__unregister_cpu_notifier() only removes registered notifier from its linked list when CPU hotplug is configured. If we free registered CPU notifier when HOTPLUG_CPU=n, we corrupt the linked list.
To fix the problem, we can either use a static CPU notifier that walks through each pool or just simply disable CPU notifier when CPU hotplug is not configured (which is perfectly safe because the code in question is called after all possible CPUs are online and will remain online until power off).
v2: #ifdef for cpu_notifier_register_done during cleanup.
--- mm/zswap.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
mm/zswap.c +14 -0
@@ -118,7 +118,9 @@ struct zswap_pool {struct kref kref;struct list_head list;struct work_struct work; +#ifdef CONFIG_HOTPLUG_CPU struct notifier_block notifier; +#endif char tfm_name[CRYPTO_MAX_ALG_NAME ]; };
@@ -448,6 +450,7 @@ static int __zswap_cpu_comp_notifier(struct zswap_pool *pool,return NOTIFY_OK ; } +#ifdef CONFIG_HOTPLUG_CPU static int zswap_cpu_comp_notifier (struct notifier_block *nb,unsigned long action,void *pcpu) {
@@ -456,27 +459,34 @@ static int zswap_cpu_comp_notifier(struct notifier_block *nb, return __zswap_cpu_comp_notifier(pool, action, cpu); } +#endif static int zswap_cpu_comp_init (struct zswap_pool *pool) {unsigned long cpu; +#ifdef CONFIG_HOTPLUG_CPU memset (&pool->notifier,0 ,sizeof (pool->notifier)); pool->notifier.notifier_call = zswap_cpu_comp_notifier;cpu_notifier_register_begin (); +#endif for_each_online_cpu (cpu)if (__zswap_cpu_comp_notifier (pool,CPU_UP_PREPARE , cpu) ==NOTIFY_BAD ) goto cleanup; +#ifdef CONFIG_HOTPLUG_CPU __register_cpu_notifier (&pool->notifier);cpu_notifier_register_done (); +#endif return 0 ; cleanup:for_each_online_cpu (cpu)__zswap_cpu_comp_notifier (pool,CPU_UP_CANCELED , cpu); +#ifdef CONFIG_HOTPLUG_CPU cpu_notifier_register_done (); +#endif return -ENOMEM ; }
@@ -484,11 +494,15 @@ static void zswap_cpu_comp_destroy(struct zswap_pool *pool) {unsigned long cpu; +#ifdef CONFIG_HOTPLUG_CPU cpu_notifier_register_begin (); +#endif for_each_online_cpu (cpu)__zswap_cpu_comp_notifier (pool,CPU_UP_CANCELED , cpu); +#ifdef CONFIG_HOTPLUG_CPU __unregister_cpu_notifier (&pool->notifier);cpu_notifier_register_done (); +#endif }/*********************************
Signature · 7 lines
2.8.0.rc3.226.g39d4020 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 11 lines · Yu Zhao
__unregister_cpu_notifier()only removes registered notifier from its linked list when CPU hotplug is configured. If we free registered CPU notifier when HOTPLUG_CPU=n, we corrupt the linked list.To fix the problem, we can either use a static CPU notifier that walks through each pool or just simply disable CPU notifier when CPU hotplug is not configured (which is perfectly safe because the code in question is called after all possible CPUs are online and will remain online until power off).
v2: #ifdef for
cpu_notifier_register_doneduring cleanup.
this ifedfery is just ugly as hell. I am also wondering whether it is really needed. __register_cpu_notifier and __unregister_cpu_notifier are noops for CONFIG_HOTPLUG_CPU=n. So what's exactly that is broken here?
Quoted 86 lines
Signe-off-by Yu Zhao <[email protected]>--- mm/zswap.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)mm/zswap.c +14
-0@@ -118,7 +118,9 @@ struct zswap_pool {struct kref kref;struct list_head list;struct work_struct work; +#ifdef CONFIG_HOTPLUG_CPU struct notifier_block notifier; +#endif char tfm_name[CRYPTO_MAX_ALG_NAME ]; };@@ -448,6 +450,7 @@ static int __zswap_cpu_comp_notifier(struct zswap_pool *pool,return NOTIFY_OK ; } +#ifdef CONFIG_HOTPLUG_CPU static int zswap_cpu_comp_notifier (struct notifier_block *nb,unsigned long action,void *pcpu) {@@ -456,27 +459,34 @@ static int zswap_cpu_comp_notifier(struct notifier_block *nb, return __zswap_cpu_comp_notifier(pool, action, cpu); } +#endif static int zswap_cpu_comp_init (struct zswap_pool *pool) {unsigned long cpu; +#ifdef CONFIG_HOTPLUG_CPU memset (&pool->notifier,0 ,sizeof (pool->notifier)); pool->notifier.notifier_call = zswap_cpu_comp_notifier;cpu_notifier_register_begin (); +#endif for_each_online_cpu (cpu)if (__zswap_cpu_comp_notifier (pool,CPU_UP_PREPARE , cpu) ==NOTIFY_BAD ) goto cleanup; +#ifdef CONFIG_HOTPLUG_CPU __register_cpu_notifier (&pool->notifier);cpu_notifier_register_done (); +#endif return 0 ; cleanup:for_each_online_cpu (cpu)__zswap_cpu_comp_notifier (pool,CPU_UP_CANCELED , cpu); +#ifdef CONFIG_HOTPLUG_CPU cpu_notifier_register_done (); +#endif return -ENOMEM ; }@@ -484,11 +494,15 @@ static void zswap_cpu_comp_destroy(struct zswap_pool *pool) {unsigned long cpu; +#ifdef CONFIG_HOTPLUG_CPU cpu_notifier_register_begin (); +#endif for_each_online_cpu (cpu)__zswap_cpu_comp_notifier (pool,CPU_UP_CANCELED , cpu); +#ifdef CONFIG_HOTPLUG_CPU __unregister_cpu_notifier (&pool->notifier);cpu_notifier_register_done (); +#endif }/********************************* Signature · 7 lines
2.8.0.rc3.226.g39d4020 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Signature · 8 lines
Michal Hocko SUSE Labs -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 11 lines · Michal Hocko
Quoted 10 lines · Yu Zhao
__unregister_cpu_notifier()only removes registered notifier from its linked list when CPU hotplug is configured. If we free registered CPU notifier when HOTPLUG_CPU=n, we corrupt the linked list.To fix the problem, we can either use a static CPU notifier that walks through each pool or just simply disable CPU notifier when CPU hotplug is not configured (which is perfectly safe because the code in question is called after all possible CPUs are online and will remain online until power off).
Quoted 5 lines
Quoted 1 line
v2: #ifdef for
cpu_notifier_register_doneduring cleanup.this ifedfery is just ugly as hell. I am also wondering whether it is really needed.
__register_cpu_notifierand__unregister_cpu_notifierare noops forCONFIG_HOTPLUG_CPU=n. So what's exactly that is broken here?
hmm, that's interesting, __unregister_cpu_notifier is always a noop if HOTPLUG_CPU=n, but __register_cpu_notifier is only a noop if HOTPLUG_CPU=n *and* MODULE. If !MODULE, __register_cpu_notifier does actually register! This was added by commit 47e627bc8c9a70392d2049e6af5bd55fae61fe53 ('hotplug: Allow modules to use the cpu hotplug notifiers even if !CONFIG_HOTPLUG_CPU') and looks like it's to allow built-ins to register so they can notice during boot when cpus are initialized.
IMHO, that is the real problem - sure, without HOTPLUG_CPU, nobody should ever get a notification that a cpu is dying, but that doesn't mean builtins that register notifiers will never unregister their notifiers and then free them.
Changing zswap is only working around the symptom; instead, hotplug should be changed to provide unregister_cpu_notifier in all cases where register_cpu_notifier is provided.
Quoted 82 lines
Quoted 82 lines
Signe-off-by Yu Zhao <[email protected]>--- mm/zswap.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)mm/zswap.c +14
-1@@ -118,7 +118,9 @@ struct zswap_pool {struct kref kref;struct list_head list;struct work_struct work; +#ifdef CONFIG_HOTPLUG_CPU struct notifier_block notifier; +#endif char tfm_name[CRYPTO_MAX_ALG_NAME ]; };@@ -448,6 +450,7 @@ static int __zswap_cpu_comp_notifier(struct zswap_pool *pool,return NOTIFY_OK ; } +#ifdef CONFIG_HOTPLUG_CPU static int zswap_cpu_comp_notifier (struct notifier_block *nb,unsigned long action,void *pcpu) {@@ -456,27 +459,34 @@ static int zswap_cpu_comp_notifier(struct notifier_block *nb, return __zswap_cpu_comp_notifier(pool, action, cpu); } +#endif static int zswap_cpu_comp_init (struct zswap_pool *pool) {unsigned long cpu; +#ifdef CONFIG_HOTPLUG_CPU memset (&pool->notifier,0 ,sizeof (pool->notifier)); pool->notifier.notifier_call = zswap_cpu_comp_notifier;cpu_notifier_register_begin (); +#endif for_each_online_cpu (cpu)if (__zswap_cpu_comp_notifier (pool,CPU_UP_PREPARE , cpu) ==NOTIFY_BAD ) goto cleanup; +#ifdef CONFIG_HOTPLUG_CPU __register_cpu_notifier (&pool->notifier);cpu_notifier_register_done (); +#endif return 0 ; cleanup:for_each_online_cpu (cpu)__zswap_cpu_comp_notifier (pool,CPU_UP_CANCELED , cpu); +#ifdef CONFIG_HOTPLUG_CPU cpu_notifier_register_done (); +#endif return -ENOMEM ; }@@ -484,11 +494,15 @@ static void zswap_cpu_comp_destroy(struct zswap_pool *pool) {unsigned long cpu; +#ifdef CONFIG_HOTPLUG_CPU cpu_notifier_register_begin (); +#endif for_each_online_cpu (cpu)__zswap_cpu_comp_notifier (pool,CPU_UP_CANCELED , cpu); +#ifdef CONFIG_HOTPLUG_CPU __unregister_cpu_notifier (&pool->notifier);cpu_notifier_register_done (); +#endif }/********************************* -- 2.8.0.rc3.226.g39d4020
Quoted 9 lines
Quoted 5 lines
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>--
Michal Hocko
SUSE Labs
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 14 lines · Dan Streetman
Quoted 13 lines · Michal Hocko
Quoted 11 lines · Yu Zhao
__unregister_cpu_notifier()only removes registered notifier from its linked list when CPU hotplug is configured. If we free registered CPU notifier when HOTPLUG_CPU=n, we corrupt the linked list.To fix the problem, we can either use a static CPU notifier that walks through each pool or just simply disable CPU notifier when CPU hotplug is not configured (which is perfectly safe because the code in question is called after all possible CPUs are online and will remain online until power off).
v2: #ifdef for
cpu_notifier_register_doneduring cleanup.
Quoted 7 lines
Quoted 3 lines
this ifedfery is just ugly as hell. I am also wondering whether it is really needed.
__register_cpu_notifierand__unregister_cpu_notifierare noops forCONFIG_HOTPLUG_CPU=n. So what's exactly that is broken here?hmm, that's interesting,
__unregister_cpu_notifieris always a noop if HOTPLUG_CPU=n, but__register_cpu_notifieris only a noop if HOTPLUG_CPU=n *and* MODULE. If !MODULE,__register_cpu_notifierdoes
OK, I've missed the MODULE part
Quoted 5 lines
actually register! This was added by commit
47e627bc8c9a70392d2049e6af5bd55fae61fe53('hotplug: Allow modules to use the cpu hotplug notifiers even if !CONFIG_HOTPLUG_CPU') and looks like it's to allow built-ins to register so they can notice during boot when cpus are initialized.
I cannot say I wound understand the motivation but that is not really all that important.
Quoted 4 lines
IMHO, that is the real problem - sure, without
HOTPLUG_CPU, nobody should ever get a notification that a cpu is dying, but that doesn't mean builtins that register notifiers will never unregister their notifiers and then free them.
Yes that is true. That suggests that __unregister_cpu_notifier should the the symmetric thing to the __register_cpu_notifier for CONFIG_MODULE, right?
Quoted 3 lines
Changing zswap is only working around the symptom; instead, hotplug should be changed to provide
unregister_cpu_notifierin all cases whereregister_cpu_notifieris provided.
Agreed.
Quoted 90 lines
Quoted 90 lines
Quoted 81 lines
Signe-off-by Yu Zhao <[email protected]>--- mm/zswap.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)mm/zswap.c +14
-1@@ -118,7 +118,9 @@ struct zswap_pool {struct kref kref;struct list_head list;struct work_struct work; +#ifdef CONFIG_HOTPLUG_CPU struct notifier_block notifier; +#endif char tfm_name[CRYPTO_MAX_ALG_NAME ]; };@@ -448,6 +450,7 @@ static int __zswap_cpu_comp_notifier(struct zswap_pool *pool,return NOTIFY_OK ; } +#ifdef CONFIG_HOTPLUG_CPU static int zswap_cpu_comp_notifier (struct notifier_block *nb,unsigned long action,void *pcpu) {@@ -456,27 +459,34 @@ static int zswap_cpu_comp_notifier(struct notifier_block *nb, return __zswap_cpu_comp_notifier(pool, action, cpu); } +#endif static int zswap_cpu_comp_init (struct zswap_pool *pool) {unsigned long cpu; +#ifdef CONFIG_HOTPLUG_CPU memset (&pool->notifier,0 ,sizeof (pool->notifier)); pool->notifier.notifier_call = zswap_cpu_comp_notifier;cpu_notifier_register_begin (); +#endif for_each_online_cpu (cpu)if (__zswap_cpu_comp_notifier (pool,CPU_UP_PREPARE , cpu) ==NOTIFY_BAD ) goto cleanup; +#ifdef CONFIG_HOTPLUG_CPU __register_cpu_notifier (&pool->notifier);cpu_notifier_register_done (); +#endif return 0 ; cleanup:for_each_online_cpu (cpu)__zswap_cpu_comp_notifier (pool,CPU_UP_CANCELED , cpu); +#ifdef CONFIG_HOTPLUG_CPU cpu_notifier_register_done (); +#endif return -ENOMEM ; }@@ -484,11 +494,15 @@ static void zswap_cpu_comp_destroy(struct zswap_pool *pool) {unsigned long cpu; +#ifdef CONFIG_HOTPLUG_CPU cpu_notifier_register_begin (); +#endif for_each_online_cpu (cpu)__zswap_cpu_comp_notifier (pool,CPU_UP_CANCELED , cpu); +#ifdef CONFIG_HOTPLUG_CPU __unregister_cpu_notifier (&pool->notifier);cpu_notifier_register_done (); +#endif }/********************************* -- 2.8.0.rc3.226.g39d4020
Quoted 5 lines
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>--
Michal Hocko
SUSE Labs
Signature · 8 lines
Michal Hocko SUSE Labs -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 34 lines · Michal Hocko
Quoted 14 lines · Dan Streetman
Quoted 13 lines · Michal Hocko
Quoted 11 lines · Yu Zhao
__unregister_cpu_notifier()only removes registered notifier from its linked list when CPU hotplug is configured. If we free registered CPU notifier when HOTPLUG_CPU=n, we corrupt the linked list.To fix the problem, we can either use a static CPU notifier that walks through each pool or just simply disable CPU notifier when CPU hotplug is not configured (which is perfectly safe because the code in question is called after all possible CPUs are online and will remain online until power off).
v2: #ifdef for
cpu_notifier_register_doneduring cleanup.Quoted 7 lines
Quoted 3 lines
this ifedfery is just ugly as hell. I am also wondering whether it is really needed.
__register_cpu_notifierand__unregister_cpu_notifierare noops forCONFIG_HOTPLUG_CPU=n. So what's exactly that is broken here?hmm, that's interesting,
__unregister_cpu_notifieris always a noop if HOTPLUG_CPU=n, but__register_cpu_notifieris only a noop if HOTPLUG_CPU=n *and* MODULE. If !MODULE,__register_cpu_notifierdoesOK, I've missed the MODULE part
Quoted 5 lines
actually register! This was added by commit
47e627bc8c9a70392d2049e6af5bd55fae61fe53('hotplug: Allow modules to use the cpu hotplug notifiers even if !CONFIG_HOTPLUG_CPU') and looks like it's to allow built-ins to register so they can notice during boot when cpus are initialized.I cannot say I wound understand the motivation but that is not really all that important.
Quoted 8 lines
Quoted 4 lines
IMHO, that is the real problem - sure, without
HOTPLUG_CPU, nobody should ever get a notification that a cpu is dying, but that doesn't mean builtins that register notifiers will never unregister their notifiers and then free them.Yes that is true. That suggests that
__unregister_cpu_notifiershould the the symmetric thing to the__register_cpu_notifierforCONFIG_MODULE, right?
I meant the following. Completely untested
---
include/linux/cpu.h +1 -0
@@ -120,6 +120,7 @@ extern void __unregister_cpu_notifier(struct notifier_block *nb);#ifndef MODULE extern int register_cpu_notifier (struct notifier_block *nb);extern int __register_cpu_notifier (struct notifier_block *nb); +extern void __unregister_cpu_notifier (struct notifier_block *nb);#else static inline int register_cpu_notifier (struct notifier_block *nb) {
Signature · 8 lines
Michal Hocko SUSE Labs -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 40 lines · Michal Hocko
Quoted 39 lines · Michal Hocko
Quoted 14 lines · Dan Streetman
Quoted 13 lines · Michal Hocko
Quoted 11 lines · Yu Zhao
__unregister_cpu_notifier()only removes registered notifier from its linked list when CPU hotplug is configured. If we free registered CPU notifier when HOTPLUG_CPU=n, we corrupt the linked list.To fix the problem, we can either use a static CPU notifier that walks through each pool or just simply disable CPU notifier when CPU hotplug is not configured (which is perfectly safe because the code in question is called after all possible CPUs are online and will remain online until power off).
v2: #ifdef for
cpu_notifier_register_doneduring cleanup.Quoted 7 lines
Quoted 3 lines
this ifedfery is just ugly as hell. I am also wondering whether it is really needed.
__register_cpu_notifierand__unregister_cpu_notifierare noops forCONFIG_HOTPLUG_CPU=n. So what's exactly that is broken here?hmm, that's interesting,
__unregister_cpu_notifieris always a noop if HOTPLUG_CPU=n, but__register_cpu_notifieris only a noop if HOTPLUG_CPU=n *and* MODULE. If !MODULE,__register_cpu_notifierdoesOK, I've missed the MODULE part
Quoted 5 lines
actually register! This was added by commit
47e627bc8c9a70392d2049e6af5bd55fae61fe53('hotplug: Allow modules to use the cpu hotplug notifiers even if !CONFIG_HOTPLUG_CPU') and looks like it's to allow built-ins to register so they can notice during boot when cpus are initialized.I cannot say I wound understand the motivation but that is not really all that important.
Quoted 4 lines
IMHO, that is the real problem - sure, without
HOTPLUG_CPU, nobody should ever get a notification that a cpu is dying, but that doesn't mean builtins that register notifiers will never unregister their notifiers and then free them.
Quoted 5 lines
Quoted 3 lines
Yes that is true. That suggests that
__unregister_cpu_notifiershould the the symmetric thing to the__register_cpu_notifierforCONFIG_MODULE, right?I meant the following. Completely untested
agreed, but also needs the non-__ version, and kernel/cpu.c needs tweaking to move those functions out of the #ifdef CONFIG_HOTPLUG_CPU section.
Quoted 14 lines
---
include/linux/cpu.h +1
-1@@ -120,6 +120,7 @@ extern void __unregister_cpu_notifier(struct notifier_block *nb);#ifndef MODULE extern int register_cpu_notifier (struct notifier_block *nb);extern int __register_cpu_notifier (struct notifier_block *nb); +extern void __unregister_cpu_notifier (struct notifier_block *nb);#else static inline int register_cpu_notifier (struct notifier_block *nb) { --
Quoted 2 lines
Michal Hocko
SUSE Labs
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 1/1 hotplug: make register and unregister notifier API symmetric
[Let's CC more people - the thread started
http://lkml.kernel.org/r/[email protected]]
Quoted 45 lines · Dan Streetman
Quoted 44 lines · Michal Hocko
Quoted 42 lines · Michal Hocko
Quoted 14 lines · Dan Streetman
Quoted 13 lines · Michal Hocko
Quoted 11 lines · Yu Zhao
__unregister_cpu_notifier()only removes registered notifier from its linked list when CPU hotplug is configured. If we free registered CPU notifier when HOTPLUG_CPU=n, we corrupt the linked list.To fix the problem, we can either use a static CPU notifier that walks through each pool or just simply disable CPU notifier when CPU hotplug is not configured (which is perfectly safe because the code in question is called after all possible CPUs are online and will remain online until power off).
v2: #ifdef for
cpu_notifier_register_doneduring cleanup.Quoted 7 lines
Quoted 3 lines
this ifedfery is just ugly as hell. I am also wondering whether it is really needed.
__register_cpu_notifierand__unregister_cpu_notifierare noops forCONFIG_HOTPLUG_CPU=n. So what's exactly that is broken here?hmm, that's interesting,
__unregister_cpu_notifieris always a noop if HOTPLUG_CPU=n, but__register_cpu_notifieris only a noop if HOTPLUG_CPU=n *and* MODULE. If !MODULE,__register_cpu_notifierdoesOK, I've missed the MODULE part
Quoted 5 lines
actually register! This was added by commit
47e627bc8c9a70392d2049e6af5bd55fae61fe53('hotplug: Allow modules to use the cpu hotplug notifiers even if !CONFIG_HOTPLUG_CPU') and looks like it's to allow built-ins to register so they can notice during boot when cpus are initialized.I cannot say I wound understand the motivation but that is not really all that important.
Quoted 4 lines
IMHO, that is the real problem - sure, without
HOTPLUG_CPU, nobody should ever get a notification that a cpu is dying, but that doesn't mean builtins that register notifiers will never unregister their notifiers and then free them.Yes that is true. That suggests that
__unregister_cpu_notifiershould the the symmetric thing to the__register_cpu_notifierforCONFIG_MODULE, right?
Quoted 5 lines
Quoted 1 line
I meant the following. Completely untested
agreed, but also needs the non-__ version, and
kernel/cpu.cneeds tweaking to move those functions out of the #ifdefCONFIG_HOTPLUG_CPUsection.
OK, this is still only compile tested. Yu Zhao, assuming you were able to trigger the original problem could you test with the below patch please?
---
kbuild test robot
build botRe: [PATCH] hotplug: make register and unregister notifier API symmetric
url: https://github.com/0day-ci/linux/commits/Michal-Hocko/hotplug-make-register-and-unregister-notifier-API-symmetric/20161203-114815 config: i386-randconfig-r0-201648 (attached as .config)…
Hi Michal,
[auto build test ERROR on linus/master]
[also build test ERROR on v4.9-rc7 next-20161202]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Michal-Hocko/hotplug-make-register-and-unregister-notifier-API-symmetric/20161203-114815
config: i386-randconfig-r0-201648 (attached as .config)
compiler: gcc-5 (Debian 5.4.1-2) 5.4.1 20160904 reproduce:
# save the attached .config to linux build tree
make ARCH=i386 All errors (new ones prefixed by >>):
arch/x86/oprofile/built-in.o: In function `nmi_timer_shutdown':
>> nmi_timer_int.c:(.text+0x238b): undefined reference to `__unregister_cpu_notifier'
arch/x86/oprofile/built-in.o: In function `nmi_shutdown':
nmi_int.c:(.text+0x2793): undefined reference to `__unregister_cpu_notifier'
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
Re: [PATCH] hotplug: make register and unregister notifier API symmetric
Quoted 13 lines · kbuild test robot
Hi Michal,
[auto build test ERROR on linus/master]
[also build test ERROR on v4.9-rc7 next-20161202]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]url: https://github.com/0day-ci/linux/commits/Michal-Hocko/hotplug-make-register-and-unregister-notifier-API-symmetric/20161203-114815
config: i386-randconfig-r0-201648 (attached as .config)
compiler: gcc-5 (Debian 5.4.1-2) 5.4.1 20160904 reproduce:# save the attached .config to linux build tree make ARCH=i386
Quoted 6 lines
All errors (new ones prefixed by >>):
arch/x86/oprofile/built-in.o: In function `nmi_timer_shutdown':Quoted 1 line
Quoted 1 line
nmi_timer_int.c:(.text+0x238b): undefined reference to `__unregister_cpu_notifier'
arch/x86/oprofile/built-in.o: In function `nmi_shutdown':nmi_int.c:(.text+0x2793): undefined reference to `__unregister_cpu_notifier'
Ohh, right. I have missed that unregister functions definitions are guarded as well. This patch should hopefully be correct finally. Please note it also exports register/unregister callbacks when CONFIG_HOTPLUG_CPU is not defined which is not really needed strictly speaking because those are only used when !MODULE but I would rather not make the code more complicated. If maintainers prefer I can guard exports separately of course.
---
kbuild test robot
build botRe: [PATCH] hotplug: make register and unregister notifier API symmetric
In reply to Michal Hockourl: https://github.com/0day-ci/linux/commits/Michal-Hocko/hotplug-make-register-and-unregister-notifier-API-symmetric/20161203-114815 config: i386-randconfig-s1-201648 (attached as .config)…
Hi Michal,
[auto build test ERROR on linus/master]
[also build test ERROR on v4.9-rc7 next-20161202]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Michal-Hocko/hotplug-make-register-and-unregister-notifier-API-symmetric/20161203-114815
config: i386-randconfig-s1-201648 (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901 reproduce:
# save the attached .config to linux build tree
make ARCH=i386 All errors (new ones prefixed by >>):
mm/built-in.o: In function `zs_unregister_cpu_notifier':
>> zsmalloc.c:(.text.unlikely+0xc7e): undefined reference to `__unregister_cpu_notifier'
arch/x86/oprofile/built-in.o: In function `nmi_timer_shutdown':
nmi_timer_int.c:(.text+0x1c7d): undefined reference to __unregister_cpu_notifier' arch/x86/oprofile/built-in.o: In function nmi_shutdown':
nmi_int.c:(.text+0x2319): undefined reference to `__unregister_cpu_notifier'
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
Re: [PATCH] hotplug: make register and unregister notifier API symmetric
In reply to Michal HockoQuoted 51 lines · Michal Hocko
[Let's CC more people - the thread started
http://lkml.kernel.org/r/[email protected]]Quoted 47 lines · Dan Streetman
Quoted 45 lines · Michal Hocko
Quoted 34 lines · Michal Hocko
Quoted 14 lines · Dan Streetman
Quoted 13 lines · Michal Hocko
Quoted 11 lines · Yu Zhao
__unregister_cpu_notifier()only removes registered notifier from its linked list when CPU hotplug is configured. If we free registered CPU notifier when HOTPLUG_CPU=n, we corrupt the linked list.To fix the problem, we can either use a static CPU notifier that walks through each pool or just simply disable CPU notifier when CPU hotplug is not configured (which is perfectly safe because the code in question is called after all possible CPUs are online and will remain online until power off).
v2: #ifdef for
cpu_notifier_register_doneduring cleanup.Quoted 7 lines
Quoted 3 lines
this ifedfery is just ugly as hell. I am also wondering whether it is really needed.
__register_cpu_notifierand__unregister_cpu_notifierare noops forCONFIG_HOTPLUG_CPU=n. So what's exactly that is broken here?hmm, that's interesting,
__unregister_cpu_notifieris always a noop if HOTPLUG_CPU=n, but__register_cpu_notifieris only a noop if HOTPLUG_CPU=n *and* MODULE. If !MODULE,__register_cpu_notifierdoesOK, I've missed the MODULE part
Quoted 5 lines
actually register! This was added by commit
47e627bc8c9a70392d2049e6af5bd55fae61fe53('hotplug: Allow modules to use the cpu hotplug notifiers even if !CONFIG_HOTPLUG_CPU') and looks like it's to allow built-ins to register so they can notice during boot when cpus are initialized.I cannot say I wound understand the motivation but that is not really all that important.
Quoted 8 lines
Quoted 4 lines
IMHO, that is the real problem - sure, without
HOTPLUG_CPU, nobody should ever get a notification that a cpu is dying, but that doesn't mean builtins that register notifiers will never unregister their notifiers and then free them.Yes that is true. That suggests that
__unregister_cpu_notifiershould the the symmetric thing to the__register_cpu_notifierforCONFIG_MODULE, right?I meant the following. Completely untested
Quoted 7 lines
Quoted 3 lines
agreed, but also needs the non-__ version, and
kernel/cpu.cneeds tweaking to move those functions out of the #ifdefCONFIG_HOTPLUG_CPUsection.OK, this is still only compile tested. Yu Zhao, assuming you were able to trigger the original problem could you test with the below patch please?
This patch (plus the latest fix in this thread) solves the problem.
Just for the record, the problem is when CONFIG_HOTPLUG_CPU=n, changing /sys/module/zswap/parameters/compressor multiple times will cause:
[ 144.964346] BUG: unable to handle kernel paging request at ffff880658a2be78 [ 144.971337] IP: [<ffffffffa290b00b>] raw_notifier_chain_register+0x1b/0x40 <snipped> [ 145.122628] Call Trace: [ 145.125086] [<ffffffffa28e5cf8>] __register_cpu_notifier+0x18/0x20 [ 145.131350] [<ffffffffa2a5dd73>] zswap_pool_create+0x273/0x400 [ 145.137268] [<ffffffffa2a5e0fc>] __zswap_param_set+0x1fc/0x300 [ 145.143188] [<ffffffffa2944c1d>] ? trace_hardirqs_on+0xd/0x10 [ 145.149018] [<ffffffffa2908798>] ? kernel_param_lock+0x28/0x30 [ 145.154940] [<ffffffffa2a3e8cf>] ? __might_fault+0x4f/0xa0 [ 145.160511] [<ffffffffa2a5e237>] zswap_compressor_param_set+0x17/0x20 [ 145.167035] [<ffffffffa2908d3c>] param_attr_store+0x5c/0xb0 [ 145.172694] [<ffffffffa290848d>] module_attr_store+0x1d/0x30 [ 145.178443] [<ffffffffa2b2b41f>] sysfs_kf_write+0x4f/0x70 [ 145.183925] [<ffffffffa2b2a5b9>] kernfs_fop_write+0x149/0x180 [ 145.189761] [<ffffffffa2a99248>] __vfs_write+0x18/0x40 [ 145.194982] [<ffffffffa2a9a412>] vfs_write+0xb2/0x1a0 [ 145.200122] [<ffffffffa2a9a732>] SyS_write+0x52/0xa0 [ 145.205177] [<ffffffffa2ff4d97>] entry_SYSCALL_64_fastpath+0x12/0x17
Quoted 66 lines
---
Fromc812fe4e519914aa37f092d3a0321038fadcdde7Mon Sep 17 00:00:00 2001
From: Michal Hocko <[email protected]>
Date: Fri, 2 Dec 2016 16:06:56 +0100
Subject: [PATCH] hotplug: make register and unregister notifier API symmetricYu Zhao has noticed that
__unregister_cpu_notifieronly unregisters its notifiers when HOTPLUG_CPU=y while the registration might succeed even when HOTPLUG_CPU=n if MODULE is enabled. This means that e.g. zswap might keep a stale notifier on the list on the manual clean up during the pool tear down and thus corrupt the list. Fix this issue by making unregister APIs symmetric to the register so there are no surprises.Fixes 47e627bc8c9a ("[PATCH] hotplug: Allow modules to use the cpu hotplug notifiers even if !CONFIG_HOTPLUG_CPU")Cc stable # zswap needs it 4.3+Reported-by Yu Zhao <[email protected]>Signed-off-by Michal Hocko <[email protected]>--- include/linux/cpu.h | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-)include/linux/cpu.h +4
-11@@ -105,22 +105,16 @@ extern bool cpuhp_tasks_frozen; { .notifier_call = fn, .priority = pri }; \ __register_cpu_notifier(&fn##_nb); \ } -#else /* #if defined(CONFIG_HOTPLUG_CPU) || !defined(MODULE) */ -#define cpu_notifier (fn, pri) do { (void)(fn); } while (0) -#define __cpu_notifier (fn, pri) do { (void)(fn); } while (0) -#endif /* #else #if defined(CONFIG_HOTPLUG_CPU) || !defined(MODULE) */ -#ifdef CONFIG_HOTPLUG_CPUextern int register_cpu_notifier (struct notifier_block *nb);extern int __register_cpu_notifier (struct notifier_block *nb);extern void unregister_cpu_notifier (struct notifier_block *nb);extern void __unregister_cpu_notifier (struct notifier_block *nb); -#else -#ifndef MODULE -extern int register_cpu_notifier(struct notifier_block *nb); -extern int __register_cpu_notifier(struct notifier_block *nb); -#else +#else /* #if defined(CONFIG_HOTPLUG_CPU) || !defined(MODULE) */ +#define cpu_notifier (fn, pri) do { (void)(fn); } while (0) +#define __cpu_notifier (fn, pri) do { (void)(fn); } while (0) +static inline int register_cpu_notifier (struct notifier_block *nb) {return 0 ;@@ -130,7 +124,6 @@ static inline int __register_cpu_notifier(struct notifier_block *nb) {return 0 ; } -#endif static inline void unregister_cpu_notifier (struct notifier_block *nb) {Signature · 5 lines
2.10.2 -- Michal Hocko SUSE Labs
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] hotplug: make register and unregister notifier API symmetric
Quoted 76 lines · Yu Zhao
Quoted 51 lines · Michal Hocko
[Let's CC more people - the thread started
http://lkml.kernel.org/r/[email protected]]Quoted 47 lines · Dan Streetman
Quoted 45 lines · Michal Hocko
Quoted 34 lines · Michal Hocko
Quoted 14 lines · Dan Streetman
Quoted 13 lines · Michal Hocko
Quoted 11 lines · Yu Zhao
__unregister_cpu_notifier()only removes registered notifier from its linked list when CPU hotplug is configured. If we free registered CPU notifier when HOTPLUG_CPU=n, we corrupt the linked list.To fix the problem, we can either use a static CPU notifier that walks through each pool or just simply disable CPU notifier when CPU hotplug is not configured (which is perfectly safe because the code in question is called after all possible CPUs are online and will remain online until power off).
v2: #ifdef for
cpu_notifier_register_doneduring cleanup.Quoted 7 lines
Quoted 3 lines
this ifedfery is just ugly as hell. I am also wondering whether it is really needed.
__register_cpu_notifierand__unregister_cpu_notifierare noops forCONFIG_HOTPLUG_CPU=n. So what's exactly that is broken here?hmm, that's interesting,
__unregister_cpu_notifieris always a noop if HOTPLUG_CPU=n, but__register_cpu_notifieris only a noop if HOTPLUG_CPU=n *and* MODULE. If !MODULE,__register_cpu_notifierdoesOK, I've missed the MODULE part
Quoted 5 lines
actually register! This was added by commit
47e627bc8c9a70392d2049e6af5bd55fae61fe53('hotplug: Allow modules to use the cpu hotplug notifiers even if !CONFIG_HOTPLUG_CPU') and looks like it's to allow built-ins to register so they can notice during boot when cpus are initialized.I cannot say I wound understand the motivation but that is not really all that important.
Quoted 8 lines
Quoted 4 lines
IMHO, that is the real problem - sure, without
HOTPLUG_CPU, nobody should ever get a notification that a cpu is dying, but that doesn't mean builtins that register notifiers will never unregister their notifiers and then free them.Yes that is true. That suggests that
__unregister_cpu_notifiershould the the symmetric thing to the__register_cpu_notifierforCONFIG_MODULE, right?I meant the following. Completely untested
Quoted 7 lines
Quoted 3 lines
agreed, but also needs the non-__ version, and
kernel/cpu.cneeds tweaking to move those functions out of the #ifdefCONFIG_HOTPLUG_CPUsection.OK, this is still only compile tested. Yu Zhao, assuming you were able to trigger the original problem could you test with the below patch please?
This patch (plus the latest fix in this thread) solves the problem.
Just for the record, the problem is when
CONFIG_HOTPLUG_CPU=n, changing/sys/module/zswap/parameters/compressormultiple times will cause:[ 144.964346] BUG: unable to handle kernel paging request at ffff880658a2be78 [ 144.971337] IP: [<ffffffffa290b00b>] raw_notifier_chain_register+0x1b/0x40 <snipped> [ 145.122628] Call Trace: [ 145.125086] [<ffffffffa28e5cf8>] __register_cpu_notifier+0x18/0x20 [ 145.131350] [<ffffffffa2a5dd73>] zswap_pool_create+0x273/0x400 [ 145.137268] [<ffffffffa2a5e0fc>] __zswap_param_set+0x1fc/0x300 [ 145.143188] [<ffffffffa2944c1d>] ? trace_hardirqs_on+0xd/0x10 [ 145.149018] [<ffffffffa2908798>] ? kernel_param_lock+0x28/0x30 [ 145.154940] [<ffffffffa2a3e8cf>] ? __might_fault+0x4f/0xa0 [ 145.160511] [<ffffffffa2a5e237>] zswap_compressor_param_set+0x17/0x20
Quoted 8 lines
[ 145.167035] [<ffffffffa2908d3c>] param_attr_store+0x5c/0xb0 [ 145.172694] [<ffffffffa290848d>] module_attr_store+0x1d/0x30 [ 145.178443] [<ffffffffa2b2b41f>] sysfs_kf_write+0x4f/0x70 [ 145.183925] [<ffffffffa2b2a5b9>] kernfs_fop_write+0x149/0x180 [ 145.189761] [<ffffffffa2a99248>] __vfs_write+0x18/0x40 [ 145.194982] [<ffffffffa2a9a412>] vfs_write+0xb2/0x1a0 [ 145.200122] [<ffffffffa2a9a732>] SyS_write+0x52/0xa0 [ 145.205177] [<ffffffffa2ff4d97>] entry_SYSCALL_64_fastpath+0x12/0x17
Thanks for this additional information which I have added to the changelog. I have also added your Tested-by unless you have any objections and will repost soon.
Signature · 8 lines
Michal Hocko SUSE Labs -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 11 lines · Michal Hocko
Quoted 10 lines · Yu Zhao
__unregister_cpu_notifier()only removes registered notifier from its linked list when CPU hotplug is configured. If we free registered CPU notifier when HOTPLUG_CPU=n, we corrupt the linked list.To fix the problem, we can either use a static CPU notifier that walks through each pool or just simply disable CPU notifier when CPU hotplug is not configured (which is perfectly safe because the code in question is called after all possible CPUs are online and will remain online until power off).
Quoted 5 lines
Quoted 1 line
v2: #ifdef for
cpu_notifier_register_doneduring cleanup.this ifedfery is just ugly as hell. I am also wondering whether it is really needed.
__register_cpu_notifierand__unregister_cpu_notifierare noops forCONFIG_HOTPLUG_CPU=n. So what's exactly that is broken here?
Well, I'm not a fan of ifdef and I don't like the unnecessary memory usage (notifier_block) and lock (cpu_notifier_register_begin/done) either.
Just pointing this out, having no problem living with your hotplug fixes.
Quoted 82 lines
Quoted 82 lines
Signe-off-by Yu Zhao <[email protected]>--- mm/zswap.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)mm/zswap.c +14
-0@@ -118,7 +118,9 @@ struct zswap_pool {struct kref kref;struct list_head list;struct work_struct work; +#ifdef CONFIG_HOTPLUG_CPU struct notifier_block notifier; +#endif char tfm_name[CRYPTO_MAX_ALG_NAME ]; };@@ -448,6 +450,7 @@ static int __zswap_cpu_comp_notifier(struct zswap_pool *pool,return NOTIFY_OK ; } +#ifdef CONFIG_HOTPLUG_CPU static int zswap_cpu_comp_notifier (struct notifier_block *nb,unsigned long action,void *pcpu) {@@ -456,27 +459,34 @@ static int zswap_cpu_comp_notifier(struct notifier_block *nb, return __zswap_cpu_comp_notifier(pool, action, cpu); } +#endif static int zswap_cpu_comp_init (struct zswap_pool *pool) {unsigned long cpu; +#ifdef CONFIG_HOTPLUG_CPU memset (&pool->notifier,0 ,sizeof (pool->notifier)); pool->notifier.notifier_call = zswap_cpu_comp_notifier;cpu_notifier_register_begin (); +#endif for_each_online_cpu (cpu)if (__zswap_cpu_comp_notifier (pool,CPU_UP_PREPARE , cpu) ==NOTIFY_BAD ) goto cleanup; +#ifdef CONFIG_HOTPLUG_CPU __register_cpu_notifier (&pool->notifier);cpu_notifier_register_done (); +#endif return 0 ; cleanup:for_each_online_cpu (cpu)__zswap_cpu_comp_notifier (pool,CPU_UP_CANCELED , cpu); +#ifdef CONFIG_HOTPLUG_CPU cpu_notifier_register_done (); +#endif return -ENOMEM ; }@@ -484,11 +494,15 @@ static void zswap_cpu_comp_destroy(struct zswap_pool *pool) {unsigned long cpu; +#ifdef CONFIG_HOTPLUG_CPU cpu_notifier_register_begin (); +#endif for_each_online_cpu (cpu)__zswap_cpu_comp_notifier (pool,CPU_UP_CANCELED , cpu); +#ifdef CONFIG_HOTPLUG_CPU __unregister_cpu_notifier (&pool->notifier);cpu_notifier_register_done (); +#endif }/********************************* Signature · 1 line
2.8.0.rc3.226.g39d4020
Quoted 9 lines
Quoted 5 lines
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>Signature · 2 lines
Michal Hocko SUSE Labs
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>