aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorMarcelo Tosatti <mtosatti@redhat.com>2009-12-23 11:35:23 -0500
committerMarcelo Tosatti <mtosatti@redhat.com>2010-03-01 10:35:45 -0500
commita983fb238728e1123177e8058d4f644b949a7d05 (patch)
tree55f9b26d8ace10a1233b293dd423eae2d0ff9046 /arch/x86
parentb050b015abbef8225826eecb6f6b4d4a6dea7b79 (diff)
KVM: x86: switch kvm_set_memory_alias to SRCU update
Using a similar two-step procedure as for memslots. Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/include/asm/kvm_host.h4
-rw-r--r--arch/x86/kvm/x86.c60
2 files changed, 55 insertions, 9 deletions
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 7cdcb3d0f770..6c8c7c578c46 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -368,8 +368,12 @@ struct kvm_mem_alias {
368 gfn_t base_gfn; 368 gfn_t base_gfn;
369 unsigned long npages; 369 unsigned long npages;
370 gfn_t target_gfn; 370 gfn_t target_gfn;
371#define KVM_ALIAS_INVALID 1UL
372 unsigned long flags;
371}; 373};
372 374
375#define KVM_ARCH_HAS_UNALIAS_INSTANTIATION
376
373struct kvm_mem_aliases { 377struct kvm_mem_aliases {
374 struct kvm_mem_alias aliases[KVM_ALIAS_SLOTS]; 378 struct kvm_mem_alias aliases[KVM_ALIAS_SLOTS];
375 int naliases; 379 int naliases;
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index e7488350ca16..28127c936c3b 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -38,6 +38,7 @@
38#include <linux/intel-iommu.h> 38#include <linux/intel-iommu.h>
39#include <linux/cpufreq.h> 39#include <linux/cpufreq.h>
40#include <linux/user-return-notifier.h> 40#include <linux/user-return-notifier.h>
41#include <linux/srcu.h>
41#include <trace/events/kvm.h> 42#include <trace/events/kvm.h>
42#undef TRACE_INCLUDE_FILE 43#undef TRACE_INCLUDE_FILE
43#define CREATE_TRACE_POINTS 44#define CREATE_TRACE_POINTS
@@ -2223,11 +2224,32 @@ static int kvm_vm_ioctl_get_nr_mmu_pages(struct kvm *kvm)
2223 return kvm->arch.n_alloc_mmu_pages; 2224 return kvm->arch.n_alloc_mmu_pages;
2224} 2225}
2225 2226
2227gfn_t unalias_gfn_instantiation(struct kvm *kvm, gfn_t gfn)
2228{
2229 int i;
2230 struct kvm_mem_alias *alias;
2231 struct kvm_mem_aliases *aliases;
2232
2233 aliases = rcu_dereference(kvm->arch.aliases);
2234
2235 for (i = 0; i < aliases->naliases; ++i) {
2236 alias = &aliases->aliases[i];
2237 if (alias->flags & KVM_ALIAS_INVALID)
2238 continue;
2239 if (gfn >= alias->base_gfn
2240 && gfn < alias->base_gfn + alias->npages)
2241 return alias->target_gfn + gfn - alias->base_gfn;
2242 }
2243 return gfn;
2244}
2245
2226gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn) 2246gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn)
2227{ 2247{
2228 int i; 2248 int i;
2229 struct kvm_mem_alias *alias; 2249 struct kvm_mem_alias *alias;
2230 struct kvm_mem_aliases *aliases = kvm->arch.aliases; 2250 struct kvm_mem_aliases *aliases;
2251
2252 aliases = rcu_dereference(kvm->arch.aliases);
2231 2253
2232 for (i = 0; i < aliases->naliases; ++i) { 2254 for (i = 0; i < aliases->naliases; ++i) {
2233 alias = &aliases->aliases[i]; 2255 alias = &aliases->aliases[i];
@@ -2248,7 +2270,7 @@ static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm,
2248{ 2270{
2249 int r, n; 2271 int r, n;
2250 struct kvm_mem_alias *p; 2272 struct kvm_mem_alias *p;
2251 struct kvm_mem_aliases *aliases; 2273 struct kvm_mem_aliases *aliases, *old_aliases;
2252 2274
2253 r = -EINVAL; 2275 r = -EINVAL;
2254 /* General sanity checks */ 2276 /* General sanity checks */
@@ -2265,28 +2287,48 @@ static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm,
2265 < alias->target_phys_addr) 2287 < alias->target_phys_addr)
2266 goto out; 2288 goto out;
2267 2289
2290 r = -ENOMEM;
2291 aliases = kzalloc(sizeof(struct kvm_mem_aliases), GFP_KERNEL);
2292 if (!aliases)
2293 goto out;
2294
2268 down_write(&kvm->slots_lock); 2295 down_write(&kvm->slots_lock);
2269 spin_lock(&kvm->mmu_lock);
2270 2296
2271 aliases = kvm->arch.aliases; 2297 /* invalidate any gfn reference in case of deletion/shrinking */
2298 memcpy(aliases, kvm->arch.aliases, sizeof(struct kvm_mem_aliases));
2299 aliases->aliases[alias->slot].flags |= KVM_ALIAS_INVALID;
2300 old_aliases = kvm->arch.aliases;
2301 rcu_assign_pointer(kvm->arch.aliases, aliases);
2302 synchronize_srcu_expedited(&kvm->srcu);
2303 kvm_mmu_zap_all(kvm);
2304 kfree(old_aliases);
2305
2306 r = -ENOMEM;
2307 aliases = kzalloc(sizeof(struct kvm_mem_aliases), GFP_KERNEL);
2308 if (!aliases)
2309 goto out_unlock;
2310
2311 memcpy(aliases, kvm->arch.aliases, sizeof(struct kvm_mem_aliases));
2272 2312
2273 p = &aliases->aliases[alias->slot]; 2313 p = &aliases->aliases[alias->slot];
2274 p->base_gfn = alias->guest_phys_addr >> PAGE_SHIFT; 2314 p->base_gfn = alias->guest_phys_addr >> PAGE_SHIFT;
2275 p->npages = alias->memory_size >> PAGE_SHIFT; 2315 p->npages = alias->memory_size >> PAGE_SHIFT;
2276 p->target_gfn = alias->target_phys_addr >> PAGE_SHIFT; 2316 p->target_gfn = alias->target_phys_addr >> PAGE_SHIFT;
2317 p->flags &= ~(KVM_ALIAS_INVALID);
2277 2318
2278 for (n = KVM_ALIAS_SLOTS; n > 0; --n) 2319 for (n = KVM_ALIAS_SLOTS; n > 0; --n)
2279 if (aliases->aliases[n - 1].npages) 2320 if (aliases->aliases[n - 1].npages)
2280 break; 2321 break;
2281 aliases->naliases = n; 2322 aliases->naliases = n;
2282 2323
2283 spin_unlock(&kvm->mmu_lock); 2324 old_aliases = kvm->arch.aliases;
2284 kvm_mmu_zap_all(kvm); 2325 rcu_assign_pointer(kvm->arch.aliases, aliases);
2326 synchronize_srcu_expedited(&kvm->srcu);
2327 kfree(old_aliases);
2328 r = 0;
2285 2329
2330out_unlock:
2286 up_write(&kvm->slots_lock); 2331 up_write(&kvm->slots_lock);
2287
2288 return 0;
2289
2290out: 2332out:
2291 return r; 2333 return r;
2292} 2334}