diff options
author | Avi Kivity <avi@redhat.com> | 2012-07-26 04:54:21 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2012-07-26 04:54:21 -0400 |
commit | e9bda6f6f902e6b55d9baceb5523468a048cbe56 (patch) | |
tree | bf09cc165da1197cd34967da0593d08b9a37c0f3 /arch/x86/kvm/mmu.c | |
parent | bdc0077af574800d24318b6945cf2344e8dbb050 (diff) | |
parent | 06e48c510aa37f6e791602e6420422ea7071fe94 (diff) |
Merge branch 'queue' into next
Merge patches queued during the run-up to the merge window.
* queue: (25 commits)
KVM: Choose better candidate for directed yield
KVM: Note down when cpu relax intercepted or pause loop exited
KVM: Add config to support ple or cpu relax optimzation
KVM: switch to symbolic name for irq_states size
KVM: x86: Fix typos in pmu.c
KVM: x86: Fix typos in lapic.c
KVM: x86: Fix typos in cpuid.c
KVM: x86: Fix typos in emulate.c
KVM: x86: Fix typos in x86.c
KVM: SVM: Fix typos
KVM: VMX: Fix typos
KVM: remove the unused parameter of gfn_to_pfn_memslot
KVM: remove is_error_hpa
KVM: make bad_pfn static to kvm_main.c
KVM: using get_fault_pfn to get the fault pfn
KVM: MMU: track the refcount when unmap the page
KVM: x86: remove unnecessary mark_page_dirty
KVM: MMU: Avoid handling same rmap_pde in kvm_handle_hva_range()
KVM: MMU: Push trace_kvm_age_page() into kvm_age_rmapp()
KVM: MMU: Add memslot parameter to hva handlers
...
Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/x86/kvm/mmu.c')
-rw-r--r-- | arch/x86/kvm/mmu.c | 117 |
1 files changed, 78 insertions, 39 deletions
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 01ca00423938..241993443599 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c | |||
@@ -556,6 +556,14 @@ static int mmu_spte_clear_track_bits(u64 *sptep) | |||
556 | return 0; | 556 | return 0; |
557 | 557 | ||
558 | pfn = spte_to_pfn(old_spte); | 558 | pfn = spte_to_pfn(old_spte); |
559 | |||
560 | /* | ||
561 | * KVM does not hold the refcount of the page used by | ||
562 | * kvm mmu, before reclaiming the page, we should | ||
563 | * unmap it from mmu first. | ||
564 | */ | ||
565 | WARN_ON(!kvm_is_mmio_pfn(pfn) && !page_count(pfn_to_page(pfn))); | ||
566 | |||
559 | if (!shadow_accessed_mask || old_spte & shadow_accessed_mask) | 567 | if (!shadow_accessed_mask || old_spte & shadow_accessed_mask) |
560 | kvm_set_pfn_accessed(pfn); | 568 | kvm_set_pfn_accessed(pfn); |
561 | if (!shadow_dirty_mask || (old_spte & shadow_dirty_mask)) | 569 | if (!shadow_dirty_mask || (old_spte & shadow_dirty_mask)) |
@@ -960,13 +968,13 @@ static void pte_list_walk(unsigned long *pte_list, pte_list_walk_fn fn) | |||
960 | static unsigned long *__gfn_to_rmap(gfn_t gfn, int level, | 968 | static unsigned long *__gfn_to_rmap(gfn_t gfn, int level, |
961 | struct kvm_memory_slot *slot) | 969 | struct kvm_memory_slot *slot) |
962 | { | 970 | { |
963 | struct kvm_lpage_info *linfo; | 971 | unsigned long idx; |
964 | 972 | ||
965 | if (likely(level == PT_PAGE_TABLE_LEVEL)) | 973 | if (likely(level == PT_PAGE_TABLE_LEVEL)) |
966 | return &slot->rmap[gfn - slot->base_gfn]; | 974 | return &slot->rmap[gfn - slot->base_gfn]; |
967 | 975 | ||
968 | linfo = lpage_info_slot(gfn, slot, level); | 976 | idx = gfn_to_index(gfn, slot->base_gfn, level); |
969 | return &linfo->rmap_pde; | 977 | return &slot->arch.rmap_pde[level - PT_DIRECTORY_LEVEL][idx]; |
970 | } | 978 | } |
971 | 979 | ||
972 | /* | 980 | /* |
@@ -1200,7 +1208,7 @@ static bool rmap_write_protect(struct kvm *kvm, u64 gfn) | |||
1200 | } | 1208 | } |
1201 | 1209 | ||
1202 | static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp, | 1210 | static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp, |
1203 | unsigned long data) | 1211 | struct kvm_memory_slot *slot, unsigned long data) |
1204 | { | 1212 | { |
1205 | u64 *sptep; | 1213 | u64 *sptep; |
1206 | struct rmap_iterator iter; | 1214 | struct rmap_iterator iter; |
@@ -1218,7 +1226,7 @@ static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp, | |||
1218 | } | 1226 | } |
1219 | 1227 | ||
1220 | static int kvm_set_pte_rmapp(struct kvm *kvm, unsigned long *rmapp, | 1228 | static int kvm_set_pte_rmapp(struct kvm *kvm, unsigned long *rmapp, |
1221 | unsigned long data) | 1229 | struct kvm_memory_slot *slot, unsigned long data) |
1222 | { | 1230 | { |
1223 | u64 *sptep; | 1231 | u64 *sptep; |
1224 | struct rmap_iterator iter; | 1232 | struct rmap_iterator iter; |
@@ -1259,43 +1267,67 @@ static int kvm_set_pte_rmapp(struct kvm *kvm, unsigned long *rmapp, | |||
1259 | return 0; | 1267 | return 0; |
1260 | } | 1268 | } |
1261 | 1269 | ||
1262 | static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, | 1270 | static int kvm_handle_hva_range(struct kvm *kvm, |
1263 | unsigned long data, | 1271 | unsigned long start, |
1264 | int (*handler)(struct kvm *kvm, unsigned long *rmapp, | 1272 | unsigned long end, |
1265 | unsigned long data)) | 1273 | unsigned long data, |
1274 | int (*handler)(struct kvm *kvm, | ||
1275 | unsigned long *rmapp, | ||
1276 | struct kvm_memory_slot *slot, | ||
1277 | unsigned long data)) | ||
1266 | { | 1278 | { |
1267 | int j; | 1279 | int j; |
1268 | int ret; | 1280 | int ret = 0; |
1269 | int retval = 0; | ||
1270 | struct kvm_memslots *slots; | 1281 | struct kvm_memslots *slots; |
1271 | struct kvm_memory_slot *memslot; | 1282 | struct kvm_memory_slot *memslot; |
1272 | 1283 | ||
1273 | slots = kvm_memslots(kvm); | 1284 | slots = kvm_memslots(kvm); |
1274 | 1285 | ||
1275 | kvm_for_each_memslot(memslot, slots) { | 1286 | kvm_for_each_memslot(memslot, slots) { |
1276 | unsigned long start = memslot->userspace_addr; | 1287 | unsigned long hva_start, hva_end; |
1277 | unsigned long end; | 1288 | gfn_t gfn_start, gfn_end; |
1278 | 1289 | ||
1279 | end = start + (memslot->npages << PAGE_SHIFT); | 1290 | hva_start = max(start, memslot->userspace_addr); |
1280 | if (hva >= start && hva < end) { | 1291 | hva_end = min(end, memslot->userspace_addr + |
1281 | gfn_t gfn_offset = (hva - start) >> PAGE_SHIFT; | 1292 | (memslot->npages << PAGE_SHIFT)); |
1282 | gfn_t gfn = memslot->base_gfn + gfn_offset; | 1293 | if (hva_start >= hva_end) |
1294 | continue; | ||
1295 | /* | ||
1296 | * {gfn(page) | page intersects with [hva_start, hva_end)} = | ||
1297 | * {gfn_start, gfn_start+1, ..., gfn_end-1}. | ||
1298 | */ | ||
1299 | gfn_start = hva_to_gfn_memslot(hva_start, memslot); | ||
1300 | gfn_end = hva_to_gfn_memslot(hva_end + PAGE_SIZE - 1, memslot); | ||
1283 | 1301 | ||
1284 | ret = handler(kvm, &memslot->rmap[gfn_offset], data); | 1302 | for (j = PT_PAGE_TABLE_LEVEL; |
1303 | j < PT_PAGE_TABLE_LEVEL + KVM_NR_PAGE_SIZES; ++j) { | ||
1304 | unsigned long idx, idx_end; | ||
1305 | unsigned long *rmapp; | ||
1285 | 1306 | ||
1286 | for (j = 0; j < KVM_NR_PAGE_SIZES - 1; ++j) { | 1307 | /* |
1287 | struct kvm_lpage_info *linfo; | 1308 | * {idx(page_j) | page_j intersects with |
1309 | * [hva_start, hva_end)} = {idx, idx+1, ..., idx_end}. | ||
1310 | */ | ||
1311 | idx = gfn_to_index(gfn_start, memslot->base_gfn, j); | ||
1312 | idx_end = gfn_to_index(gfn_end - 1, memslot->base_gfn, j); | ||
1288 | 1313 | ||
1289 | linfo = lpage_info_slot(gfn, memslot, | 1314 | rmapp = __gfn_to_rmap(gfn_start, j, memslot); |
1290 | PT_DIRECTORY_LEVEL + j); | 1315 | |
1291 | ret |= handler(kvm, &linfo->rmap_pde, data); | 1316 | for (; idx <= idx_end; ++idx) |
1292 | } | 1317 | ret |= handler(kvm, rmapp++, memslot, data); |
1293 | trace_kvm_age_page(hva, memslot, ret); | ||
1294 | retval |= ret; | ||
1295 | } | 1318 | } |
1296 | } | 1319 | } |
1297 | 1320 | ||
1298 | return retval; | 1321 | return ret; |
1322 | } | ||
1323 | |||
1324 | static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, | ||
1325 | unsigned long data, | ||
1326 | int (*handler)(struct kvm *kvm, unsigned long *rmapp, | ||
1327 | struct kvm_memory_slot *slot, | ||
1328 | unsigned long data)) | ||
1329 | { | ||
1330 | return kvm_handle_hva_range(kvm, hva, hva + 1, data, handler); | ||
1299 | } | 1331 | } |
1300 | 1332 | ||
1301 | int kvm_unmap_hva(struct kvm *kvm, unsigned long hva) | 1333 | int kvm_unmap_hva(struct kvm *kvm, unsigned long hva) |
@@ -1303,13 +1335,18 @@ int kvm_unmap_hva(struct kvm *kvm, unsigned long hva) | |||
1303 | return kvm_handle_hva(kvm, hva, 0, kvm_unmap_rmapp); | 1335 | return kvm_handle_hva(kvm, hva, 0, kvm_unmap_rmapp); |
1304 | } | 1336 | } |
1305 | 1337 | ||
1338 | int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end) | ||
1339 | { | ||
1340 | return kvm_handle_hva_range(kvm, start, end, 0, kvm_unmap_rmapp); | ||
1341 | } | ||
1342 | |||
1306 | void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte) | 1343 | void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte) |
1307 | { | 1344 | { |
1308 | kvm_handle_hva(kvm, hva, (unsigned long)&pte, kvm_set_pte_rmapp); | 1345 | kvm_handle_hva(kvm, hva, (unsigned long)&pte, kvm_set_pte_rmapp); |
1309 | } | 1346 | } |
1310 | 1347 | ||
1311 | static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp, | 1348 | static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp, |
1312 | unsigned long data) | 1349 | struct kvm_memory_slot *slot, unsigned long data) |
1313 | { | 1350 | { |
1314 | u64 *sptep; | 1351 | u64 *sptep; |
1315 | struct rmap_iterator uninitialized_var(iter); | 1352 | struct rmap_iterator uninitialized_var(iter); |
@@ -1323,8 +1360,10 @@ static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp, | |||
1323 | * This has some overhead, but not as much as the cost of swapping | 1360 | * This has some overhead, but not as much as the cost of swapping |
1324 | * out actively used pages or breaking up actively used hugepages. | 1361 | * out actively used pages or breaking up actively used hugepages. |
1325 | */ | 1362 | */ |
1326 | if (!shadow_accessed_mask) | 1363 | if (!shadow_accessed_mask) { |
1327 | return kvm_unmap_rmapp(kvm, rmapp, data); | 1364 | young = kvm_unmap_rmapp(kvm, rmapp, slot, data); |
1365 | goto out; | ||
1366 | } | ||
1328 | 1367 | ||
1329 | for (sptep = rmap_get_first(*rmapp, &iter); sptep; | 1368 | for (sptep = rmap_get_first(*rmapp, &iter); sptep; |
1330 | sptep = rmap_get_next(&iter)) { | 1369 | sptep = rmap_get_next(&iter)) { |
@@ -1336,12 +1375,14 @@ static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp, | |||
1336 | (unsigned long *)sptep); | 1375 | (unsigned long *)sptep); |
1337 | } | 1376 | } |
1338 | } | 1377 | } |
1339 | 1378 | out: | |
1379 | /* @data has hva passed to kvm_age_hva(). */ | ||
1380 | trace_kvm_age_page(data, slot, young); | ||
1340 | return young; | 1381 | return young; |
1341 | } | 1382 | } |
1342 | 1383 | ||
1343 | static int kvm_test_age_rmapp(struct kvm *kvm, unsigned long *rmapp, | 1384 | static int kvm_test_age_rmapp(struct kvm *kvm, unsigned long *rmapp, |
1344 | unsigned long data) | 1385 | struct kvm_memory_slot *slot, unsigned long data) |
1345 | { | 1386 | { |
1346 | u64 *sptep; | 1387 | u64 *sptep; |
1347 | struct rmap_iterator iter; | 1388 | struct rmap_iterator iter; |
@@ -1379,13 +1420,13 @@ static void rmap_recycle(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn) | |||
1379 | 1420 | ||
1380 | rmapp = gfn_to_rmap(vcpu->kvm, gfn, sp->role.level); | 1421 | rmapp = gfn_to_rmap(vcpu->kvm, gfn, sp->role.level); |
1381 | 1422 | ||
1382 | kvm_unmap_rmapp(vcpu->kvm, rmapp, 0); | 1423 | kvm_unmap_rmapp(vcpu->kvm, rmapp, NULL, 0); |
1383 | kvm_flush_remote_tlbs(vcpu->kvm); | 1424 | kvm_flush_remote_tlbs(vcpu->kvm); |
1384 | } | 1425 | } |
1385 | 1426 | ||
1386 | int kvm_age_hva(struct kvm *kvm, unsigned long hva) | 1427 | int kvm_age_hva(struct kvm *kvm, unsigned long hva) |
1387 | { | 1428 | { |
1388 | return kvm_handle_hva(kvm, hva, 0, kvm_age_rmapp); | 1429 | return kvm_handle_hva(kvm, hva, hva, kvm_age_rmapp); |
1389 | } | 1430 | } |
1390 | 1431 | ||
1391 | int kvm_test_age_hva(struct kvm *kvm, unsigned long hva) | 1432 | int kvm_test_age_hva(struct kvm *kvm, unsigned long hva) |
@@ -2472,14 +2513,12 @@ static pfn_t pte_prefetch_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn, | |||
2472 | unsigned long hva; | 2513 | unsigned long hva; |
2473 | 2514 | ||
2474 | slot = gfn_to_memslot_dirty_bitmap(vcpu, gfn, no_dirty_log); | 2515 | slot = gfn_to_memslot_dirty_bitmap(vcpu, gfn, no_dirty_log); |
2475 | if (!slot) { | 2516 | if (!slot) |
2476 | get_page(fault_page); | 2517 | return get_fault_pfn(); |
2477 | return page_to_pfn(fault_page); | ||
2478 | } | ||
2479 | 2518 | ||
2480 | hva = gfn_to_hva_memslot(slot, gfn); | 2519 | hva = gfn_to_hva_memslot(slot, gfn); |
2481 | 2520 | ||
2482 | return hva_to_pfn_atomic(vcpu->kvm, hva); | 2521 | return hva_to_pfn_atomic(hva); |
2483 | } | 2522 | } |
2484 | 2523 | ||
2485 | static int direct_pte_prefetch_many(struct kvm_vcpu *vcpu, | 2524 | static int direct_pte_prefetch_many(struct kvm_vcpu *vcpu, |