summaryrefslogtreecommitdiff
path: root/arch/s390/kernel
diff options
context:
space:
mode:
authorHeiko Carstens <heiko.carstens@de.ibm.com>2012-09-04 12:26:03 (GMT)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2012-09-26 13:45:08 (GMT)
commitfade4dc49101e3b68fb375fd2b00d0ef1f31a36f (patch)
tree302bd25e0575ce0b0ad33e34378577ad506bb786 /arch/s390/kernel
parent34cda99260247873df53ae00885fb0f426b149a5 (diff)
downloadlinux-fade4dc49101e3b68fb375fd2b00d0ef1f31a36f.tar.xz
s390/sysinfo,topology: fix cpu topology maximum nesting detection
The maximum nesting of the cpu topology is evaluated when /proc/sysinfo is the first time read. This happens without a lock and a concurrent reader on a different cpu can see and use an invalid intermediate value. Besides the fact that this race is quite unlikely the worst thing that could happen is that /proc/sysinfo would contain bogus information about the machine's cpu topology. Nevertheless this should be fixed. So move the detection code to the early machine detection code and since now the value is early available use it in the topology code as well. Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/kernel')
-rw-r--r--arch/s390/kernel/early.c27
-rw-r--r--arch/s390/kernel/sysinfo.c12
-rw-r--r--arch/s390/kernel/topology.c10
3 files changed, 29 insertions, 20 deletions
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c
index 1345ba4..f4bcdc0 100644
--- a/arch/s390/kernel/early.c
+++ b/arch/s390/kernel/early.c
@@ -215,26 +215,44 @@ static noinline __init void init_kernel_storage_key(void)
PAGE_DEFAULT_KEY, 0);
}
-static __initdata struct sysinfo_3_2_2 vmms __aligned(PAGE_SIZE);
+static __initdata char sysinfo_page[PAGE_SIZE] __aligned(PAGE_SIZE);
static noinline __init void detect_machine_type(void)
{
+ struct sysinfo_3_2_2 *vmms = (struct sysinfo_3_2_2 *)&sysinfo_page;
+
/* Check current-configuration-level */
if ((stsi(NULL, 0, 0, 0) >> 28) <= 2) {
S390_lowcore.machine_flags |= MACHINE_FLAG_LPAR;
return;
}
/* Get virtual-machine cpu information. */
- if (stsi(&vmms, 3, 2, 2) == -ENOSYS || !vmms.count)
+ if (stsi(vmms, 3, 2, 2) == -ENOSYS || !vmms->count)
return;
/* Running under KVM? If not we assume z/VM */
- if (!memcmp(vmms.vm[0].cpi, "\xd2\xe5\xd4", 3))
+ if (!memcmp(vmms->vm[0].cpi, "\xd2\xe5\xd4", 3))
S390_lowcore.machine_flags |= MACHINE_FLAG_KVM;
else
S390_lowcore.machine_flags |= MACHINE_FLAG_VM;
}
+static __init void setup_topology(void)
+{
+#ifdef CONFIG_64BIT
+ int max_mnest;
+
+ if (!test_facility(11))
+ return;
+ S390_lowcore.machine_flags |= MACHINE_FLAG_TOPOLOGY;
+ for (max_mnest = 6; max_mnest > 1; max_mnest--) {
+ if (stsi(&sysinfo_page, 15, 1, max_mnest) != -ENOSYS)
+ break;
+ }
+ topology_max_mnest = max_mnest;
+#endif
+}
+
static void early_pgm_check_handler(void)
{
unsigned long addr;
@@ -364,8 +382,6 @@ static __init void detect_machine_facilities(void)
S390_lowcore.machine_flags |= MACHINE_FLAG_IDTE;
if (test_facility(8))
S390_lowcore.machine_flags |= MACHINE_FLAG_PFMF;
- if (test_facility(11))
- S390_lowcore.machine_flags |= MACHINE_FLAG_TOPOLOGY;
if (test_facility(27))
S390_lowcore.machine_flags |= MACHINE_FLAG_MVCOS;
if (test_facility(40))
@@ -467,6 +483,7 @@ void __init startup_init(void)
detect_diag44();
detect_machine_facilities();
setup_hpage();
+ setup_topology();
sclp_facilities_detect();
detect_memory_layout(memory_chunk);
#ifdef CONFIG_DYNAMIC_FTRACE
diff --git a/arch/s390/kernel/sysinfo.c b/arch/s390/kernel/sysinfo.c
index 2249b0c..2af4ee6 100644
--- a/arch/s390/kernel/sysinfo.c
+++ b/arch/s390/kernel/sysinfo.c
@@ -22,6 +22,8 @@
#include <math-emu/soft-fp.h>
#include <math-emu/single.h>
+int topology_max_mnest;
+
static inline int stsi_0(void)
{
int rc = stsi(NULL, 0, 0, 0);
@@ -95,15 +97,7 @@ static void stsi_15_1_x(struct seq_file *m, struct sysinfo_15_1_x *info)
seq_putc(m, '\n');
if (!MACHINE_HAS_TOPOLOGY)
return;
- if (max_mnest) {
- stsi(info, 15, 1, max_mnest);
- } else {
- for (max_mnest = 6; max_mnest > 1; max_mnest--) {
- rc = stsi(info, 15, 1, max_mnest);
- if (rc != -ENOSYS)
- break;
- }
- }
+ stsi(info, 15, 1, topology_max_mnest);
seq_printf(m, "CPU Topology HW: ");
for (i = 0; i < TOPOLOGY_NR_MAG; i++)
seq_printf(m, " %d", info->mag[i]);
diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c
index fc957f2..80ca4ba 100644
--- a/arch/s390/kernel/topology.c
+++ b/arch/s390/kernel/topology.c
@@ -251,12 +251,10 @@ static void update_cpu_core_map(void)
void store_topology(struct sysinfo_15_1_x *info)
{
- int rc;
-
- rc = stsi(info, 15, 1, 3);
- if (rc != -ENOSYS)
- return;
- stsi(info, 15, 1, 2);
+ if (topology_max_mnest >= 3)
+ stsi(info, 15, 1, 3);
+ else
+ stsi(info, 15, 1, 2);
}
int arch_update_cpu_topology(void)