@@ -103,6 +103,57 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
return 0;
}
+struct sync_stop_machine_data {
+ atomic_t begin;
+ atomic_t end;
+ int (*fn)(void *);
+ void *data;
+};
+
+static int __kprobes __sync_stop_machine(void *data)
+{
+ struct sync_stop_machine_data *ssmd;
+ int ret;
+
+ ssmd = (struct sync_stop_machine_data *)data;
+
+ /* Wait until all CPUs are ready before calling the function */
+ atomic_dec(&ssmd->begin);
+ smp_mb__after_atomic_dec();
+ while (atomic_read(&ssmd->begin)) {}
+
+ ret = ssmd->fn(ssmd->data);
+
+ /* Wait for all CPUs to finish 'fn' before returning */
+ smp_mb__before_atomic_dec();
+ atomic_dec(&ssmd->end);
+ while (atomic_read(&ssmd->end)) {}
+
+ return ret;
+}
+
+static int __kprobes sync_stop_machine(int (*fn)(void *), void *data)
+{
+ struct sync_stop_machine_data ssmd = {
+ .fn = fn,
+ .data = data
+ };
+ int num_cpus;
+ int ret;
+
+ get_online_cpus(); /* So number of CPUs can't change */
+
+ num_cpus = num_online_cpus();
+ atomic_set(&ssmd.begin, num_cpus);
+ atomic_set(&ssmd.end, num_cpus);
+ smp_wmb();
+
+ ret = stop_machine(__sync_stop_machine, &ssmd, &cpu_online_map);
+
+ put_online_cpus();
+ return ret;
+}
+
#ifdef CONFIG_THUMB2_KERNEL
/*
@@ -127,7 +178,7 @@ void __kprobes arch_arm_kprobe(struct kprobe *p)
flush_insns(addr, sizeof(u16));
} else if (addr & 2) {
/* A 32-bit instruction spanning two words needs special care */
- stop_machine(set_t32_breakpoint, (void *)addr, &cpu_online_map);
+ sync_stop_machine(set_t32_breakpoint, (void *)addr);
} else {
/* Word aligned 32-bit instruction can be written atomically */
u32 bkp = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION;
@@ -190,7 +241,7 @@ int __kprobes __arch_disarm_kprobe(void *p)
void __kprobes arch_disarm_kprobe(struct kprobe *p)
{
- stop_machine(__arch_disarm_kprobe, p, &cpu_online_map);
+ sync_stop_machine(__arch_disarm_kprobe, p);
}
void __kprobes arch_remove_kprobe(struct kprobe *p)