Skip to contentSkip to conversation

cpumask_of_node() should handle -1 as a node

PATCH Applied Anton Blanchard 7 participants 22 messages Jan 6, 2010 – Jan 14, 2010

Subsystems (5)
x86 PowerPC MIPS x86 MM +1 more subsystems
lore
Share & tools
lore
#0 lore raw

cover cpumask_of_node() should handle -1 as a node

A number of places in the kernel use cpumask_of_node(-1), but most arch NUMA implementations are broken. The following patches fix this.

Apologies for the resend, somehow quilt mail screwed up the message ids.

#1 lore raw

PATCH 1/6 powerpc: cpumask_of_node() should handle -1 as a node

pcibus_to_node can return -1 if we cannot determine which node a pci bus is on. If passed -1, cpumask_of_node will negatively index the lookup array and pull in random data:

# cat /sys/devices/pci0000:00/0000:00:01.0/local_cpus
00000000,00000003,00000000,00000000
# cat /sys/devices/pci0000:00/0000:00:01.0/local_cpulist
64-65

Change cpumask_of_node to check for -1 and return cpu_all_mask in this case:

# cat /sys/devices/pci0000:00/0000:00:01.0/local_cpus
ffffffff,ffffffff,ffffffff,ffffffff
# cat /sys/devices/pci0000:00/0000:00:01.0/local_cpulist
0-127

---

arch/powerpc/include/asm/topology.h +3 -1
Index: linux-cpumask/arch/powerpc/include/asm/topology.h
===================================================================
@@ -17,7 +17,9 @@ static inline int cpu_to_node(int cpu)
 
 #define parent_node(node)	(node)
 
-#define cpumask_of_node(node) (&numa_cpumask_lookup_table[node])
+#define cpumask_of_node(node) ((node) == -1 ?				\
+			       cpu_all_mask :				\
+			       &numa_cpumask_lookup_table[node])
 
 int of_node_to_nid(struct device_node *device);
 
#2 lore raw

PATCH 2/6 alpha: cpumask_of_node() should handle -1 as a node

In reply to Anton Blanchard

pcibus_to_node can return -1 if we cannot determine which node a pci bus is on. If passed -1, cpumask_of_node will negatively index the lookup array and pull in random data:

# cat /sys/devices/pci0000:00/0000:00:01.0/local_cpus
00000000,00000003,00000000,00000000
# cat /sys/devices/pci0000:00/0000:00:01.0/local_cpulist
64-65

Change cpumask_of_node to check for -1 and return cpu_all_mask in this case:

# cat /sys/devices/pci0000:00/0000:00:01.0/local_cpus
ffffffff,ffffffff,ffffffff,ffffffff
# cat /sys/devices/pci0000:00/0000:00:01.0/local_cpulist
0-127

---

