stop_machine: fix error code handling on multiple cpus
authorHeiko Carstens <heiko.carstens@de.ibm.com>
Wed, 22 Oct 2008 15:00:26 +0000 (10:00 -0500)
committerRusty Russell <rusty@rustcorp.com.au>
Tue, 21 Oct 2008 23:00:26 +0000 (10:00 +1100)
Using |= for updating a value which might be updated on several cpus
concurrently will not always work since we need to make sure that the
update happens atomically.
To fix this just use a write if the called function returns an error
code on a cpu. We end up writing the error code of an arbitrary cpu
if multiple ones fail but that should be sufficient.

Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
kernel/stop_machine.c

index 0e688c6a1a63d22d6b034de5af7b2891c1df2aad..8aff79d90ddccd3647cb884664920e45c609fe72 100644 (file)
@@ -66,6 +66,7 @@ static void stop_cpu(struct work_struct *unused)
        enum stopmachine_state curstate = STOPMACHINE_NONE;
        struct stop_machine_data *smdata = &idle;
        int cpu = smp_processor_id();
+       int err;
 
        if (!active_cpus) {
                if (cpu == first_cpu(cpu_online_map))
@@ -86,9 +87,11 @@ static void stop_cpu(struct work_struct *unused)
                                hard_irq_disable();
                                break;
                        case STOPMACHINE_RUN:
-                               /* |= allows error detection if functions on
-                                * multiple CPUs. */
-                               smdata->fnret |= smdata->fn(smdata->data);
+                               /* On multiple CPUs only a single error code
+                                * is needed to tell that something failed. */
+                               err = smdata->fn(smdata->data);
+                               if (err)
+                                       smdata->fnret = err;
                                break;
                        default:
                                break;