cpuset,mm: update tasks' mems_allowed in time (58568d2)
Hi,
The patch cpuset,mm: update tasks' mems_allowed in time (58568d2) causes a regression uncovered by SGI. Basically it is allowing possible but not online nodes in the task_struct.mems_allowed nodemask (which is contrary to several comments still in kernel/cpuset.c), and that causes cpuset_mem_spread_node() to return an offline node to slab, causing an oops.
Easy to reproduce if you have a machine with !online nodes.
- mkdir /dev/cpuset
- mount cpuset -t cpuset /dev/cpuset
- echo 1 > /dev/cpuset/memory_spread_slab
kernel BUG at /usr/src/packages/BUILD/kernel-default-2.6.32/linux-2.6.32/mm/slab.c:3271! bash[6885]: bugcheck! 0 [1]
Pid: 6885, CPU 5, comm: bash
psr : 00001010095a2010 ifs : 800000000000038b ip : [<a00000010020cf00>]
Tainted: G W (2.6.32-0.6.8-default) ip is at ____cache_alloc_node+0x440/0x500
unat: 0000000000000000 pfs : 000000000000038b rsc : 0000000000000003
rnat: 0000000000283d85 bsps: 0000000000000001 pr : 99596aaa69aa6999
ldrs: 0000000000000000 ccv : 0000000000000018 fpsr: 0009804c0270033f csd : 0000000000000000 ssd : 0000000000000000
b0 : a00000010020cf00 b6 : a0000001004962c0 b7 : a000000100493240 f6 : 000000000000000000000 f7 : 000000000000000000000 f8 : 000000000000000000000 f9 : 000000000000000000000 f10 : 000000000000000000000 f11 : 000000000000000000000 r1 : a0000001015c6fc0 r2 : 000000000000e662 r3 : 000000000000fffe r8 : 000000000000005c r9 : 0000000000000000 r10 : 0000000000004000 r11 : 0000000000000000 r12 : e000003c3904fcc0 r13 : e000003c39040000 r14 : 000000000000e662 r15 : a00000010138ed88 r16 : ffffffffffff65c8 r17 : a00000010138ed80 r18 : a0000001013c7ad0 r19 : a0000001013d3b60 r20 : e00001b03afdfe18 r21 : 0000000000000001 r22 : e0000130030365c8 r23 : e000013003040000 r24 : ffffffffffff0400 r25 : 00000000000068ef r26 : 00000000000068ef r27 : a0000001029621d0 r28 : 00000000000068f0 r29 : 00000000000068f0 r30 : 00000000000068f0 r31 : 000000000000000a
Call Trace: [<a000000100017a80>] show_stack+0x80/0xa0 [<a0000001000180e0>] show_regs+0x640/0x920 [<a000000100029a90>] die+0x190/0x2e0 [<a000000100029c30>] die_if_kernel+0x50/0x80 [<a000000100904af0>] ia64_bad_break+0x470/0x760 [<a00000010000cb60>] ia64_native_leave_kernel+0x0/0x270 [<a00000010020cf00>] ____cache_alloc_node+0x440/0x500 [<a00000010020ffa0>] kmem_cache_alloc+0x360/0x660
A simple bandaid is to skip !online nodes in cpuset_mem_spread_node(). However I'm a bit worried about 58568d2.
It is doing a lot of stuff. It is removing the callback_mutex from around several seemingly unrelated places (eg. from around guarnatee_online_cpus, which explicitly asks to be called with that lock held), and other places, so I don't know how it is not racy with hotplug.
Then it also says that the fastpath doesn't use any locking, so the update-path first adds the newly allowed nodes, then removes the newly prohibited nodes. Unfortunately there are no barriers apparent (and none added), and cpumask/nodemask can be larger than one word, so it seems there could be races.
It also seems like the exported cpuset_mems_allowed and cpuset_cpus_allowed APIs are just broken wrt hotplug because the hotplug lock is dropped before returning.
I'd just like to get opinions or comments from people who know the code better before wading in too far myself. I'd be really keen on making the locking simpler, using seqlocks for fastpaths, etc.
Thanks,
Nick
--
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 15 lines · Nick Piggin
Hi,
The patch cpuset,mm: update tasks'
mems_allowedin time (58568d2) causes a regression uncovered by SGI. Basically it is allowing possible but not online nodes in the task_struct.mems_allowed nodemask (which is contrary to several comments still inkernel/cpuset.c), and that causescpuset_mem_spread_node()to return an offline node to slab, causing an oops.Easy to reproduce if you have a machine with !online nodes.
- mkdir
/dev/cpuset
- mount cpuset -t cpuset/dev/cpuset
- echo 1 >/dev/cpuset/memory_spread_slab
Quoted 7 lines
kernel BUG at
/usr/src/packages/BUILD/kernel-default-2.6.32/linux-2.6.32/mm/slab.c:3271! bash[6885]: bugcheck! 0 [1]
Pid: 6885, CPU 5, comm: bash
psr :00001010095a2010ifs :800000000000038bip : [<a00000010020cf00>]Tainted: G W (2.6.32-0.6.8-default) ip is at ____cache_alloc_node+0x440/0x500
It seems like current->mems_allowed is not properly initialized, although task_cs(current)->mems_allowed is to node_states[N_HIGH_MEMORY]. See below.
Quoted 9 lines
A simple bandaid is to skip !online nodes in
cpuset_mem_spread_node(). However I'm a bit worried about 58568d2.It is doing a lot of stuff. It is removing the
callback_mutexfrom around several seemingly unrelated places (eg. from aroundguarnatee_online_cpus, which explicitly asks to be called with that lock held), and other places, so I don't know how it is not racy with hotplug.
guarantee_online_cpus() truly does require callback_mutex, the cgroup_scan_tasks() iterator locking can protect changes in the cgroup hierarchy but it doesn't protect a store to cs->cpus_allowed or for hotplug.
top_cpuset.cpus_allowed will always need to track cpu_active_map since those are the schedulable cpus, it looks like that's initialized for SMP and the cpu hotplug notifier does that correctly.
I'm not sure what the logic is doing in cpuset_attach() where cs is the cpuset to attach to:
if (cs == &top_cpuset) {
cpumask_copy(cpus_attach, cpu_possible_mask);
to = node_possible_map;
}cpus_attach is properly protected by cgroup_lock, but using node_possible_map here will set task->mems_allowed to node_possible_map when the cpuset does not have memory_migrate enabled. This is the source of your oops, I think.
Quoted 6 lines
Then it also says that the fastpath doesn't use any locking, so the update-path first adds the newly allowed nodes, then removes the newly prohibited nodes. Unfortunately there are no barriers apparent (and none added), and cpumask/nodemask can be larger than one word, so it seems there could be races.
We can remove the store to tsk->mems_allowed in cpuset_migrate_mm() because cpuset_change_task_nodemask() already does it under task_lock(tsk).
cpuset_migrate_mm() looks to be subsequently updating the cpuset_attach() nodemask when moving to top_cpuset so it doesn't get stuck with node_possible_map, but that's not called unless memory_migrate is enabled.
Quoted 4 lines
It also seems like the exported
cpuset_mems_allowedandcpuset_cpus_allowedAPIs are just broken wrt hotplug because the hotplug lock is dropped before returning.
The usage of cpuset_cpus_allowed_locked() looks wrong in the scheduler, as
well: it can't hold callback_mutex since it is only declared at file scope in the cpuset code.
Quoted 39 lines · David Rientjes
Quoted 15 lines · Nick Piggin
Hi,
The patch cpuset,mm: update tasks'
mems_allowedin time (58568d2) causes a regression uncovered by SGI. Basically it is allowing possible but not online nodes in the task_struct.mems_allowed nodemask (which is contrary to several comments still inkernel/cpuset.c), and that causescpuset_mem_spread_node()to return an offline node to slab, causing an oops.Easy to reproduce if you have a machine with !online nodes.
- mkdir
/dev/cpuset
- mount cpuset -t cpuset/dev/cpuset
- echo 1 >/dev/cpuset/memory_spread_slabQuoted 7 lines
kernel BUG at
/usr/src/packages/BUILD/kernel-default-2.6.32/linux-2.6.32/mm/slab.c:3271! bash[6885]: bugcheck! 0 [1]
Pid: 6885, CPU 5, comm: bash
psr :00001010095a2010ifs :800000000000038bip : [<a00000010020cf00>]Tainted: G W (2.6.32-0.6.8-default) ip is at ____cache_alloc_node+0x440/0x500It seems like
current->mems_allowedis not properly initialized, although task_cs(current)->mems_allowed is to node_states[N_HIGH_MEMORY]. See below.Quoted 9 lines
A simple bandaid is to skip !online nodes in
cpuset_mem_spread_node(). However I'm a bit worried about 58568d2.It is doing a lot of stuff. It is removing the
callback_mutexfrom around several seemingly unrelated places (eg. from aroundguarnatee_online_cpus, which explicitly asks to be called with that lock held), and other places, so I don't know how it is not racy with hotplug.
Quoted 4 lines
guarantee_online_cpus()truly does requirecallback_mutex, thecgroup_scan_tasks()iterator locking can protect changes in the cgroup hierarchy but it doesn't protect a store tocs->cpus_allowedor for hotplug.
Right, but the callback_mutex was being removed by this patch.
Quoted 13 lines
top_cpuset.cpus_allowed will always need to track
cpu_active_mapsince those are the schedulable cpus, it looks like that's initialized for SMP and the cpu hotplug notifier does that correctly.I'm not sure what the logic is doing in
cpuset_attach()where cs is the cpuset to attach to:if (cs == &top_cpuset) { cpumask_copy(cpus_attach, cpu_possible_mask); to = node_possible_map; }
Quoted 4 lines
cpus_attachis properly protected bycgroup_lock, but usingnode_possible_maphere will settask->mems_allowedtonode_possible_mapwhen the cpuset does not havememory_migrateenabled. This is the source of your oops, I think.
Could be, yes.
Quoted 10 lines
Quoted 6 lines
Then it also says that the fastpath doesn't use any locking, so the update-path first adds the newly allowed nodes, then removes the newly prohibited nodes. Unfortunately there are no barriers apparent (and none added), and cpumask/nodemask can be larger than one word, so it seems there could be races.
We can remove the store to
tsk->mems_allowedincpuset_migrate_mm()becausecpuset_change_task_nodemask()already does it undertask_lock(tsk).
But it doesn't matter if stores are done under lock, if the loads are not. masks can be multiple words, so there isn't any ordering between reading half and old mask and half a new one that results in an invalid state. AFAIKS.
Quoted 5 lines
cpuset_migrate_mm()looks to be subsequently updating thecpuset_attach()nodemask when moving totop_cpusetso it doesn't get stuck withnode_possible_map, but that's not called unlessmemory_migrateis enabled.
Quoted 8 lines
Quoted 4 lines
It also seems like the exported
cpuset_mems_allowedandcpuset_cpus_allowedAPIs are just broken wrt hotplug because the hotplug lock is dropped before returning.The usage of
cpuset_cpus_allowed_locked()looks wrong in the scheduler, as
well: it can't holdcallback_mutexsince it is only declared at file scope in the cpuset code.
Well it is exported as cpuset_lock(). And the scheduler has it covered in all cases by the looks except for select_task_rq, which is called by wakeup code. We should stick WARN_ONs through the cpuset code for mutexes not held when they should be.
Quoted 7 lines · Nick Piggin
Quoted 4 lines
guarantee_online_cpus()truly does requirecallback_mutex, thecgroup_scan_tasks()iterator locking can protect changes in the cgroup hierarchy but it doesn't protect a store tocs->cpus_allowedor for hotplug.Right, but the
callback_mutexwas being removed by this patch.
I was making the case for it to be readded :)
Quoted 12 lines
Quoted 12 lines
top_cpuset.cpus_allowed will always need to track
cpu_active_mapsince those are the schedulable cpus, it looks like that's initialized for SMP and the cpu hotplug notifier does that correctly.I'm not sure what the logic is doing in
cpuset_attach()where cs is the cpuset to attach to:if (cs == &top_cpuset) { cpumask_copy(cpus_attach, cpu_possible_mask); to = node_possible_map; }
Quoted 7 lines
Quoted 4 lines
cpus_attachis properly protected bycgroup_lock, but usingnode_possible_maphere will settask->mems_allowedtonode_possible_mapwhen the cpuset does not havememory_migrateenabled. This is the source of your oops, I think.Could be, yes.
I'd be interested to see if you still get the same oops with the patch at the end of this email that fixes this logic.
Quoted 5 lines
But it doesn't matter if stores are done under lock, if the loads are not. masks can be multiple words, so there isn't any ordering between reading half and old mask and half a new one that results in an invalid state. AFAIKS.
It doesn't matter for MAX_NUMNODES > BITS_PER_LONG because task->mems_alllowed only gets updated via cpuset_change_task_nodemask() where the added nodes are set and then the removed nodes are cleared. The side effect of this lockless access to task->mems_allowed means we may have a small race between
nodes_or(tsk->mems_allowed, tsk->mems_allowed, *newmems); and tsk->mems_allowed = *newmems;
but the penalty is that we get an allocation on a removed node, which isn't a big deal, especially since it was previously allowed.
Quoted 5 lines
Well it is exported as
cpuset_lock(). And the scheduler has it covered in all cases by the looks except forselect_task_rq, which is called by wakeup code. We should stickWARN_ONsthrough the cpuset code for mutexes not held when they should be.
A lot of the reliance on callback_mutex was removed because the strict hierarchy walking and task membership is now guarded by cgroup_mutex instead. Some of the comments in kernel/cpuset.c weren't updated so they still say callback_mutex when in reality they mean cgroup_mutex.
---
kernel/cpuset.c +7 -3
@@ -1319,7 +1319,7 @@ static int fmeter_getrate(struct fmeter *fmp)return val; } -/* Protected by cgroup_lock */ +/* Protected by cgroup_mutex held on cpuset_attach() */ static cpumask_var_t cpus_attach;/* Called by cgroups to determine if a cpuset is usable; cgroup_mutex held */
@@ -1390,8 +1390,12 @@ static void cpuset_attach(struct cgroup_subsys *ss, struct cgroup *cont,struct cpuset *oldcs =cgroup_cs (oldcont);if (cs == &top_cpuset) { -cpumask_copy (cpus_attach, cpu_possible_mask); - to = node_possible_map; +/* +* top_cpuset.cpus_allowed and top_cpuset.mems_allowed are +* protected by cgroup_lock which is already held here. +*/ +cpumask_copy (cpus_attach, top_cpuset.cpus_allowed); + to = top_cpuset.mems_allowed; }else {guarantee_online_cpus (cs, cpus_attach);guarantee_online_mems (cs, &to);
--
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>
I'm sorry for replying this late.
Quoted 11 lines · David Rientjes
Quoted 7 lines · Nick Piggin
Quoted 4 lines
guarantee_online_cpus()truly does requirecallback_mutex, thecgroup_scan_tasks()iterator locking can protect changes in the cgroup hierarchy but it doesn't protect a store tocs->cpus_allowedor for hotplug.Right, but the
callback_mutexwas being removed by this patch.I was making the case for it to be readded :)
But cgroup_mutex is held when someone changes cs->cpus_allowed or doing hotplug, so I think callback_mutex is not necessary in this case.
Quoted 18 lines
Quoted 18 lines
Quoted 17 lines
top_cpuset.cpus_allowed will always need to track
cpu_active_mapsince those are the schedulable cpus, it looks like that's initialized for SMP and the cpu hotplug notifier does that correctly.I'm not sure what the logic is doing in
cpuset_attach()where cs is the cpuset to attach to:if (cs == &top_cpuset) { cpumask_copy(cpus_attach, cpu_possible_mask); to = node_possible_map; }
cpus_attachis properly protected bycgroup_lock, but usingnode_possible_maphere will settask->mems_allowedtonode_possible_mapwhen the cpuset does not havememory_migrateenabled. This is the source of your oops, I think.
Quoted 5 lines
Quoted 2 lines
Could be, yes.
I'd be interested to see if you still get the same oops with the patch at the end of this email that fixes this logic.
I think this patch can't fix this bug, because mems_allowed of tasks in the top group is set to node_possible_map by default, not when the task is attached.
I made a new patch at the end of this email to fix it, but I have no machine to test it now. who can test it for me.
---
init/main.c +1 -1
@@ -846,7 +846,7 @@ static int __init kernel_init(void * unused)/* * init can allocate pages on any node */ -set_mems_allowed (node_possible_map); +set_mems_allowed (node_states[N_HIGH_MEMORY ]);/* * init can run on any cpu. */
kernel/cpuset.c +10 -5
@@ -935,10 +935,12 @@ static void cpuset_migrate_mm(struct mm_struct *mm, const nodemask_t *from,struct task_struct *tsk = current; tsk->mems_allowed = *to; +wmb ();do_migrate_pages (mm, from, to,MPOL_MF_MOVE_ALL );guarantee_online_mems (task_cs (tsk),&tsk->mems_allowed); +wmb (); }/*
@@ -1391,11 +1393,10 @@ static void cpuset_attach(struct cgroup_subsys *ss, struct cgroup *cont,if (cs == &top_cpuset) {cpumask_copy (cpus_attach, cpu_possible_mask); - to = node_possible_map; }else {guarantee_online_cpus (cs, cpus_attach); -guarantee_online_mems (cs, &to); } +guarantee_online_mems (cs, &to);/* do per-task migration stuff possibly for each in the threadgroup */ cpuset_attach_task (tsk, &to, cs);
@@ -2090,15 +2091,19 @@ static int cpuset_track_online_cpus(struct notifier_block *unused_nb,static int cpuset_track_online_nodes (struct notifier_block *self,unsigned long action,void *arg) { +nodemask_t oldmems; +cgroup_lock ();switch (action) {case MEM_ONLINE : -case MEM_OFFLINE : + oldmems = top_cpuset.mems_allowed;mutex_lock (&callback_mutex); top_cpuset.mems_allowed = node_states[N_HIGH_MEMORY ];mutex_unlock (&callback_mutex); -if (action ==MEM_OFFLINE ) -scan_for_empty_cpusets (&top_cpuset); +update_tasks_nodemask (&top_cpuset, &oldmems,NULL ); +break ; +case MEM_OFFLINE : +scan_for_empty_cpusets (&top_cpuset);break ;default :break ;
kernel/kthread.c +1 -1
@@ -219,7 +219,7 @@ int kthreadd(void *unused)set_task_comm (tsk,"kthreadd" );ignore_signals (tsk);set_cpus_allowed_ptr (tsk, cpu_all_mask); -set_mems_allowed (node_possible_map); +set_mems_allowed (node_states[N_HIGH_MEMORY ]); current->flags |=PF_NOFREEZE |PF_FREEZER_NOSIG ;
Quoted 1 line · Miao Xie
I'm sorry for replying this late.
No problem.
Quoted 8 lines
Quoted 7 lines · David Rientjes
Quoted 5 lines · Nick Piggin
Quoted 4 lines
guarantee_online_cpus()truly does requirecallback_mutex, thecgroup_scan_tasks()iterator locking can protect changes in the cgroup hierarchy but it doesn't protect a store tocs->cpus_allowedor for hotplug.
Quoted 7 lines
Quoted 4 lines
Quoted 2 lines
Right, but the
callback_mutexwas being removed by this patch.I was making the case for it to be readded :)
But
cgroup_mutexis held when someone changescs->cpus_allowedor doing hotplug, so I thinkcallback_mutexis not necessary in this case.
So long as that's done consistently (and we should update the comments too).
Quoted 23 lines
Quoted 17 lines
Quoted 17 lines
Quoted 16 lines
top_cpuset.cpus_allowed will always need to track
cpu_active_mapsince those are the schedulable cpus, it looks like that's initialized for SMP and the cpu hotplug notifier does that correctly.I'm not sure what the logic is doing in
cpuset_attach()where cs is the cpuset to attach to:if (cs == &top_cpuset) { cpumask_copy(cpus_attach, cpu_possible_mask); to = node_possible_map; }
cpus_attachis properly protected bycgroup_lock, but usingnode_possible_maphere will settask->mems_allowedtonode_possible_mapwhen the cpuset does not havememory_migrateenabled. This is the source of your oops, I think.Quoted 5 lines
Quoted 2 lines
Could be, yes.
I'd be interested to see if you still get the same oops with the patch at the end of this email that fixes this logic.
Quoted 6 lines
I think this patch can't fix this bug, because
mems_allowedof tasks in the top group is set tonode_possible_mapby default, not when the task is attached.I made a new patch at the end of this email to fix it, but I have no machine to test it now. who can test it for me.
I can test it for you, but I wonder about your barriers.
Quoted 22 lines
---
init/main.c +1
-1@@ -846,7 +846,7 @@ static int __init kernel_init(void * unused)/* * init can allocate pages on any node */ -set_mems_allowed (node_possible_map); +set_mems_allowed (node_states[N_HIGH_MEMORY ]);/* * init can run on any cpu. */ kernel/cpuset.c +0
-0@@ -935,10 +935,12 @@ static void cpuset_migrate_mm(struct mm_struct *mm, const nodemask_t *from,struct task_struct *tsk = current;
kernel/cpuset.c static void cpuset_migrate_mm(struct mm_struct *mm, const nodemask_t *from, · line 946
Quoted 10 lines
kernel/cpuset.c +2
-0tsk->mems_allowed = *to; +wmb ();do_migrate_pages (mm, from, to,MPOL_MF_MOVE_ALL );guarantee_online_mems (task_cs (tsk),&tsk->mems_allowed); +wmb (); }/*
You always need to comment barriers (and use smp_ variants unless you're doing mmio).
Quoted 41 lines
kernel/cpuset.c +8
-5@@ -1391,11 +1393,10 @@ static void cpuset_attach(struct cgroup_subsys *ss, struct cgroup *cont,if (cs == &top_cpuset) {cpumask_copy (cpus_attach, cpu_possible_mask); - to = node_possible_map; }else {guarantee_online_cpus (cs, cpus_attach); -guarantee_online_mems (cs, &to); } +guarantee_online_mems (cs, &to);/* do per-task migration stuff possibly for each in the threadgroup */ cpuset_attach_task (tsk, &to, cs);@@ -2090,15 +2091,19 @@ static int cpuset_track_online_cpus(struct notifier_block *unused_nb,static int cpuset_track_online_nodes (struct notifier_block *self,unsigned long action,void *arg) { +nodemask_t oldmems; +cgroup_lock ();switch (action) {case MEM_ONLINE : -case MEM_OFFLINE : + oldmems = top_cpuset.mems_allowed;mutex_lock (&callback_mutex); top_cpuset.mems_allowed = node_states[N_HIGH_MEMORY ];mutex_unlock (&callback_mutex); -if (action ==MEM_OFFLINE ) -scan_for_empty_cpusets (&top_cpuset); +update_tasks_nodemask (&top_cpuset, &oldmems,NULL ); +break ; +case MEM_OFFLINE : +scan_for_empty_cpusets (&top_cpuset);break ;default :break ;kernel/kthread.c +0
-0
kernel/kthread.c int kthreadd(void *unused) · line 225
Quoted 8 lines
kernel/kthread.c +1
-1@@ -219,7 +219,7 @@ int kthreadd(void *unused)set_task_comm (tsk,"kthreadd" );ignore_signals (tsk);set_cpus_allowed_ptr (tsk, cpu_all_mask); -set_mems_allowed (node_possible_map); +set_mems_allowed (node_states[N_HIGH_MEMORY ]); current->flags |=PF_NOFREEZE |PF_FREEZER_NOSIG ;
--
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 8 lines · Nick Piggin
Quoted 8 lines
Quoted 8 lines
Quoted 7 lines
Quoted 4 lines
guarantee_online_cpus()truly does requirecallback_mutex, thecgroup_scan_tasks()iterator locking can protect changes in the cgroup hierarchy but it doesn't protect a store tocs->cpus_allowedor for hotplug.Right, but the
callback_mutexwas being removed by this patch.
Quoted 7 lines
Quoted 4 lines
Quoted 1 line
I was making the case for it to be readded :)
But
cgroup_mutexis held when someone changescs->cpus_allowedor doing hotplug, so I thinkcallback_mutexis not necessary in this case.So long as that's done consistently (and we should update the comments too).
I will update the comments.
Quoted 26 lines
Quoted 26 lines
---
init/main.c +1
-1@@ -846,7 +846,7 @@ static int __init kernel_init(void * unused)/* * init can allocate pages on any node */ -set_mems_allowed (node_possible_map); +set_mems_allowed (node_states[N_HIGH_MEMORY ]);/* * init can run on any cpu. */ kernel/cpuset.c +1
-0@@ -935,10 +935,12 @@ static void cpuset_migrate_mm(struct mm_struct *mm, const nodemask_t *from,struct task_struct *tsk = current; tsk->mems_allowed = *to; +wmb ();do_migrate_pages (mm, from, to,MPOL_MF_MOVE_ALL );
Quoted 8 lines
kernel/cpuset.c static void cpuset_migrate_mm(struct mm_struct *mm, const nodemask_t *from, · line 946
Quoted 5 lines
kernel/cpuset.c +1
-0guarantee_online_mems (task_cs (tsk),&tsk->mems_allowed); +wmb (); }/* You always need to comment barriers (and use
smp_variants unless you're doing mmio).
It's my mistake.
I'll remake a new patch and change it.
Thanks.
Miao
Quoted 54 lines
Quoted 51 lines
kernel/cpuset.c +8
-5@@ -1391,11 +1393,10 @@ static void cpuset_attach(struct cgroup_subsys *ss, struct cgroup *cont,if (cs == &top_cpuset) {cpumask_copy (cpus_attach, cpu_possible_mask); - to = node_possible_map; }else {guarantee_online_cpus (cs, cpus_attach); -guarantee_online_mems (cs, &to); } +guarantee_online_mems (cs, &to);/* do per-task migration stuff possibly for each in the threadgroup */ cpuset_attach_task (tsk, &to, cs);@@ -2090,15 +2091,19 @@ static int cpuset_track_online_cpus(struct notifier_block *unused_nb,static int cpuset_track_online_nodes (struct notifier_block *self,unsigned long action,void *arg) { +nodemask_t oldmems; +cgroup_lock ();switch (action) {case MEM_ONLINE : -case MEM_OFFLINE : + oldmems = top_cpuset.mems_allowed;mutex_lock (&callback_mutex); top_cpuset.mems_allowed = node_states[N_HIGH_MEMORY ];mutex_unlock (&callback_mutex); -if (action ==MEM_OFFLINE ) -scan_for_empty_cpusets (&top_cpuset); +update_tasks_nodemask (&top_cpuset, &oldmems,NULL ); +break ; +case MEM_OFFLINE : +scan_for_empty_cpusets (&top_cpuset);break ;default :break ;kernel/kthread.c +1
-1@@ -219,7 +219,7 @@ int kthreadd(void *unused)set_task_comm (tsk,"kthreadd" );ignore_signals (tsk);set_cpus_allowed_ptr (tsk, cpu_all_mask); -set_mems_allowed (node_possible_map); +set_mems_allowed (node_states[N_HIGH_MEMORY ]); current->flags |=PF_NOFREEZE |PF_FREEZER_NOSIG ;
Quoted 5 lines · Miao Xie
Quoted 5 lines
Quoted 5 lines
Quoted 4 lines
guarantee_online_cpus()truly does requirecallback_mutex, thecgroup_scan_tasks()iterator locking can protect changes in the cgroup hierarchy but it doesn't protect a store tocs->cpus_allowedor for hotplug.
Quoted 8 lines
Quoted 4 lines
Quoted 2 lines
Right, but the
callback_mutexwas being removed by this patch.I was making the case for it to be readded :)
But
cgroup_mutexis held when someone changescs->cpus_allowedor doing hotplug, so I thinkcallback_mutexis not necessary in this case.
Then why is it taken in update_cpumask()?
Quoted 4 lines
I think this patch can't fix this bug, because
mems_allowedof tasks in the top group is set tonode_possible_mapby default, not when the task is attached.
Ok, I thought that all tasks get their ->attach() function called whenever their cgroup is mounted.
Quoted 37 lines
I made a new patch at the end of this email to fix it, but I have no machine to test it now. who can test it for me.
---
init/main.c +1
-1@@ -846,7 +846,7 @@ static int __init kernel_init(void * unused)/* * init can allocate pages on any node */ -set_mems_allowed (node_possible_map); +set_mems_allowed (node_states[N_HIGH_MEMORY ]);/* * init can run on any cpu. */ kernel/cpuset.c +2
-0@@ -935,10 +935,12 @@ static void cpuset_migrate_mm(struct mm_struct *mm, const nodemask_t *from,struct task_struct *tsk = current; tsk->mems_allowed = *to; +wmb ();do_migrate_pages (mm, from, to,MPOL_MF_MOVE_ALL );guarantee_online_mems (task_cs (tsk),&tsk->mems_allowed); +wmb (); }/* @@ -1391,11 +1393,10 @@ static void cpuset_attach(struct cgroup_subsys *ss, struct cgroup *cont,if (cs == &top_cpuset) {
kernel/cpuset.c static void cpuset_attach(struct cgroup_subsys *ss, struct cgroup *cont, · line 1402
Quoted 10 lines
kernel/cpuset.c +1
-2cpumask_copy (cpus_attach, cpu_possible_mask); - to = node_possible_map; }else {guarantee_online_cpus (cs, cpus_attach); -guarantee_online_mems (cs, &to); } +guarantee_online_mems (cs, &to);/* do per-task migration stuff possibly for each in the threadgroup */ cpuset_attach_task (tsk, &to, cs);
Do we need to set cpus_attach to cpu_possible_mask? Why won't cpu_active_mask suffice?
kernel/cpuset.c static int cpuset_track_online_cpus(struct notifier_block *unused_nb, · line 2094
Quoted 5 lines
kernel/cpuset.c +1
-0@@ -2090,15 +2091,19 @@ static int cpuset_track_online_cpus(struct notifier_block *unused_nb,static int cpuset_track_online_nodes (struct notifier_block *self,unsigned long action,void *arg) { +nodemask_t oldmems;
Is it possible to use NODEMASK_ALLOC() instead?
Quoted 8 lines
kernel/cpuset.c +2
-1+cgroup_lock ();switch (action) {case MEM_ONLINE : -case MEM_OFFLINE : + oldmems = top_cpuset.mems_allowed;mutex_lock (&callback_mutex); top_cpuset.mems_allowed = node_states[N_HIGH_MEMORY ];
kernel/cpuset.c static int cpuset_track_online_cpus(struct notifier_block *unused_nb, · line 2109
Quoted 10 lines
kernel/cpuset.c +4
-2mutex_unlock (&callback_mutex); -if (action ==MEM_OFFLINE ) -scan_for_empty_cpusets (&top_cpuset); +update_tasks_nodemask (&top_cpuset, &oldmems,NULL ); +break ; +case MEM_OFFLINE : +scan_for_empty_cpusets (&top_cpuset);break ;default :break ;
Looks good.
--
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 10 lines · David Rientjes
Quoted 8 lines
Quoted 4 lines
Quoted 2 lines
Right, but the
callback_mutexwas being removed by this patch.I was making the case for it to be readded :)
But
cgroup_mutexis held when someone changescs->cpus_allowedor doing hotplug, so I thinkcallback_mutexis not necessary in this case.Then why is it taken in
update_cpumask()?
when we read cs->cpus_allowed, we need just hold one of callback_mutex and cgroup_mutex. If we want to change cs->cpus_allowed, we must hold callback_mutex and cgroup_mutex.
Quoted 12 lines
Quoted 12 lines
/*
kernel/cpuset.c +1
-2@@ -1391,11 +1393,10 @@ static void cpuset_attach(struct cgroup_subsys *ss, struct cgroup *cont,if (cs == &top_cpuset) {cpumask_copy (cpus_attach, cpu_possible_mask); - to = node_possible_map; }else {guarantee_online_cpus (cs, cpus_attach); -guarantee_online_mems (cs, &to); } +guarantee_online_mems (cs, &to);
Quoted 5 lines
kernel/cpuset.c static void cpuset_attach(struct cgroup_subsys *ss, struct cgroup *cont, · line 1402
Quoted 2 lines
kernel/cpuset.c +0
-0/* do per-task migration stuff possibly for each in the threadgroup */ cpuset_attach_task (tsk, &to, cs);Do we need to set
cpus_attachtocpu_possible_mask? Why won'tcpu_active_masksuffice?
If we set cpus_attach to cpu_possible_mask, we needn't do anything for tasks in the top_cpuset when doing cpu hotplug. If not, we will update cpus_allowed of all tasks in the top_cpuset.
Quoted 8 lines
kernel/cpuset.c static int cpuset_track_online_cpus(struct notifier_block *unused_nb, · line 2094
Quoted 6 lines
kernel/cpuset.c +1
-0@@ -2090,15 +2091,19 @@ static int cpuset_track_online_cpus(struct notifier_block *unused_nb,static int cpuset_track_online_nodes (struct notifier_block *self,unsigned long action,void *arg) { +nodemask_t oldmems;Is it possible to use
NODEMASK_ALLOC()instead?
Yes. I will write another patch to fix it.(These are the same problems in the other functions)
--
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 12 lines · Miao Xie
Quoted 12 lines
Quoted 12 lines
/*
kernel/cpuset.c +1
-2@@ -1391,11 +1393,10 @@ static void cpuset_attach(struct cgroup_subsys *ss, struct cgroup *cont,if (cs == &top_cpuset) {cpumask_copy (cpus_attach, cpu_possible_mask); - to = node_possible_map; }else {guarantee_online_cpus (cs, cpus_attach); -guarantee_online_mems (cs, &to); } +guarantee_online_mems (cs, &to);
Quoted 9 lines
Quoted 5 lines
kernel/cpuset.c static void cpuset_attach(struct cgroup_subsys *ss, struct cgroup *cont, · line 1402
Quoted 2 lines
kernel/cpuset.c +0
-0/* do per-task migration stuff possibly for each in the threadgroup */ cpuset_attach_task (tsk, &to, cs);Do we need to set
cpus_attachtocpu_possible_mask? Why won'tcpu_active_masksuffice?If we set
cpus_attachtocpu_possible_mask, we needn't do anything for tasks in thetop_cpusetwhen doing cpu hotplug. If not, we will updatecpus_allowedof all tasks in thetop_cpuset.
Cpu hotplug sets top_cpuset's cpus_allowed to cpu_active_mask by default, regardless of what was onlined or offlined. cpus_attach in the context of your patch (in cpuset_attach()) passes cpu_possible_mask to set_cpus_allowed_ptr() if the task is being attached to top_cpuset, my question was why don't we pass cpu_active_mask instead? In other words, I think we should do
cpumask_copy(cpus_attach, cpu_active_mask);
when attached to top_cpuset like my patch did.
Quoted 10 lines · David Rientjes
Cpu hotplug sets top_cpuset's
cpus_allowedtocpu_active_maskby default, regardless of what was onlined or offlined.cpus_attachin the context of your patch (incpuset_attach()) passescpu_possible_masktoset_cpus_allowed_ptr()if the task is being attached totop_cpuset, my question was why don't we passcpu_active_maskinstead? In other words, I think we should docpumask_copy(cpus_attach, cpu_active_mask);when attached to
top_cpusetlike my patch did.
If we pass cpu_active_mask to set_cpus_allowed_ptr(), task->cpus_allowed just contains the online cpus. In this way, if we do cpu hotplug(such as: online some cpu), we must update cpus_allowed of all tasks in the top cpuset.
But if we pass cpu_possible_mask, we needn't update cpus_allowed of all tasks in the top cpuset. And when the kernel looks for a cpu for task to run, the kernel will use cpu_active_mask to filter out offline cpus in task->cpus_allowed. Thus, it is safe.
--
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 · Miao Xie
Quoted 10 lines
Cpu hotplug sets top_cpuset's
cpus_allowedtocpu_active_maskby default, regardless of what was onlined or offlined.cpus_attachin the context of your patch (incpuset_attach()) passescpu_possible_masktoset_cpus_allowed_ptr()if the task is being attached totop_cpuset, my question was why don't we passcpu_active_maskinstead? In other words, I think we should docpumask_copy(cpus_attach, cpu_active_mask);when attached to
top_cpusetlike my patch did.
Quoted 8 lines
If we pass
cpu_active_masktoset_cpus_allowed_ptr(),task->cpus_allowedjust contains the online cpus. In this way, if we do cpu hotplug(such as: online some cpu), we must updatecpus_allowedof all tasks in the top cpuset.But if we pass
cpu_possible_mask, we needn't updatecpus_allowedof all tasks in the top cpuset. And when the kernel looks for a cpu for task to run, the kernel will usecpu_active_maskto filter out offline cpus intask->cpus_allowed. Thus, it is safe.
That is terribly inconsistent between top_cpuset and all descendants; all other cpusets require that task->cpus_allowed be a subset of cpu_online_mask, including those descendants that allow all cpus (and all mems).
--
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 22 lines · David Rientjes
Quoted 11 lines · Miao Xie
Quoted 10 lines
Cpu hotplug sets top_cpuset's
cpus_allowedtocpu_active_maskby default, regardless of what was onlined or offlined.cpus_attachin the context of your patch (incpuset_attach()) passescpu_possible_masktoset_cpus_allowed_ptr()if the task is being attached totop_cpuset, my question was why don't we passcpu_active_maskinstead? In other words, I think we should docpumask_copy(cpus_attach, cpu_active_mask);when attached to
top_cpusetlike my patch did.Quoted 8 lines
If we pass
cpu_active_masktoset_cpus_allowed_ptr(),task->cpus_allowedjust contains the online cpus. In this way, if we do cpu hotplug(such as: online some cpu), we must updatecpus_allowedof all tasks in the top cpuset.But if we pass
cpu_possible_mask, we needn't updatecpus_allowedof all tasks in the top cpuset. And when the kernel looks for a cpu for task to run, the kernel will usecpu_active_maskto filter out offline cpus intask->cpus_allowed. Thus, it is safe.
Quoted 4 lines
That is terribly inconsistent between
top_cpusetand all descendants; all other cpusets require thattask->cpus_allowedbe a subset ofcpu_online_mask, including those descendants that allow all cpus (and all mems).
I think it is not a big deal because it is safe and doesn't cause any problem. Beside that, task->cpus_allowed is initialized to cpu_possible_mask on the no-cpuset kernel, so using cpu_possible_mask to initialize task->cpus_allowed is reasonable. (top cpuset is a special cpuset, isn't it?)
--
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 5 lines · Miao Xie
I think it is not a big deal because it is safe and doesn't cause any problem. Beside that,
task->cpus_allowedis initialized tocpu_possible_maskon the no-cpuset kernel, so usingcpu_possible_maskto initializetask->cpus_allowedis reasonable. (top cpuset is a special cpuset, isn't it?)
I'm suprised that I can create a descendant cpuset of top_cpuset that cannot include all of its parents' cpus and that the root cpuset's cpus mask doesn't change when cpus are onlined/offlined.
Quoted 8 lines · David Rientjes
Quoted 5 lines · Miao Xie
I think it is not a big deal because it is safe and doesn't cause any problem. Beside that,
task->cpus_allowedis initialized tocpu_possible_maskon the no-cpuset kernel, so usingcpu_possible_maskto initializetask->cpus_allowedis reasonable. (top cpuset is a special cpuset, isn't it?)
Quoted 4 lines
I'm suprised that I can create a descendant cpuset of
top_cpusetthat cannot include all of its parents' cpus and that the root cpuset's cpus mask doesn't change when cpus are onlined/offlined.
top cpuset's cpus is consistent with cpu_online_mask because the kernel changes it when doing cpu hotplug. So the problem which you said doesn't exist.
Just cpus_allowed of all tasks in the top cpuset is initialized to cpu_possible_mask in order to avoid updating them when doing cpu hotplug.
--
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 13 lines · David Rientjes
Quoted 5 lines · Nick Piggin
But it doesn't matter if stores are done under lock, if the loads are not. masks can be multiple words, so there isn't any ordering between reading half and old mask and half a new one that results in an invalid state. AFAIKS.
It doesn't matter for
MAX_NUMNODES>BITS_PER_LONGbecausetask->mems_alllowedonly gets updated viacpuset_change_task_nodemask()where the added nodes are set and then the removed nodes are cleared. The side effect of this lockless access totask->mems_allowedmeans we may have a small race between
Quoted 8 lines
nodes_or(tsk->mems_allowed, tsk->mems_allowed, *newmems); and tsk->mems_allowed = *newmems;but the penalty is that we get an allocation on a removed node, which isn't a big deal, especially since it was previously allowed.
If you have a concurrent reader without any synchronisation, then what stops it from loading a word of the mask before stores to add the new nodes and then loading another word of the mask after the stores to remove the old nodes? (which can give an empty mask).
--
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 5 lines · Nick Piggin
If you have a concurrent reader without any synchronisation, then what stops it from loading a word of the mask before stores to add the new nodes and then loading another word of the mask after the stores to remove the old nodes? (which can give an empty mask).
Currently nothing, so we'll need a variant for configurations where the size of nodemask_t is larger than we can atomically store.
--
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 · David Rientjes
Quoted 5 lines · Nick Piggin
If you have a concurrent reader without any synchronisation, then what stops it from loading a word of the mask before stores to add the new nodes and then loading another word of the mask after the stores to remove the old nodes? (which can give an empty mask).
Currently nothing, so we'll need a variant for configurations where the size of
nodemask_tis larger than we can atomically store.
Sorry, Could you explain what you advised?
I think it is hard to fix this problem by adding a variant, because it is hard to avoid loading a word of the mask before
nodes_or(tsk->mems_allowed, tsk->mems_allowed, *newmems);
and then loading another word of the mask after
tsk->mems_allowed = *newmems;
unless we use lock.
Maybe we need a rw-lock to protect task->mems_allowed.
--
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 6 lines · Miao Xie
Sorry, Could you explain what you advised?
I think it is hard to fix this problem by adding a variant, because it is hard to avoid loading a word of the mask beforenodes_or(tsk->mems_allowed, tsk->mems_allowed, *newmems);
Quoted 8 lines
and then loading another word of the mask after
tsk->mems_allowed = *newmems;unless we use lock.
Maybe we need a rw-lock to protect
task->mems_allowed.
I meant that we need to define synchronization only for configurations that do not do atomic nodemask_t stores, it's otherwise unnecessary. We'll need to load and store tsk->mems_allowed via a helper function that is defined to take the rwlock for such configs and only read/write the nodemask for others.
--
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 · David Rientjes
Quoted 12 lines · Miao Xie
Sorry, Could you explain what you advised?
I think it is hard to fix this problem by adding a variant, because it is hard to avoid loading a word of the mask beforenodes_or(tsk->mems_allowed, tsk->mems_allowed, *newmems);and then loading another word of the mask after
tsk->mems_allowed = *newmems;unless we use lock.
Quoted 9 lines
Quoted 2 lines
Maybe we need a rw-lock to protect
task->mems_allowed.I meant that we need to define synchronization only for configurations that do not do atomic
nodemask_tstores, it's otherwise unnecessary. We'll need to load and storetsk->mems_allowedvia a helper function that is defined to take the rwlock for such configs and only read/write the nodemask for others.
By investigating, we found that it is hard to guarantee the consistent between mempolicy and mems_allowed because mempolicy was designed as a self-update function. it just can be changed by one's self. Maybe we must change the implement of mempolicy.
--
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 22 lines · Miao Xie
Quoted 12 lines
Quoted 12 lines
Sorry, Could you explain what you advised?
I think it is hard to fix this problem by adding a variant, because it is hard to avoid loading a word of the mask beforenodes_or(tsk->mems_allowed, tsk->mems_allowed, *newmems);and then loading another word of the mask after
tsk->mems_allowed = *newmems;unless we use lock.
Quoted 9 lines
Quoted 2 lines
Maybe we need a rw-lock to protect
task->mems_allowed.I meant that we need to define synchronization only for configurations that do not do atomic
nodemask_tstores, it's otherwise unnecessary. We'll need to load and storetsk->mems_allowedvia a helper function that is defined to take the rwlock for such configs and only read/write the nodemask for others.
Quoted 4 lines
By investigating, we found that it is hard to guarantee the consistent between mempolicy and
mems_allowedbecause mempolicy was designed as a self-update function. it just can be changed by one's self. Maybe we must change the implement of mempolicy.
Before your change, cpuset nodemask changes were serialized on manage_mutex which would, in turn, serialize the rebinding of each attached task's mempolicy. update_nodemask() is now serialized on cgroup_lock(), which also protects scan_for_empty_cpusets(), so the cpuset code protects it adequately. If a concurrent mempolicy change from a user's set_mempolicy() happens, however, it could introduce an inconsistency between them.
If we protect current->mems_allowed with a rwlock or seqlock for configs where MAX_NUMNODES > BITS_PER_LONG, then we can always guarantee that we get the entire nodemask. The same problem is present for current->cpus_allowed, however, with NR_CPUS > BITS_PER_LONG. We must be able to safely dereference both masks without the chance of returning nodes_empty() or cpus_empty().
--
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 51 lines
Hi,
The patch cpuset,mm: update tasks'
mems_allowedin time (58568d2) causes a regression uncovered by SGI. Basically it is allowing possible but not online nodes in the task_struct.mems_allowed nodemask (which is contrary to several comments still inkernel/cpuset.c), and that causescpuset_mem_spread_node()to return an offline node to slab, causing an oops.Easy to reproduce if you have a machine with !online nodes.
- mkdir
/dev/cpuset
- mount cpuset -t cpuset/dev/cpuset
- echo 1 >/dev/cpuset/memory_spread_slabkernel BUG at
/usr/src/packages/BUILD/kernel-default-2.6.32/linux-2.6.32/mm/slab.c:3271! bash[6885]: bugcheck! 0 [1]
Pid: 6885, CPU 5, comm: bash
psr :00001010095a2010ifs :800000000000038bip : [<a00000010020cf00>]Tainted: G W (2.6.32-0.6.8-default) ip is at ____cache_alloc_node+0x440/0x500unat: 0000000000000000 pfs :
000000000000038brsc : 0000000000000003
rnat:0000000000283d85bsps: 0000000000000001 pr :99596aaa69aa6999
ldrs: 0000000000000000 ccv : 0000000000000018 fpsr:0009804c0270033fcsd : 0000000000000000 ssd : 0000000000000000
b0 :a00000010020cf00b6 :a0000001004962c0b7 :a000000100493240f6 : 000000000000000000000 f7 : 000000000000000000000 f8 : 000000000000000000000 f9 : 000000000000000000000 f10 : 000000000000000000000 f11 : 000000000000000000000 r1 :a0000001015c6fc0r2 :000000000000e662r3 :000000000000fffer8 :000000000000005cr9 : 0000000000000000 r10 : 0000000000004000 r11 : 0000000000000000 r12 :e000003c3904fcc0r13 :e000003c39040000r14 :000000000000e662r15 :a00000010138ed88r16 :ffffffffffff65c8r17 :a00000010138ed80r18 :a0000001013c7ad0r19 :a0000001013d3b60r20 :e00001b03afdfe18r21 : 0000000000000001 r22 :e0000130030365c8r23 :e000013003040000r24 :ffffffffffff0400r25 :00000000000068efr26 :00000000000068efr27 :a0000001029621d0r28 :00000000000068f0r29 :00000000000068f0r30 :00000000000068f0r31 :000000000000000aCall Trace: [<a000000100017a80>] show_stack+0x80/0xa0 [<a0000001000180e0>] show_regs+0x640/0x920 [<a000000100029a90>] die+0x190/0x2e0 [<a000000100029c30>] die_if_kernel+0x50/0x80 [<a000000100904af0>] ia64_bad_break+0x470/0x760 [<a00000010000cb60>] ia64_native_leave_kernel+0x0/0x270 [<a00000010020cf00>] ____cache_alloc_node+0x440/0x500 [<a00000010020ffa0>] kmem_cache_alloc+0x360/0x660
Quoted 2 lines
A simple bandaid is to skip !online nodes in
cpuset_mem_spread_node(). However I'm a bit worried about 58568d2.
Personally, I like just revert at once than bandaid. 58568d2 didn't introduce any new feature, then we can revet it without abi breakage.
This test result seems patch author didn't test his own patch enough much.
thanks.
Quoted 21 lines
It is doing a lot of stuff. It is removing the
callback_mutexfrom around several seemingly unrelated places (eg. from aroundguarnatee_online_cpus, which explicitly asks to be called with that lock held), and other places, so I don't know how it is not racy with hotplug.Then it also says that the fastpath doesn't use any locking, so the update-path first adds the newly allowed nodes, then removes the newly prohibited nodes. Unfortunately there are no barriers apparent (and none added), and cpumask/nodemask can be larger than one word, so it seems there could be races.
It also seems like the exported
cpuset_mems_allowedandcpuset_cpus_allowedAPIs are just broken wrt hotplug because the hotplug lock is dropped before returning.I'd just like to get opinions or comments from people who know the code better before wading in too far myself. I'd be really keen on making the locking simpler, using seqlocks for fastpaths, etc.
Quoted 8 lines
Thanks,
Nick--
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>
--
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 3 lines · KOSAKI Motohiro
Personally, I like just revert at once than bandaid. 58568d2 didn't introduce any new feature, then we can revet it without abi breakage.
Revert a commit from more than six months ago when the fix is probably a small patch in cpuset_attach()? I think we can do better than that.
This may not have introduced a new feature, but it was a worthwhile change to avoid the old cpuset_update_task_memory_state() hooks in mempolicy, page allocator, etc. code that could block on callback_mutex for iterating the hierarchy.
--
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 51 lines · On Fri, 19 Feb 2010 00:49:21 +1100 Nick Piggin <[email protected]> wrote:
Hi,
The patch cpuset,mm: update tasks'
mems_allowedin time (58568d2) causes a regression uncovered by SGI. Basically it is allowing possible but not online nodes in the task_struct.mems_allowed nodemask (which is contrary to several comments still inkernel/cpuset.c), and that causescpuset_mem_spread_node()to return an offline node to slab, causing an oops.Easy to reproduce if you have a machine with !online nodes.
- mkdir
/dev/cpuset
- mount cpuset -t cpuset/dev/cpuset
- echo 1 >/dev/cpuset/memory_spread_slabkernel BUG at
/usr/src/packages/BUILD/kernel-default-2.6.32/linux-2.6.32/mm/slab.c:3271! bash[6885]: bugcheck! 0 [1]
Pid: 6885, CPU 5, comm: bash
psr :00001010095a2010ifs :800000000000038bip : [<a00000010020cf00>]Tainted: G W (2.6.32-0.6.8-default) ip is at ____cache_alloc_node+0x440/0x500unat: 0000000000000000 pfs :
000000000000038brsc : 0000000000000003
rnat:0000000000283d85bsps: 0000000000000001 pr :99596aaa69aa6999
ldrs: 0000000000000000 ccv : 0000000000000018 fpsr:0009804c0270033fcsd : 0000000000000000 ssd : 0000000000000000
b0 :a00000010020cf00b6 :a0000001004962c0b7 :a000000100493240f6 : 000000000000000000000 f7 : 000000000000000000000 f8 : 000000000000000000000 f9 : 000000000000000000000 f10 : 000000000000000000000 f11 : 000000000000000000000 r1 :a0000001015c6fc0r2 :000000000000e662r3 :000000000000fffer8 :000000000000005cr9 : 0000000000000000 r10 : 0000000000004000 r11 : 0000000000000000 r12 :e000003c3904fcc0r13 :e000003c39040000r14 :000000000000e662r15 :a00000010138ed88r16 :ffffffffffff65c8r17 :a00000010138ed80r18 :a0000001013c7ad0r19 :a0000001013d3b60r20 :e00001b03afdfe18r21 : 0000000000000001 r22 :e0000130030365c8r23 :e000013003040000r24 :ffffffffffff0400r25 :00000000000068efr26 :00000000000068efr27 :a0000001029621d0r28 :00000000000068f0r29 :00000000000068f0r30 :00000000000068f0r31 :000000000000000aCall Trace: [<a000000100017a80>] show_stack+0x80/0xa0 [<a0000001000180e0>] show_regs+0x640/0x920 [<a000000100029a90>] die+0x190/0x2e0 [<a000000100029c30>] die_if_kernel+0x50/0x80 [<a000000100904af0>] ia64_bad_break+0x470/0x760 [<a00000010000cb60>] ia64_native_leave_kernel+0x0/0x270 [<a00000010020cf00>] ____cache_alloc_node+0x440/0x500 [<a00000010020ffa0>] kmem_cache_alloc+0x360/0x660
Quoted 1 line
A simple bandaid is to skip !online nodes in
cpuset_mem_spread_node().
I think that's good.
Quoted 7 lines
However I'm a bit worried about 58568d2.
It is doing a lot of stuff. It is removing the
callback_mutexfrom around several seemingly unrelated places (eg. from aroundguarnatee_online_cpus, which explicitly asks to be called with that lock held), and other places, so I don't know how it is not racy with hotplug.
Because removing pgdat is not archieved yet. It was verrrry difficult.. So, once node become online, it never turns to be offline. But all pages on the node are removed. Just zonelists are rebuilded. (zonelist rebuild uses stop_machine_run.
Quoted 7 lines
Then it also says that the fastpath doesn't use any locking, so the update-path first adds the newly allowed nodes, then removes the newly prohibited nodes. Unfortunately there are no barriers apparent (and none added), and cpumask/nodemask can be larger than one word, so it seems there could be races.
Maybe. IMHO, "newly allowed node" and "newly prohobited node" come from user's command. We don't need to guarantee correctness.
So, our concerns is only "don't access offlined node". Right ? But as I wrote, a node once onlined will never be offlined. So, I think it's difficult to cause panic.
My concern is zonelist rather than bitmap. But I hear no panic report about update of it until now. (Maybe because "struct zone" is never freed.)
Quoted 4 lines
It also seems like the exported
cpuset_mems_allowedandcpuset_cpus_allowedAPIs are just broken wrt hotplug because the hotplug lock is dropped before returning.
About cpu, it can disappear...then, it should be fixed.
Quoted 4 lines
I'd just like to get opinions or comments from people who know the code better before wading in too far myself. I'd be really keen on making the locking simpler, using seqlocks for fastpaths, etc.
Thanks,
-Kame