]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
KVM: s390: Fix _gmap_unmap_crste()
authorClaudio Imbrenda <imbrenda@linux.ibm.com>
Tue, 2 Jun 2026 14:23:47 +0000 (16:23 +0200)
committerClaudio Imbrenda <imbrenda@linux.ibm.com>
Tue, 2 Jun 2026 14:46:41 +0000 (16:46 +0200)
In _gmap_unmap_crste(), the crste to be unmapped is zapped calling
gmap_crstep_xchg_atomic() exactly once, and expecting it to succeed.
This is a reasonable sanity check, since kvm->mmu_lock is being held in
write mode, and thus no races should be possible.

An upcoming patch will change the behaviour of gmap_crstep_xchg_atomic()
to return false and clear the vsie_notif bit if the operation triggers
an unshadow operation. With the new behaviour, an unmap operation that
triggers an unshadow would cause the VM to be killed.

Prepare for the change by checking if the vsie_notif bit was set in
the old crste if gmap_crstep_xchg_atomic() fails the first time, and
try a second time. The second time no failures are allowed.

Fixes: b827ef02f409 ("KVM: s390: Remove non-atomic dat_crstep_xchg()")
Fixes: a2c17f9270cc ("KVM: s390: New gmap code")
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Message-ID: <20260602142356.169458-2-imbrenda@linux.ibm.com>

arch/s390/kvm/gmap.c

index 957126ab991ca5182d62acf011d43778675dc12f..52d55ddea8d4fcb427b75b3d3aa7b5e4f2fefce9 100644 (file)
@@ -395,15 +395,28 @@ static long _gmap_unmap_crste(union crste *crstep, gfn_t gfn, gfn_t next, struct
        struct gmap_unmap_priv *priv = walk->priv;
        struct folio *folio = NULL;
        union crste old = *crstep;
+       bool ok;
 
        if (!old.h.fc)
                return 0;
 
        if (old.s.fc1.pr && test_bit(GMAP_FLAG_EXPORT_ON_UNMAP, &priv->gmap->flags))
                folio = phys_to_folio(crste_origin_large(old));
-       /* No races should happen because kvm->mmu_lock is held in write mode */
-       KVM_BUG_ON(!gmap_crstep_xchg_atomic(priv->gmap, crstep, old, _CRSTE_EMPTY(old.h.tt), gfn),
-                  priv->gmap->kvm);
+       /*
+        * No races should happen because kvm->mmu_lock is held in write mode,
+        * but the unmap operation could have triggered an unshadow, which
+        * causes gmap_crstep_xchg_atomic() to return false and clear the
+        * vsie_notif bit. Allow the operation to fail once, if the old crste
+        * had the vsie_notif bit set. A second failure is not allowed, for
+        * the reasons above.
+        */
+       ok = gmap_crstep_xchg_atomic(priv->gmap, crstep, old, _CRSTE_EMPTY(old.h.tt), gfn);
+       if (!ok) {
+               KVM_BUG_ON(!old.s.fc1.vsie_notif, priv->gmap->kvm);
+               old.s.fc1.vsie_notif = 0;
+               ok = gmap_crstep_xchg_atomic(priv->gmap, crstep, old, _CRSTE_EMPTY(old.h.tt), gfn);
+               KVM_BUG_ON(!ok, priv->gmap->kvm);
+       }
        if (folio)
                uv_convert_from_secure_folio(folio);