arch/alpha/include/asm/topology.h +3 -0
Index: linux-cpumask/arch/alpha/include/asm/topology.h
===================================================================
@@ -28,6 +28,9 @@ static const struct cpumask *cpumask_of_
 {
 	int cpu;
 
+	if (node == -1)
+		return cpu_all_mask;
+
 	cpumask_clear(&node_to_cpumask_map[node]);
 
 	for_each_online_cpu(cpu) {
maintainer
#3 lore raw

Re: [patch 2/6] alpha: cpumask_of_node() should handle -1 as a node

Quoted 26 lines · Anton Blanchard

pcibus_to_node can return -1 if we cannot determine which node a pci bus is on. If passed -1, cpumask_of_node will negatively index the lookup array and pull in random data:

# cat /sys/devices/pci0000:00/0000:00:01.0/local_cpus
00000000,00000003,00000000,00000000
# cat /sys/devices/pci0000:00/0000:00:01.0/local_cpulist
64-65

Change cpumask_of_node to check for -1 and return cpu_all_mask in this case:

# cat /sys/devices/pci0000:00/0000:00:01.0/local_cpus
ffffffff,ffffffff,ffffffff,ffffffff
# cat /sys/devices/pci0000:00/0000:00:01.0/local_cpulist
0-127

---

Index: linux-cpumask/arch/alpha/include/asm/topology.h
===================================================================

arch/alpha/include/asm/topology.h     2010-01-06 15:20:46.610083557 +1100 renamed from arch/alpha/include/asm/topology.h        2010-01-06 15:20:22.952583839 +1100 +0 -0
@@ -28,6 +28,9 @@ static const struct cpumask *cpumask_of_
  {

arch/alpha/include/asm/topology.h     2010-01-06 15:20:46.610083557 +1100 static const struct cpumask *cpumask_of_

Quoted 10 lines
arch/alpha/include/asm/topology.h     2010-01-06 15:20:46.610083557 +1100 renamed from arch/alpha/include/asm/topology.h        2010-01-06 15:20:22.952583839 +1100 +3 -1
        int cpu;
 
+       if (node == -1)
+               return cpu_all_mask;
+
        cpumask_clear(&node_to_cpumask_map[node]);
 
        for_each_online_cpu(cpu) {
 
--

Thanks! I've added this to alpha-2.6.

Matt
--
To unsubscribe from this list: send the line "unsubscribe linux-alpha" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#4 lore raw

PATCH 3/6 ia64: cpumask_of_node() should handle -1 as a node

In reply to Anton Blanchard

pcibus_to_node can return -1 if we cannot determine which node a pci bus is on. If passed -1, cpumask_of_node will negatively index the lookup array and pull in random data:

# cat /sys/devices/pci0000:00/0000:00:01.0/local_cpus
00000000,00000003,00000000,00000000
# cat /sys/devices/pci0000:00/0000:00:01.0/local_cpulist
64-65

Change cpumask_of_node to check for -1 and return cpu_all_mask in this case:

# cat /sys/devices/pci0000:00/0000:00:01.0/local_cpus
ffffffff,ffffffff,ffffffff,ffffffff
# cat /sys/devices/pci0000:00/0000:00:01.0/local_cpulist
0-127

---

Index: linux-cpumask/arch/ia64/include/asm/topology.h
=================================--- linux-cpumask.orig/arch/ia64/include/asm/topology.h 2010-01-06 15:20:22.832584260 +1100
+++ linux-cpumask/arch/ia64/include/asm/topology.h 2010-01-06 15:26:46.620650121 +1100
@@ -33,7 +33,9 @@
/*
* Returns a bitmask of CPUs on Node 'node'. */
-#define cpumask_of_node(node) (&node_to_cpu_mask[node])
+#define cpumask_of_node(node) ((node) = -1 ? \
+ cpu_all_mask : \
+ &node_to_cpu_mask[node])

/*
* Returns the number of the node containing Node 'nid'.

#5 lore raw

PATCH 4/6 mips: cpumask_of_node() should handle -1 as a node

In reply to Anton Blanchard

pcibus_to_node can return -1 if we cannot determine which node a pci bus is on. If passed -1, cpumask_of_node will negatively index the lookup array and pull in random data:

# cat /sys/devices/pci0000:00/0000:00:01.0/local_cpus
00000000,00000003,00000000,00000000
# cat /sys/devices/pci0000:00/0000:00:01.0/local_cpulist
64-65

Change cpumask_of_node to check for -1 and return cpu_all_mask in this case:

# cat /sys/devices/pci0000:00/0000:00:01.0/local_cpus
ffffffff,ffffffff,ffffffff,ffffffff
# cat /sys/devices/pci0000:00/0000:00:01.0/local_cpulist
0-127

---

arch/mips/include/asm/mach-ip27/topology.h +3 -1
Index: linux-cpumask/arch/mips/include/asm/mach-ip27/topology.h
===================================================================
@@ -24,7 +24,9 @@ extern struct cpuinfo_ip27 sn_cpu_info[N
 
 #define cpu_to_node(cpu)	(sn_cpu_info[(cpu)].p_nodeid)
 #define parent_node(node)	(node)
-#define cpumask_of_node(node)	(&hub_data(node)->h_cpus)
+#define cpumask_of_node(node)	((node) == -1 ?				\
+				 cpu_all_mask :				\
+				 &hub_data(node)->h_cpus)
 struct pci_bus;
 extern int pcibus_to_node(struct pci_bus *);
 
Applied
#6 lore raw

Re: [patch 4/6] mips: cpumask_of_node() should handle -1 as a node

Quoted 1 line · Anton Blanchard

Subject: [patch 4/6] mips: cpumask_of_node() should handle -1 as a node

Thanks, applied!

Ralf

#7 lore raw

PATCH 5/6 sparc: cpumask_of_node() should handle -1 as a node

In reply to Anton Blanchard

pcibus_to_node can return -1 if we cannot determine which node a pci bus is on. If passed -1, cpumask_of_node will negatively index the lookup array and pull in random data:

# cat /sys/devices/pci0000:00/0000:00:01.0/local_cpus
00000000,00000003,00000000,00000000
# cat /sys/devices/pci0000:00/0000:00:01.0/local_cpulist
64-65

Change cpumask_of_node to check for -1 and return cpu_all_mask in this case:

# cat /sys/devices/pci0000:00/0000:00:01.0/local_cpus
ffffffff,ffffffff,ffffffff,ffffffff
# cat /sys/devices/pci0000:00/0000:00:01.0/local_cpulist
0-127

---

Index: linux-cpumask/arch/sparc/include/asm/topology_64.h
=================================--- linux-cpumask.orig/arch/sparc/include/asm/topology_64.h 2010-01-06 15:20:22.912584116 +1100
+++ linux-cpumask/arch/sparc/include/asm/topology_64.h 2010-01-06 15:27:17.209419879 +1100
@@ -12,7 +12,9 @@ static inline int cpu_to_node(int cpu)

#define parent_node(node) (node)

-#define cpumask_of_node(node) (&numa_cpumask_lookup_table[node])
+#define cpumask_of_node(node) ((node) = -1 ? \
+ cpu_all_mask : \
+ &numa_cpumask_lookup_table[node])

struct pci_bus;
#ifdef CONFIG_PCI

Acked-by on v1 5/6
#8 lore raw

Re: [patch 5/6] sparc: cpumask_of_node() should handle -1 as a node

From: Anton Blanchard <[email protected]>
Date: Wed, 06 Jan 2010 15:55:14 +1100

Quoted 12 lines

pcibus_to_node can return -1 if we cannot determine which node a pci bus is on. If passed -1, cpumask_of_node will negatively index the lookup array and pull in random data:

# cat /sys/devices/pci0000:00/0000:00:01.0/local_cpus
00000000,00000003,00000000,00000000
# cat /sys/devices/pci0000:00/0000:00:01.0/local_cpulist
64-65

Change cpumask_of_node to check for -1 and return cpu_all_mask in this case:

Quoted 6 lines
# cat /sys/devices/pci0000:00/0000:00:01.0/local_cpus
ffffffff,ffffffff,ffffffff,ffffffff
# cat /sys/devices/pci0000:00/0000:00:01.0/local_cpulist
0-127
#9 lore raw

PATCH 6/6 x86: cpumask_of_node() should handle -1 as a node

In reply to Anton Blanchard

pcibus_to_node can return -1 if we cannot determine which node a pci bus is on. If passed -1, cpumask_of_node will negatively index the lookup array and pull in random data:

# cat /sys/devices/pci0000:00/0000:00:01.0/local_cpus
00000000,00000003,00000000,00000000
# cat /sys/devices/pci0000:00/0000:00:01.0/local_cpulist
64-65

Change cpumask_of_node to check for -1 and return cpu_all_mask in this case:

# cat /sys/devices/pci0000:00/0000:00:01.0/local_cpus
ffffffff,ffffffff,ffffffff,ffffffff
# cat /sys/devices/pci0000:00/0000:00:01.0/local_cpulist
0-127

---

arch/x86/include/asm/topology.h +2 -1
index c5087d7..cc4f136 100644
@@ -99,7 +99,8 @@ extern const struct cpumask *cpumask_of_node(int node);
 /* Returns a pointer to the cpumask of CPUs on Node 'node'. */
 static inline const struct cpumask *cpumask_of_node(int node)
 {
-	return node_to_cpumask_map[node];
+	return (node == -1) ? cpu_all_mask :
+		node_to_cpumask_map[node];
 }
 #endif
 
arch/x86/mm/numa.c +3 -0
index 550df48..e57a7f5 100644
@@ -47,6 +47,9 @@ void __init setup_node_to_cpumask_map(void)
  */
 const struct cpumask *cpumask_of_node(int node)
 {
+	if (node == -1)
+		return cpu_all_mask;
+
 	if (node >= nr_node_ids) {
 		printk(KERN_WARNING
 			"cpumask_of_node(%d): node > nr_node_ids(%d)\n",
#10 lore raw

Re: [patch 6/6] x86: cpumask_of_node() should handle -1 as a node

Quoted 3 lines · Anton Blanchard

pcibus_to_node can return -1 if we cannot determine which node a pci bus is on. If passed -1, cpumask_of_node will negatively index the lookup array and pull in random data:

If you grep for the callers, you'll see those which do this (now-obsolete) check. One more patch :)

Thanks,
Rusty.

#11 lore raw

Re: [patch 6/6] x86: cpumask_of_node() should handle -1 as a node

Quoted 7 lines · Rusty Russell
Quoted 3 lines

pcibus_to_node can return -1 if we cannot determine which node a pci bus is on. If passed -1, cpumask_of_node will negatively index the lookup array and pull in random data:

If you grep for the callers, you'll see those which do this (now-obsolete) check. One more patch :)

Do we really want to do this? A nid of -1 is undefined, so the result of cpumask_of_node(-1) should be undefined; there's no formal definition that a nid of -1 follows the semantics that we use for x86 pci buses, for example, where it implies no NUMA locality in all cases.

I think a better fix would be to define -1 where appropriate to either be an invalid node, cpu_all_mask, or whatever in the caller:

	mask = (nid != -1) ? cpumask_of_node(nid) : cpu_all_mask;
#12 lore raw

Re: [patch 6/6] x86: cpumask_of_node() should handle -1 as a node

Hi David,

Quoted 4 lines

Do we really want to do this? A nid of -1 is undefined, so the result of cpumask_of_node(-1) should be undefined; there's no formal definition that a nid of -1 follows the semantics that we use for x86 pci buses, for example, where it implies no NUMA locality in all cases.

I don't like the use of -1 as a node, but it's much more widespread than x86; including sh, powerpc, sparc and the generic topology code. eg:

#fdef CONFIG_PCI
extern int pcibus_to_node(struct pci_bus *pbus); #else
static inline int pcibus_to_node(struct pci_bus *pbus)

{
        return -1;
}

It would be nice to get rid of this special case but I suspect that's not 2.6.33 material.

Speaking of invalid node ids, I also noticed the scheduler isn't using node iterators:

        for (i = 0; i < nr_node_ids; i++) {

which should be fixed at some stage too since it doesn't allow us to allocate the node structures sparsely.

Anton

#13 lore raw

Re: [patch 6/6] x86: cpumask_of_node() should handle -1 as a node

Quoted 11 lines · Anton Blanchard

I don't like the use of -1 as a node, but it's much more widespread than x86; including sh, powerpc, sparc and the generic topology code. eg:

#fdef CONFIG_PCI
extern int pcibus_to_node(struct pci_bus *pbus); #else
static inline int pcibus_to_node(struct pci_bus *pbus)

{
        return -1;
}

This seems to be the same semantics that NUMA_NO_NODE was defined for, it's not necessarily a special case.

Regardless, the result of cpumask_of_node(NUMA_NO_NODE) should be undefined as it currently is unless you want to obsolete NUMA_NO_NODE entirely which is much more work. In other words, special-casing a nid of -1 to mean no affinity is inappropriate if NUMA_NO_NODE represents an invalid nid.

If x86 pci buses want to use -1 to imply that meaning, that's fine, but it shouldn't be coded in a generic interface such as cpumask_of_node(). Does that make sense?

Quoted 8 lines

Speaking of invalid node ids, I also noticed the scheduler isn't using node iterators:

        for (i = 0; i < nr_node_ids; i++) {

which should be fixed at some stage too since it doesn't allow us to allocate the node structures sparsely.

That loop has nothing to do with the allocation of a node structure, it's quite plausible that it checks for various states such as node_online(i) while looping and doing something else interesting for those that are offline. Keep in mind that this isn't equivalent to using for_each_node() since that only iterates over N_POSSIBLE which is architecture specific.

#14 lore raw

Re: [patch 6/6] x86: cpumask_of_node() should handle -1 as a node

Hi David,

Quoted 9 lines

This seems to be the same semantics that NUMA_NO_NODE was defined for, it's not necessarily a special case.

Regardless, the result of cpumask_of_node(NUMA_NO_NODE) should be undefined as it currently is unless you want to obsolete NUMA_NO_NODE entirely which is much more work. In other words, special-casing a nid of -1 to mean no affinity is inappropriate if NUMA_NO_NODE represents an invalid nid.

Quoted 3 lines

If x86 pci buses want to use -1 to imply that meaning, that's fine, but it shouldn't be coded in a generic interface such as cpumask_of_node(). Does that make sense?

I wasn't using the example to strengthen the case of the -1 behaviour, but to highlight that a complete fix would be more work and risk not making it back to -stable.

I'm all for removing the special case as a followon patch.

Quoted 5 lines
Quoted 5 lines

Speaking of invalid node ids, I also noticed the scheduler isn't using node iterators:

        for (i = 0; i < nr_node_ids; i++) {
Quoted 8 lines
Quoted 2 lines

which should be fixed at some stage too since it doesn't allow us to allocate the node structures sparsely.

That loop has nothing to do with the allocation of a node structure, it's quite plausible that it checks for various states such as node_online(i) while looping and doing something else interesting for those that are offline. Keep in mind that this isn't equivalent to using for_each_node() since that only iterates over N_POSSIBLE which is architecture specific.

Yeah I understand it isn't the same thing, but the scheduler oopses in a number of places with CPUMASK_OFFSTACK and sparse node ids, so things that can be switched to node iterators should and node_online() checks should be added elsewhere.

Anton

#15 lore raw

Re: [patch 6/6] x86: cpumask_of_node() should handle -1 as a node

Quoted 4 lines · Anton Blanchard

I wasn't using the example to strengthen the case of the -1 behaviour, but to highlight that a complete fix would be more work and risk not making it back to -stable.

I don't think that we should defer a complete fix to the callers because it's "more work." If you've identified places where -1 is passed to cpumask_of_node() without being checked, I think those would be fairly obvious -stable candidates themselves instead of this series.

#16 lore raw

Re: [patch 6/6] x86: cpumask_of_node() should handle -1 as a node

In reply to David Rientjes
Quoted 14 lines · David Rientjes
Quoted 11 lines · Anton Blanchard

I don't like the use of -1 as a node, but it's much more widespread than x86; including sh, powerpc, sparc and the generic topology code. eg:

#fdef CONFIG_PCI
extern int pcibus_to_node(struct pci_bus *pbus); #else
static inline int pcibus_to_node(struct pci_bus *pbus)

{
        return -1;
}
Quoted 2 lines

This seems to be the same semantics that NUMA_NO_NODE was defined for, it's not necessarily a special case.

It's widespread, and we've just had another bug due to pcibus_to_node handling -1 and cpumask_of_node not. (Search lkml for subject "[Regression] 2.6.33-rc2
- pci: Commit e0cd516 causes OOPS").

So I think the evidence is in favor of just handling -1.

Cheers,
Rusty.

#17 lore raw

Re: [patch 6/6] x86: cpumask_of_node() should handle -1 as a node

Quoted 15 lines · Rusty Russell
Quoted 14 lines · David Rientjes
Quoted 11 lines · Anton Blanchard

I don't like the use of -1 as a node, but it's much more widespread than x86; including sh, powerpc, sparc and the generic topology code. eg:

#fdef CONFIG_PCI
extern int pcibus_to_node(struct pci_bus *pbus); #else
static inline int pcibus_to_node(struct pci_bus *pbus)

{
        return -1;
}
Quoted 7 lines
Quoted 2 lines

This seems to be the same semantics that NUMA_NO_NODE was defined for, it's not necessarily a special case.

It's widespread, and we've just had another bug due to pcibus_to_node handling -1 and cpumask_of_node not. (Search lkml for subject "[Regression] 2.6.33-rc2
- pci: Commit e0cd516 causes OOPS").

That's similiar to the problem in cpumask_of_pcibus() that I fixed with 7715a1e back in September. The difference is that I isolated my fix to the pci bus implementation that defined the nid of -1 to mean no NUMA affinity, whereas generic kernel code can use that value for any (or no) definition and returning cpu_all_mask may not apply. We know it does for pcibus, but not for generic NUMA node ids that happen to be invald.

The hope is that eventually we can remove many dependencies on node ids for these purposes; buses with no affinity are not actually members of any NUMA node. I had a proposal for a generic kernel interface that is based on ACPI system localities that would define the proximity of any system entity (of which node is only a type defining "memory") to each other. I'm waiting for enough time to work on that project.

NUMA is special because a single cpu is always a member of a single node, so we're violating the bidirectional mapping by saying that node -1 maps to all cpus while all cpus don't map to node -1. In other words, I think we should take this as an opportunity to find and fix broken callers as we've done both by my patch from September and by your aforementioned case. In this particular case, it would be a matter of doing:

	mask = (nid != -1) ? cpumask_of_node(nid) : cpu_all_mask;

I'm hoping that Ingo will weigh in on this topic with his taste and vision for how we should decouple device locality information from entities that are not members of any NUMA node if we continue to "special case" these things.

#18 lore raw

Re: [patch 6/6] x86: cpumask_of_node() should handle -1 as a node

In reply to Rusty Russell

Hi Rusty,

Quoted 2 lines

If you grep for the callers, you'll see those which do this (now-obsolete) check. One more patch :)

Good point. I was hoping to have a chance at a -stable backport, so I'll do this cleanup in a follow up patch.

Anton

#19 lore raw
In reply to Anton Blanchard
Quoted 3 lines · On Wed, 06 Jan 2010 15:55:09 +1100 Anton Blanchard <[email protected]> wrote:

A number of places in the kernel use cpumask_of_node(-1), but most arch NUMA implementations are broken. The following patches fix this.

So.. what's happening here? Nobody has applied the patches anywhere, you later said "the scheduler oopses in a number of places with CPUMASK_OFFSTACK and sparse node ids" and mention of a -stable backport was mentioned.

#20 lore raw

Hi Andrew,

Quoted 7 lines
Quoted 2 lines

A number of places in the kernel use cpumask_of_node(-1), but most arch NUMA implementations are broken. The following patches fix this.

So.. what's happening here? Nobody has applied the patches anywhere, you later said "the scheduler oopses in a number of places with CPUMASK_OFFSTACK and sparse node ids" and mention of a -stable backport was mentioned.

That scheduler issue doesn't appear in mainline as no one is allocating sparse node IDs yet.

There is still the opportunity for an Oops with CPUMASK_OFFSTACK and /sys/.../local_cpus and even with CPUMASK_OFFSTACK disabled it will return random data.

Ralph has picked up the mips bit, Ben is sucking in the powerpc bit. Davem has acked the sparc bit. I'll roll up a -stable patch once they hit.

No answer from alpha and ia64.

Anton

#21 lore raw
In reply to Andrew Morton

Hi,

Quoted 4 lines

So.. what's happening here? Nobody has applied the patches anywhere, you later said "the scheduler oopses in a number of places with CPUMASK_OFFSTACK and sparse node ids" and mention of a -stable backport was mentioned.

Just checked and it's already upstream on ia64. That just leaves alpha.

Anton