s390/sysinfo,topology: fix cpu topology maximum nesting detection
authorHeiko Carstens <heiko.carstens@de.ibm.com>
Tue, 4 Sep 2012 12:26:03 +0000 (14:26 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Wed, 26 Sep 2012 13:45:08 +0000 (15:45 +0200)
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>
arch/s390/include/asm/sysinfo.h
arch/s390/kernel/early.c
arch/s390/kernel/sysinfo.c
arch/s390/kernel/topology.c

index 12e5256adca34390d69e2f3f722051c953caff35..04e6e9774708cb7301cc8e37ae46f3dbbca0799d 100644 (file)
@@ -118,6 +118,8 @@ struct sysinfo_3_2_2 {
        char reserved_544[3552];
 };
 
+extern int topology_max_mnest;
+
 #define TOPOLOGY_CPU_BITS      64
 #define TOPOLOGY_NR_MAG                6
 
index 1345ba452c83f6bd8cb305620205086452af1fe0..f4bcdc01bfc81309c6302fae2f6eae023a7668e1 100644 (file)
@@ -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
index 2249b0cf80ef22c0ff33f6226f7c5241394ecd2b..2af4ee67fe52a1bbdc4228dc1d0f034cba651368 100644 (file)
@@ -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]);
index fc957f2eef7c1071ed06bc83e8599d2a30e69b1e..80ca4ba759f65fdd3e42b019ae88d3adec91cd58 100644 (file)
@@ -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)