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: vsie: Fix races with partial gmap invalidations

Introduce a new boolean flag, used for shadow gmaps, to keep track of
whether the gmap has been invalidated, either partially or totally.

Use the new flag to check whether shadow gmap invalidations happened
during shadowing. In such cases, abort whatever was going on, return
-EAGAIN and let the caller try again.

Fixes: 19d6c5b80443 ("KVM: s390: vsie: Fix unshadowing while shadowing")
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Message-ID: <20260407161721.247044-1-imbrenda@linux.ibm.com>

+9 -4
+5 -4
arch/s390/kvm/gaccess.c
··· 1449 1449 pgste_set_unlock(ptep_h, pgste); 1450 1450 if (rc) 1451 1451 return rc; 1452 - if (!sg->parent) 1452 + if (sg->invalidated) 1453 1453 return -EAGAIN; 1454 1454 1455 1455 newpte = _pte(f->pfn, 0, !p, 0); ··· 1479 1479 1480 1480 do { 1481 1481 /* _gmap_crstep_xchg_atomic() could have unshadowed this shadow gmap */ 1482 - if (!sg->parent) 1482 + if (sg->invalidated) 1483 1483 return -EAGAIN; 1484 1484 oldcrste = READ_ONCE(*host); 1485 1485 newcrste = _crste_fc1(f->pfn, oldcrste.h.tt, f->writable, !p); ··· 1492 1492 if (!newcrste.h.p && !f->writable) 1493 1493 return -EOPNOTSUPP; 1494 1494 } while (!_gmap_crstep_xchg_atomic(sg->parent, host, oldcrste, newcrste, f->gfn, false)); 1495 - if (!sg->parent) 1495 + if (sg->invalidated) 1496 1496 return -EAGAIN; 1497 1497 1498 1498 newcrste = _crste_fc1(f->pfn, oldcrste.h.tt, 0, !p); ··· 1545 1545 entries[i].pfn, i + 1, entries[i].writable); 1546 1546 if (rc) 1547 1547 return rc; 1548 - if (!sg->parent) 1548 + if (sg->invalidated) 1549 1549 return -EAGAIN; 1550 1550 } 1551 1551 ··· 1601 1601 scoped_guard(spinlock, &parent->children_lock) { 1602 1602 if (READ_ONCE(sg->parent) != parent) 1603 1603 return -EAGAIN; 1604 + sg->invalidated = false; 1604 1605 rc = _gaccess_do_shadow(vcpu->arch.mc, sg, saddr, walk); 1605 1606 } 1606 1607 if (rc == -ENOMEM)
+3
arch/s390/kvm/gmap.c
··· 181 181 182 182 list_del(&child->list); 183 183 child->parent = NULL; 184 + child->invalidated = true; 184 185 } 185 186 186 187 /** ··· 1070 1069 if (level > TABLE_TYPE_PAGE_TABLE) 1071 1070 align = 1UL << (11 * level + _SEGMENT_SHIFT); 1072 1071 kvm_s390_vsie_gmap_notifier(sg, ALIGN_DOWN(gaddr, align), ALIGN(gaddr + 1, align)); 1072 + sg->invalidated = true; 1073 1073 if (dat_entry_walk(NULL, r_gfn, sg->asce, 0, level, &crstep, &ptep)) 1074 1074 return; 1075 1075 if (ptep) { ··· 1176 1174 scoped_guard(spinlock, &parent->children_lock) { 1177 1175 if (READ_ONCE(sg->parent) != parent) 1178 1176 return -EAGAIN; 1177 + sg->invalidated = false; 1179 1178 for (i = 0; i < CRST_TABLE_PAGES; i++) { 1180 1179 if (!context->f[i].valid) 1181 1180 continue;
+1
arch/s390/kvm/gmap.h
··· 60 60 struct gmap { 61 61 unsigned long flags; 62 62 unsigned char edat_level; 63 + bool invalidated; 63 64 struct kvm *kvm; 64 65 union asce asce; 65 66 struct list_head list;