Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

KVM: s390: Fix gmap_link()

The slow path of the fault handler ultimately called gmap_link(), which
assumed the fault was a major fault, and blindly called dat_link().

In case of minor faults, things were not always handled properly; in
particular the prefix and vsie marker bits were ignored.

Move dat_link() into gmap.c, renaming it accordingly. Once moved, the
new _gmap_link() function will be able to correctly honour the prefix
and vsie markers.

This will cause spurious unshadows in some uncommon cases.

Fixes: 94fd9b16cc67 ("KVM: s390: KVM page table management functions: lifecycle management")
Fixes: a2c17f9270cc ("KVM: s390: New gmap code")
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>

+52 -54
-48
arch/s390/kvm/dat.c
··· 997 997 return _dat_walk_gfn_range(start, end, asce, &test_age_ops, 0, NULL) > 0; 998 998 } 999 999 1000 - int dat_link(struct kvm_s390_mmu_cache *mc, union asce asce, int level, 1001 - bool uses_skeys, struct guest_fault *f) 1002 - { 1003 - union crste oldval, newval; 1004 - union pte newpte, oldpte; 1005 - union pgste pgste; 1006 - int rc = 0; 1007 - 1008 - rc = dat_entry_walk(mc, f->gfn, asce, DAT_WALK_ALLOC_CONTINUE, level, &f->crstep, &f->ptep); 1009 - if (rc == -EINVAL || rc == -ENOMEM) 1010 - return rc; 1011 - if (rc) 1012 - return -EAGAIN; 1013 - 1014 - if (WARN_ON_ONCE(unlikely(get_level(f->crstep, f->ptep) > level))) 1015 - return -EINVAL; 1016 - 1017 - if (f->ptep) { 1018 - pgste = pgste_get_lock(f->ptep); 1019 - oldpte = *f->ptep; 1020 - newpte = _pte(f->pfn, f->writable, f->write_attempt | oldpte.s.d, !f->page); 1021 - newpte.s.sd = oldpte.s.sd; 1022 - oldpte.s.sd = 0; 1023 - if (oldpte.val == _PTE_EMPTY.val || oldpte.h.pfra == f->pfn) { 1024 - pgste = __dat_ptep_xchg(f->ptep, pgste, newpte, f->gfn, asce, uses_skeys); 1025 - if (f->callback) 1026 - f->callback(f); 1027 - } else { 1028 - rc = -EAGAIN; 1029 - } 1030 - pgste_set_unlock(f->ptep, pgste); 1031 - } else { 1032 - oldval = READ_ONCE(*f->crstep); 1033 - newval = _crste_fc1(f->pfn, oldval.h.tt, f->writable, 1034 - f->write_attempt | oldval.s.fc1.d); 1035 - newval.s.fc1.sd = oldval.s.fc1.sd; 1036 - if (oldval.val != _CRSTE_EMPTY(oldval.h.tt).val && 1037 - crste_origin_large(oldval) != crste_origin_large(newval)) 1038 - return -EAGAIN; 1039 - if (!dat_crstep_xchg_atomic(f->crstep, oldval, newval, f->gfn, asce)) 1040 - return -EAGAIN; 1041 - if (f->callback) 1042 - f->callback(f); 1043 - } 1044 - 1045 - return rc; 1046 - } 1047 - 1048 1000 static long dat_set_pn_crste(union crste *crstep, gfn_t gfn, gfn_t next, struct dat_walk *walk) 1049 1001 { 1050 1002 union crste newcrste, oldcrste;
-2
arch/s390/kvm/dat.h
··· 540 540 u16 type, u16 param); 541 541 int dat_set_prefix_notif_bit(union asce asce, gfn_t gfn); 542 542 bool dat_test_age_gfn(union asce asce, gfn_t start, gfn_t end); 543 - int dat_link(struct kvm_s390_mmu_cache *mc, union asce asce, int level, 544 - bool uses_skeys, struct guest_fault *f); 545 543 546 544 int dat_perform_essa(union asce asce, gfn_t gfn, int orc, union essa_state *state, bool *dirty); 547 545 long dat_reset_cmma(union asce asce, gfn_t start_gfn);
+52 -4
arch/s390/kvm/gmap.c
··· 631 631 return test_bit(GMAP_FLAG_ALLOW_HPAGE_1M, &gmap->flags); 632 632 } 633 633 634 + static int _gmap_link(struct kvm_s390_mmu_cache *mc, struct gmap *gmap, int level, 635 + struct guest_fault *f) 636 + { 637 + union crste oldval, newval; 638 + union pte newpte, oldpte; 639 + union pgste pgste; 640 + int rc = 0; 641 + 642 + rc = dat_entry_walk(mc, f->gfn, gmap->asce, DAT_WALK_ALLOC_CONTINUE, level, 643 + &f->crstep, &f->ptep); 644 + if (rc == -ENOMEM) 645 + return rc; 646 + if (KVM_BUG_ON(rc == -EINVAL, gmap->kvm)) 647 + return rc; 648 + if (rc) 649 + return -EAGAIN; 650 + if (KVM_BUG_ON(get_level(f->crstep, f->ptep) > level, gmap->kvm)) 651 + return -EINVAL; 652 + 653 + if (f->ptep) { 654 + pgste = pgste_get_lock(f->ptep); 655 + oldpte = *f->ptep; 656 + newpte = _pte(f->pfn, f->writable, f->write_attempt | oldpte.s.d, !f->page); 657 + newpte.s.sd = oldpte.s.sd; 658 + oldpte.s.sd = 0; 659 + if (oldpte.val == _PTE_EMPTY.val || oldpte.h.pfra == f->pfn) { 660 + pgste = gmap_ptep_xchg(gmap, f->ptep, newpte, pgste, f->gfn); 661 + if (f->callback) 662 + f->callback(f); 663 + } else { 664 + rc = -EAGAIN; 665 + } 666 + pgste_set_unlock(f->ptep, pgste); 667 + } else { 668 + do { 669 + oldval = READ_ONCE(*f->crstep); 670 + newval = _crste_fc1(f->pfn, oldval.h.tt, f->writable, 671 + f->write_attempt | oldval.s.fc1.d); 672 + newval.s.fc1.sd = oldval.s.fc1.sd; 673 + if (oldval.val != _CRSTE_EMPTY(oldval.h.tt).val && 674 + crste_origin_large(oldval) != crste_origin_large(newval)) 675 + return -EAGAIN; 676 + } while (!gmap_crstep_xchg_atomic(gmap, f->crstep, oldval, newval, f->gfn)); 677 + if (f->callback) 678 + f->callback(f); 679 + } 680 + 681 + return rc; 682 + } 683 + 634 684 int gmap_link(struct kvm_s390_mmu_cache *mc, struct gmap *gmap, struct guest_fault *f) 635 685 { 636 686 unsigned int order; 637 - int rc, level; 687 + int level; 638 688 639 689 lockdep_assert_held(&gmap->kvm->mmu_lock); 640 690 ··· 696 646 else if (order >= get_order(_SEGMENT_SIZE) && gmap_1m_allowed(gmap, f->gfn)) 697 647 level = TABLE_TYPE_SEGMENT; 698 648 } 699 - rc = dat_link(mc, gmap->asce, level, uses_skeys(gmap), f); 700 - KVM_BUG_ON(rc == -EINVAL, gmap->kvm); 701 - return rc; 649 + return _gmap_link(mc, gmap, level, f); 702 650 } 703 651 704 652 static int gmap_ucas_map_one(struct kvm_s390_mmu_cache *mc, struct gmap *gmap,