diff options
Diffstat (limited to 'sys/kern/subr_smp.c')
-rw-r--r-- | sys/kern/subr_smp.c | 55 |
1 files changed, 52 insertions, 3 deletions
diff --git a/sys/kern/subr_smp.c b/sys/kern/subr_smp.c index 3614798..77d1b2b 100644 --- a/sys/kern/subr_smp.c +++ b/sys/kern/subr_smp.c @@ -225,6 +225,18 @@ generic_stop_cpus(cpuset_t map, u_int type) CTR2(KTR_SMP, "stop_cpus(%s) with %u type", cpusetobj_strprint(cpusetbuf, &map), type); +#ifdef XENHVM + /* + * When migrating a PVHVM domain we need to make sure there are + * no IPIs in progress. IPIs that have been issued, but not + * yet delivered (not pending on a vCPU) will be lost in the + * IPI rebinding process, violating FreeBSD's assumption of + * reliable IPI delivery. + */ + if (type == IPI_SUSPEND) + mtx_lock_spin(&smp_ipi_mtx); +#endif + if (stopping_cpu != PCPU_GET(cpuid)) while (atomic_cmpset_int(&stopping_cpu, NOCPU, PCPU_GET(cpuid)) == 0) @@ -252,6 +264,11 @@ generic_stop_cpus(cpuset_t map, u_int type) } } +#ifdef XENHVM + if (type == IPI_SUSPEND) + mtx_unlock_spin(&smp_ipi_mtx); +#endif + stopping_cpu = NOCPU; return (1); } @@ -292,28 +309,60 @@ suspend_cpus(cpuset_t map) * 0: NA * 1: ok */ -int -restart_cpus(cpuset_t map) +static int +generic_restart_cpus(cpuset_t map, u_int type) { #ifdef KTR char cpusetbuf[CPUSETBUFSIZ]; #endif + volatile cpuset_t *cpus; + + KASSERT( +#if defined(__amd64__) || defined(__i386__) + type == IPI_STOP || type == IPI_STOP_HARD || type == IPI_SUSPEND, +#else + type == IPI_STOP || type == IPI_STOP_HARD, +#endif + ("%s: invalid stop type", __func__)); if (!smp_started) return 0; CTR1(KTR_SMP, "restart_cpus(%s)", cpusetobj_strprint(cpusetbuf, &map)); +#if defined(__amd64__) || defined(__i386__) + if (type == IPI_SUSPEND) + cpus = &suspended_cpus; + else +#endif + cpus = &stopped_cpus; + /* signal other cpus to restart */ CPU_COPY_STORE_REL(&map, &started_cpus); /* wait for each to clear its bit */ - while (CPU_OVERLAP(&stopped_cpus, &map)) + while (CPU_OVERLAP(cpus, &map)) cpu_spinwait(); return 1; } +int +restart_cpus(cpuset_t map) +{ + + return (generic_restart_cpus(map, IPI_STOP)); +} + +#if defined(__amd64__) || defined(__i386__) +int +resume_cpus(cpuset_t map) +{ + + return (generic_restart_cpus(map, IPI_SUSPEND)); +} +#endif + /* * All-CPU rendezvous. CPUs are signalled, all execute the setup function * (if specified), rendezvous, execute the action function (if specified), |