diff options
author | Avi Kivity <avi@qumranet.com> | 2007-06-07 12:18:30 -0400 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2007-07-16 05:05:46 -0400 |
commit | d9e368d61263055eceac2966bb7ea31b89da3425 (patch) | |
tree | 9d507b851ea7bd667cdd50dde640e47e0d4773e9 /drivers/kvm/kvm_main.c | |
parent | 39c3b86e5c193e09f69f0e99c93600a4999ffc60 (diff) |
KVM: Flush remote tlbs when reducing shadow pte permissions
When a vcpu causes a shadow tlb entry to have reduced permissions, it
must also clear the tlb on remote vcpus. We do that by:
- setting a bit on the vcpu that requests a tlb flush before the next entry
- if the vcpu is currently executing, we send an ipi to make sure it
exits before we continue
Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers/kvm/kvm_main.c')
-rw-r--r-- | drivers/kvm/kvm_main.c | 44 |
1 files changed, 44 insertions, 0 deletions
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c index 4e1a017f3db7..633c2eded08d 100644 --- a/drivers/kvm/kvm_main.c +++ b/drivers/kvm/kvm_main.c | |||
@@ -41,6 +41,8 @@ | |||
41 | #include <linux/fs.h> | 41 | #include <linux/fs.h> |
42 | #include <linux/mount.h> | 42 | #include <linux/mount.h> |
43 | #include <linux/sched.h> | 43 | #include <linux/sched.h> |
44 | #include <linux/cpumask.h> | ||
45 | #include <linux/smp.h> | ||
44 | 46 | ||
45 | #include "x86_emulate.h" | 47 | #include "x86_emulate.h" |
46 | #include "segment_descriptor.h" | 48 | #include "segment_descriptor.h" |
@@ -309,6 +311,48 @@ static void vcpu_put(struct kvm_vcpu *vcpu) | |||
309 | mutex_unlock(&vcpu->mutex); | 311 | mutex_unlock(&vcpu->mutex); |
310 | } | 312 | } |
311 | 313 | ||
314 | static void ack_flush(void *_completed) | ||
315 | { | ||
316 | atomic_t *completed = _completed; | ||
317 | |||
318 | atomic_inc(completed); | ||
319 | } | ||
320 | |||
321 | void kvm_flush_remote_tlbs(struct kvm *kvm) | ||
322 | { | ||
323 | int i, cpu, needed; | ||
324 | cpumask_t cpus; | ||
325 | struct kvm_vcpu *vcpu; | ||
326 | atomic_t completed; | ||
327 | |||
328 | atomic_set(&completed, 0); | ||
329 | cpus_clear(cpus); | ||
330 | needed = 0; | ||
331 | for (i = 0; i < kvm->nvcpus; ++i) { | ||
332 | vcpu = &kvm->vcpus[i]; | ||
333 | if (test_and_set_bit(KVM_TLB_FLUSH, &vcpu->requests)) | ||
334 | continue; | ||
335 | cpu = vcpu->cpu; | ||
336 | if (cpu != -1 && cpu != raw_smp_processor_id()) | ||
337 | if (!cpu_isset(cpu, cpus)) { | ||
338 | cpu_set(cpu, cpus); | ||
339 | ++needed; | ||
340 | } | ||
341 | } | ||
342 | |||
343 | /* | ||
344 | * We really want smp_call_function_mask() here. But that's not | ||
345 | * available, so ipi all cpus in parallel and wait for them | ||
346 | * to complete. | ||
347 | */ | ||
348 | for (cpu = first_cpu(cpus); cpu != NR_CPUS; cpu = next_cpu(cpu, cpus)) | ||
349 | smp_call_function_single(cpu, ack_flush, &completed, 1, 0); | ||
350 | while (atomic_read(&completed) != needed) { | ||
351 | cpu_relax(); | ||
352 | barrier(); | ||
353 | } | ||
354 | } | ||
355 | |||
312 | static struct kvm *kvm_create_vm(void) | 356 | static struct kvm *kvm_create_vm(void) |
313 | { | 357 | { |
314 | struct kvm *kvm = kzalloc(sizeof(struct kvm), GFP_KERNEL); | 358 | struct kvm *kvm = kzalloc(sizeof(struct kvm), GFP_KERNEL); |