@@ -195,6 +195,12 @@ static void kvmppc_pte_free(pte_t *ptep)
195
195
kmem_cache_free (kvm_pte_cache , ptep );
196
196
}
197
197
198
+ /* Like pmd_huge() and pmd_large(), but works regardless of config options */
199
+ static inline int pmd_is_leaf (pmd_t pmd )
200
+ {
201
+ return !!(pmd_val (pmd ) & _PAGE_PTE );
202
+ }
203
+
198
204
static int kvmppc_create_pte (struct kvm * kvm , pte_t pte , unsigned long gpa ,
199
205
unsigned int level , unsigned long mmu_seq )
200
206
{
@@ -219,7 +225,7 @@ static int kvmppc_create_pte(struct kvm *kvm, pte_t pte, unsigned long gpa,
219
225
else
220
226
new_pmd = pmd_alloc_one (kvm -> mm , gpa );
221
227
222
- if (level == 0 && !(pmd && pmd_present (* pmd )))
228
+ if (level == 0 && !(pmd && pmd_present (* pmd ) && ! pmd_is_leaf ( * pmd ) ))
223
229
new_ptep = kvmppc_pte_alloc ();
224
230
225
231
/* Check if we might have been invalidated; let the guest retry if so */
@@ -244,12 +250,30 @@ static int kvmppc_create_pte(struct kvm *kvm, pte_t pte, unsigned long gpa,
244
250
new_pmd = NULL ;
245
251
}
246
252
pmd = pmd_offset (pud , gpa );
247
- if (pmd_large (* pmd )) {
248
- /* Someone else has instantiated a large page here; retry */
249
- ret = - EAGAIN ;
250
- goto out_unlock ;
251
- }
252
- if (level == 1 && !pmd_none (* pmd )) {
253
+ if (pmd_is_leaf (* pmd )) {
254
+ unsigned long lgpa = gpa & PMD_MASK ;
255
+
256
+ /*
257
+ * If we raced with another CPU which has just put
258
+ * a 2MB pte in after we saw a pte page, try again.
259
+ */
260
+ if (level == 0 && !new_ptep ) {
261
+ ret = - EAGAIN ;
262
+ goto out_unlock ;
263
+ }
264
+ /* Valid 2MB page here already, remove it */
265
+ old = kvmppc_radix_update_pte (kvm , pmdp_ptep (pmd ),
266
+ ~0UL , 0 , lgpa , PMD_SHIFT );
267
+ kvmppc_radix_tlbie_page (kvm , lgpa , PMD_SHIFT );
268
+ if (old & _PAGE_DIRTY ) {
269
+ unsigned long gfn = lgpa >> PAGE_SHIFT ;
270
+ struct kvm_memory_slot * memslot ;
271
+ memslot = gfn_to_memslot (kvm , gfn );
272
+ if (memslot && memslot -> dirty_bitmap )
273
+ kvmppc_update_dirty_map (memslot ,
274
+ gfn , PMD_SIZE );
275
+ }
276
+ } else if (level == 1 && !pmd_none (* pmd )) {
253
277
/*
254
278
* There's a page table page here, but we wanted
255
279
* to install a large page. Tell the caller and let
@@ -412,28 +436,24 @@ int kvmppc_book3s_radix_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
412
436
} else {
413
437
page = pages [0 ];
414
438
pfn = page_to_pfn (page );
415
- if (PageHuge (page )) {
416
- page = compound_head (page );
417
- pte_size <<= compound_order (page );
439
+ if (PageCompound (page )) {
440
+ pte_size <<= compound_order (compound_head (page ));
418
441
/* See if we can insert a 2MB large-page PTE here */
419
442
if (pte_size >= PMD_SIZE &&
420
- (gpa & PMD_MASK & PAGE_MASK ) ==
421
- (hva & PMD_MASK & PAGE_MASK )) {
443
+ (gpa & ( PMD_SIZE - PAGE_SIZE ) ) ==
444
+ (hva & ( PMD_SIZE - PAGE_SIZE ) )) {
422
445
level = 1 ;
423
446
pfn &= ~((PMD_SIZE >> PAGE_SHIFT ) - 1 );
424
447
}
425
448
}
426
449
/* See if we can provide write access */
427
450
if (writing ) {
428
- /*
429
- * We assume gup_fast has set dirty on the host PTE.
430
- */
431
451
pgflags |= _PAGE_WRITE ;
432
452
} else {
433
453
local_irq_save (flags );
434
454
ptep = find_current_mm_pte (current -> mm -> pgd ,
435
455
hva , NULL , NULL );
436
- if (ptep && pte_write (* ptep ) && pte_dirty ( * ptep ) )
456
+ if (ptep && pte_write (* ptep ))
437
457
pgflags |= _PAGE_WRITE ;
438
458
local_irq_restore (flags );
439
459
}
@@ -459,18 +479,15 @@ int kvmppc_book3s_radix_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
459
479
pte = pfn_pte (pfn , __pgprot (pgflags ));
460
480
ret = kvmppc_create_pte (kvm , pte , gpa , level , mmu_seq );
461
481
}
462
- if (ret == 0 || ret == - EAGAIN )
463
- ret = RESUME_GUEST ;
464
482
465
483
if (page ) {
466
- /*
467
- * We drop pages[0] here, not page because page might
468
- * have been set to the head page of a compound, but
469
- * we have to drop the reference on the correct tail
470
- * page to match the get inside gup()
471
- */
472
- put_page (pages [0 ]);
484
+ if (!ret && (pgflags & _PAGE_WRITE ))
485
+ set_page_dirty_lock (page );
486
+ put_page (page );
473
487
}
488
+
489
+ if (ret == 0 || ret == - EAGAIN )
490
+ ret = RESUME_GUEST ;
474
491
return ret ;
475
492
}
476
493
@@ -644,7 +661,7 @@ void kvmppc_free_radix(struct kvm *kvm)
644
661
continue ;
645
662
pmd = pmd_offset (pud , 0 );
646
663
for (im = 0 ; im < PTRS_PER_PMD ; ++ im , ++ pmd ) {
647
- if (pmd_huge (* pmd )) {
664
+ if (pmd_is_leaf (* pmd )) {
648
665
pmd_clear (pmd );
649
666
continue ;
650
667
}
0 commit comments