public inbox for kvm@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 00/15] KVM: s390: Stop using page->index and other things
@ 2025-01-17 19:09 Claudio Imbrenda
  2025-01-17 19:09 ` [PATCH v3 01/15] KVM: Do not restrict the size of KVM-internal memory regions Claudio Imbrenda
                   ` (14 more replies)
  0 siblings, 15 replies; 42+ messages in thread
From: Claudio Imbrenda @ 2025-01-17 19:09 UTC (permalink / raw)
  To: kvm
  Cc: linux-s390, frankja, borntraeger, schlameuss, david, willy, hca,
	svens, agordeev, gor, nrb, nsg, seanjc, seiden

This patchseries starts moving some of the gmap logic into KVM itself,
going towards the final goal of completely removing gmap from the
non-kvm memory management code. Aside from just moving some code from
mm/gmap into kvm, this series also starts using __kvm_faultin_pfn() to
fault-in pages as needed.

But more importantly, this series removes almost all uses of
page->index (and all uses of page->lru) from the s390 KVM code.
The only remaining use is for the vsie pages, but that has already been
taken care of by David in another series.

Unfortunately the mix of hastiness and holidays means that this series
is a little bit all over the place, and not as complete as I would have
liked to.

I'm posting it now so to try to speed up the removal of page->index,
hopefully I will be able to post another short series before the
upcoming merge window closes.


v1->v2:
* moved some code around between patches to improve readability and shuffle
  the order of some patches
* rebase on Sean's patchseries
* add Sean's patch to remove size limitations for internal memslots
* use Sean's new API for internal memslots to place one huge internal
  memslot instead of many 4T ones for UCONTROL guests
* create new kvm/gmap-vsie.c file for VSIE code, instead of dumping
  everything in the existing files, which are already too large
* improve comments and patch descriptions
* minor style and cosmetic fixes

v2->v3
* moved patch 5 back to its place
* moved uv_wiggle_folio() to mm/gmap.c and renamed it to
  kvm_s390_wiggle_split_folio()
* fixed some typos
* added some lockdep asserts
* minor style fixes
* added some comments
* fixed documentation


Claudio Imbrenda (14):
  KVM: s390: wrapper for KVM_BUG
  KVM: s390: fake memslot for ucontrol VMs
  KVM: s390: selftests: fix ucontrol memory region test
  KVM: s390: move pv gmap functions into kvm
  KVM: s390: use __kvm_faultin_pfn()
  KVM: s390: get rid of gmap_fault()
  KVM: s390: get rid of gmap_translate()
  KVM: s390: move some gmap shadowing functions away from mm/gmap.c
  KVM: s390: stop using page->index for non-shadow gmaps
  KVM: s390: stop using lists to keep track of used dat tables
  KVM: s390: move gmap_shadow_pgt_lookup() into kvm
  KVM: s390: remove useless page->index usage
  KVM: s390: move PGSTE softbits
  KVM: s390: remove the last user of page->index

Sean Christopherson (1):
  KVM: Do not restrict the size of KVM-internal memory regions

 Documentation/virt/kvm/api.rst                |   2 +-
 arch/s390/include/asm/gmap.h                  |  18 +-
 arch/s390/include/asm/kvm_host.h              |   2 +
 arch/s390/include/asm/pgtable.h               |  21 +-
 arch/s390/include/asm/uv.h                    |   6 +-
 arch/s390/kernel/uv.c                         | 292 +-------
 arch/s390/kvm/Makefile                        |   2 +-
 arch/s390/kvm/gaccess.c                       |  42 ++
 arch/s390/kvm/gmap-vsie.c                     | 142 ++++
 arch/s390/kvm/gmap.c                          | 206 ++++++
 arch/s390/kvm/gmap.h                          |  39 +
 arch/s390/kvm/intercept.c                     |   5 +-
 arch/s390/kvm/interrupt.c                     |  19 +-
 arch/s390/kvm/kvm-s390.c                      | 219 +++++-
 arch/s390/kvm/kvm-s390.h                      |  19 +
 arch/s390/kvm/pv.c                            |   1 +
 arch/s390/kvm/vsie.c                          |   2 +
 arch/s390/mm/gmap.c                           | 681 ++++--------------
 .../selftests/kvm/s390x/ucontrol_test.c       |   6 +-
 virt/kvm/kvm_main.c                           |  10 +-
 20 files changed, 867 insertions(+), 867 deletions(-)
 create mode 100644 arch/s390/kvm/gmap-vsie.c
 create mode 100644 arch/s390/kvm/gmap.c
 create mode 100644 arch/s390/kvm/gmap.h

-- 
2.48.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [PATCH v3 01/15] KVM: Do not restrict the size of KVM-internal memory regions
  2025-01-17 19:09 [PATCH v3 00/15] KVM: s390: Stop using page->index and other things Claudio Imbrenda
@ 2025-01-17 19:09 ` Claudio Imbrenda
  2025-01-20 12:06   ` David Hildenbrand
  2025-01-17 19:09 ` [PATCH v3 02/15] KVM: s390: wrapper for KVM_BUG Claudio Imbrenda
                   ` (13 subsequent siblings)
  14 siblings, 1 reply; 42+ messages in thread
From: Claudio Imbrenda @ 2025-01-17 19:09 UTC (permalink / raw)
  To: kvm
  Cc: linux-s390, frankja, borntraeger, schlameuss, david, willy, hca,
	svens, agordeev, gor, nrb, nsg, seanjc, seiden

From: Sean Christopherson <seanjc@google.com>

Exempt KVM-internal memslots from the KVM_MEM_MAX_NR_PAGES restriction, as
the limit on the number of pages exists purely to play nice with dirty
bitmap operations, which use 32-bit values to index the bitmaps, and dirty
logging isn't supported for KVM-internal memslots.

Link: https://lore.kernel.org/all/20240802205003.353672-6-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
Reviewed-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
---
 virt/kvm/kvm_main.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index a8a84bf450f9..ee3f040a4891 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -1966,7 +1966,15 @@ static int kvm_set_memory_region(struct kvm *kvm,
 		return -EINVAL;
 	if (mem->guest_phys_addr + mem->memory_size < mem->guest_phys_addr)
 		return -EINVAL;
-	if ((mem->memory_size >> PAGE_SHIFT) > KVM_MEM_MAX_NR_PAGES)
+
+	/*
+	 * The size of userspace-defined memory regions is restricted in order
+	 * to play nice with dirty bitmap operations, which are indexed with an
+	 * "unsigned int".  KVM's internal memory regions don't support dirty
+	 * logging, and so are exempt.
+	 */
+	if (id < KVM_USER_MEM_SLOTS &&
+	    (mem->memory_size >> PAGE_SHIFT) > KVM_MEM_MAX_NR_PAGES)
 		return -EINVAL;
 
 	slots = __kvm_memslots(kvm, as_id);
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v3 02/15] KVM: s390: wrapper for KVM_BUG
  2025-01-17 19:09 [PATCH v3 00/15] KVM: s390: Stop using page->index and other things Claudio Imbrenda
  2025-01-17 19:09 ` [PATCH v3 01/15] KVM: Do not restrict the size of KVM-internal memory regions Claudio Imbrenda
@ 2025-01-17 19:09 ` Claudio Imbrenda
  2025-01-20 12:07   ` David Hildenbrand
  2025-01-17 19:09 ` [PATCH v3 03/15] KVM: s390: fake memslot for ucontrol VMs Claudio Imbrenda
                   ` (12 subsequent siblings)
  14 siblings, 1 reply; 42+ messages in thread
From: Claudio Imbrenda @ 2025-01-17 19:09 UTC (permalink / raw)
  To: kvm
  Cc: linux-s390, frankja, borntraeger, schlameuss, david, willy, hca,
	svens, agordeev, gor, nrb, nsg, seanjc, seiden

Wrap the call to KVM_BUG; this reduces code duplication and improves
readability.

Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Reviewed-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Reviewed-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
---
 arch/s390/kvm/kvm-s390.c | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index d8080c27d45b..ecbdd7d41230 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -4766,6 +4766,13 @@ static int vcpu_post_run_addressing_exception(struct kvm_vcpu *vcpu)
 	return kvm_s390_inject_prog_irq(vcpu, &pgm_info);
 }
 
+static void kvm_s390_assert_primary_as(struct kvm_vcpu *vcpu)
+{
+	KVM_BUG(current->thread.gmap_teid.as != PSW_BITS_AS_PRIMARY, vcpu->kvm,
+		"Unexpected program interrupt 0x%x, TEID 0x%016lx",
+		current->thread.gmap_int_code, current->thread.gmap_teid.val);
+}
+
 static int vcpu_post_run_handle_fault(struct kvm_vcpu *vcpu)
 {
 	unsigned int flags = 0;
@@ -4781,9 +4788,7 @@ static int vcpu_post_run_handle_fault(struct kvm_vcpu *vcpu)
 		vcpu->stat.exit_null++;
 		break;
 	case PGM_NON_SECURE_STORAGE_ACCESS:
-		KVM_BUG(current->thread.gmap_teid.as != PSW_BITS_AS_PRIMARY, vcpu->kvm,
-			"Unexpected program interrupt 0x%x, TEID 0x%016lx",
-			current->thread.gmap_int_code, current->thread.gmap_teid.val);
+		kvm_s390_assert_primary_as(vcpu);
 		/*
 		 * This is normal operation; a page belonging to a protected
 		 * guest has not been imported yet. Try to import the page into
@@ -4794,9 +4799,7 @@ static int vcpu_post_run_handle_fault(struct kvm_vcpu *vcpu)
 		break;
 	case PGM_SECURE_STORAGE_ACCESS:
 	case PGM_SECURE_STORAGE_VIOLATION:
-		KVM_BUG(current->thread.gmap_teid.as != PSW_BITS_AS_PRIMARY, vcpu->kvm,
-			"Unexpected program interrupt 0x%x, TEID 0x%016lx",
-			current->thread.gmap_int_code, current->thread.gmap_teid.val);
+		kvm_s390_assert_primary_as(vcpu);
 		/*
 		 * This can happen after a reboot with asynchronous teardown;
 		 * the new guest (normal or protected) will run on top of the
@@ -4825,9 +4828,7 @@ static int vcpu_post_run_handle_fault(struct kvm_vcpu *vcpu)
 	case PGM_REGION_FIRST_TRANS:
 	case PGM_REGION_SECOND_TRANS:
 	case PGM_REGION_THIRD_TRANS:
-		KVM_BUG(current->thread.gmap_teid.as != PSW_BITS_AS_PRIMARY, vcpu->kvm,
-			"Unexpected program interrupt 0x%x, TEID 0x%016lx",
-			current->thread.gmap_int_code, current->thread.gmap_teid.val);
+		kvm_s390_assert_primary_as(vcpu);
 		if (vcpu->arch.gmap->pfault_enabled) {
 			rc = gmap_fault(vcpu->arch.gmap, gaddr, flags | FAULT_FLAG_RETRY_NOWAIT);
 			if (rc == -EFAULT)
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v3 03/15] KVM: s390: fake memslot for ucontrol VMs
  2025-01-17 19:09 [PATCH v3 00/15] KVM: s390: Stop using page->index and other things Claudio Imbrenda
  2025-01-17 19:09 ` [PATCH v3 01/15] KVM: Do not restrict the size of KVM-internal memory regions Claudio Imbrenda
  2025-01-17 19:09 ` [PATCH v3 02/15] KVM: s390: wrapper for KVM_BUG Claudio Imbrenda
@ 2025-01-17 19:09 ` Claudio Imbrenda
  2025-01-20 12:09   ` David Hildenbrand
                     ` (2 more replies)
  2025-01-17 19:09 ` [PATCH v3 04/15] KVM: s390: selftests: fix ucontrol memory region test Claudio Imbrenda
                   ` (11 subsequent siblings)
  14 siblings, 3 replies; 42+ messages in thread
From: Claudio Imbrenda @ 2025-01-17 19:09 UTC (permalink / raw)
  To: kvm
  Cc: linux-s390, frankja, borntraeger, schlameuss, david, willy, hca,
	svens, agordeev, gor, nrb, nsg, seanjc, seiden

Create a fake memslot for ucontrol VMs. The fake memslot identity-maps
userspace.

Now memslots will always be present, and ucontrol is not a special case
anymore.

Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
---
 Documentation/virt/kvm/api.rst   |  2 +-
 arch/s390/include/asm/kvm_host.h |  2 ++
 arch/s390/kvm/kvm-s390.c         | 15 ++++++++++++++-
 arch/s390/kvm/kvm-s390.h         |  2 ++
 4 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index f15b61317aad..cc98115a96d7 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -1419,7 +1419,7 @@ fetch) is injected in the guest.
 S390:
 ^^^^^
 
-Returns -EINVAL if the VM has the KVM_VM_S390_UCONTROL flag set.
+Returns -EINVAL or -EEXIST if the VM has the KVM_VM_S390_UCONTROL flag set.
 Returns -EINVAL if called on a protected VM.
 
 4.36 KVM_SET_TSS_ADDR
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index 97c7c8127543..9df37361bc64 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -30,6 +30,8 @@
 #define KVM_S390_ESCA_CPU_SLOTS 248
 #define KVM_MAX_VCPUS 255
 
+#define KVM_INTERNAL_MEM_SLOTS 1
+
 /*
  * These seem to be used for allocating ->chip in the routing table, which we
  * don't use. 1 is as small as we can get to reduce the needed memory. If we
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index ecbdd7d41230..58cc7f7444e5 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -3428,8 +3428,18 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 	VM_EVENT(kvm, 3, "vm created with type %lu", type);
 
 	if (type & KVM_VM_S390_UCONTROL) {
+		struct kvm_userspace_memory_region2 fake_memslot = {
+			.slot = KVM_S390_UCONTROL_MEMSLOT,
+			.guest_phys_addr = 0,
+			.userspace_addr = 0,
+			.memory_size = ALIGN_DOWN(TASK_SIZE, _SEGMENT_SIZE),
+			.flags = 0,
+		};
+
 		kvm->arch.gmap = NULL;
 		kvm->arch.mem_limit = KVM_S390_NO_MEM_LIMIT;
+		/* one flat fake memslot covering the whole address-space */
+		KVM_BUG_ON(kvm_set_internal_memslot(kvm, &fake_memslot), kvm);
 	} else {
 		if (sclp.hamax == U64_MAX)
 			kvm->arch.mem_limit = TASK_SIZE_MAX;
@@ -5854,7 +5864,7 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
 {
 	gpa_t size;
 
-	if (kvm_is_ucontrol(kvm))
+	if (kvm_is_ucontrol(kvm) && new->id < KVM_USER_MEM_SLOTS)
 		return -EINVAL;
 
 	/* When we are protected, we should not change the memory slots */
@@ -5906,6 +5916,9 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
 {
 	int rc = 0;
 
+	if (kvm_is_ucontrol(kvm))
+		return;
+
 	switch (change) {
 	case KVM_MR_DELETE:
 		rc = gmap_unmap_segment(kvm->arch.gmap, old->base_gfn * PAGE_SIZE,
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index 597d7a71deeb..30736ac16f84 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -20,6 +20,8 @@
 #include <asm/processor.h>
 #include <asm/sclp.h>
 
+#define KVM_S390_UCONTROL_MEMSLOT (KVM_USER_MEM_SLOTS + 0)
+
 static inline void kvm_s390_fpu_store(struct kvm_run *run)
 {
 	fpu_stfpc(&run->s.regs.fpc);
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v3 04/15] KVM: s390: selftests: fix ucontrol memory region test
  2025-01-17 19:09 [PATCH v3 00/15] KVM: s390: Stop using page->index and other things Claudio Imbrenda
                   ` (2 preceding siblings ...)
  2025-01-17 19:09 ` [PATCH v3 03/15] KVM: s390: fake memslot for ucontrol VMs Claudio Imbrenda
@ 2025-01-17 19:09 ` Claudio Imbrenda
  2025-01-20 12:12   ` David Hildenbrand
  2025-01-17 19:09 ` [PATCH v3 05/15] KVM: s390: move pv gmap functions into kvm Claudio Imbrenda
                   ` (10 subsequent siblings)
  14 siblings, 1 reply; 42+ messages in thread
From: Claudio Imbrenda @ 2025-01-17 19:09 UTC (permalink / raw)
  To: kvm
  Cc: linux-s390, frankja, borntraeger, schlameuss, david, willy, hca,
	svens, agordeev, gor, nrb, nsg, seanjc, seiden

With the latest patch, attempting to create a memslot from userspace
will result in an EEXIST error for UCONTROL VMs, instead of EINVAL,
since the new memslot will collide with the internal memslot. There is
no simple way to bring back the previous behaviour.

This is not a problem, but the test needs to be fixed accordingly.

Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
---
 tools/testing/selftests/kvm/s390x/ucontrol_test.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/tools/testing/selftests/kvm/s390x/ucontrol_test.c b/tools/testing/selftests/kvm/s390x/ucontrol_test.c
index 135ee22856cf..ca18736257f8 100644
--- a/tools/testing/selftests/kvm/s390x/ucontrol_test.c
+++ b/tools/testing/selftests/kvm/s390x/ucontrol_test.c
@@ -459,10 +459,12 @@ TEST_F(uc_kvm, uc_no_user_region)
 	};
 
 	ASSERT_EQ(-1, ioctl(self->vm_fd, KVM_SET_USER_MEMORY_REGION, &region));
-	ASSERT_EQ(EINVAL, errno);
+	if (errno != EEXIST)
+		ASSERT_EQ(EINVAL, errno);
 
 	ASSERT_EQ(-1, ioctl(self->vm_fd, KVM_SET_USER_MEMORY_REGION2, &region2));
-	ASSERT_EQ(EINVAL, errno);
+	if (errno != EEXIST)
+		ASSERT_EQ(EINVAL, errno);
 }
 
 TEST_F(uc_kvm, uc_map_unmap)
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v3 05/15] KVM: s390: move pv gmap functions into kvm
  2025-01-17 19:09 [PATCH v3 00/15] KVM: s390: Stop using page->index and other things Claudio Imbrenda
                   ` (3 preceding siblings ...)
  2025-01-17 19:09 ` [PATCH v3 04/15] KVM: s390: selftests: fix ucontrol memory region test Claudio Imbrenda
@ 2025-01-17 19:09 ` Claudio Imbrenda
  2025-01-21 10:55   ` Christoph Schlameuss
  2025-01-21 12:54   ` Janosch Frank
  2025-01-17 19:09 ` [PATCH v3 06/15] KVM: s390: use __kvm_faultin_pfn() Claudio Imbrenda
                   ` (9 subsequent siblings)
  14 siblings, 2 replies; 42+ messages in thread
From: Claudio Imbrenda @ 2025-01-17 19:09 UTC (permalink / raw)
  To: kvm
  Cc: linux-s390, frankja, borntraeger, schlameuss, david, willy, hca,
	svens, agordeev, gor, nrb, nsg, seanjc, seiden

Move gmap related functions from kernel/uv into kvm.

Create a new file to collect gmap-related functions.

Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
---
 arch/s390/include/asm/gmap.h |   1 +
 arch/s390/include/asm/uv.h   |   6 +-
 arch/s390/kernel/uv.c        | 292 ++++-------------------------------
 arch/s390/kvm/Makefile       |   2 +-
 arch/s390/kvm/gmap.c         | 206 ++++++++++++++++++++++++
 arch/s390/kvm/gmap.h         |  17 ++
 arch/s390/kvm/intercept.c    |   1 +
 arch/s390/kvm/kvm-s390.c     |   1 +
 arch/s390/kvm/pv.c           |   1 +
 arch/s390/mm/gmap.c          |  28 ++++
 10 files changed, 288 insertions(+), 267 deletions(-)
 create mode 100644 arch/s390/kvm/gmap.c
 create mode 100644 arch/s390/kvm/gmap.h

diff --git a/arch/s390/include/asm/gmap.h b/arch/s390/include/asm/gmap.h
index 13f51a6a5bb1..3e66f53fe3cc 100644
--- a/arch/s390/include/asm/gmap.h
+++ b/arch/s390/include/asm/gmap.h
@@ -149,6 +149,7 @@ int s390_replace_asce(struct gmap *gmap);
 void s390_uv_destroy_pfns(unsigned long count, unsigned long *pfns);
 int __s390_uv_destroy_range(struct mm_struct *mm, unsigned long start,
 			    unsigned long end, bool interruptible);
+int kvm_s390_wiggle_split_folio(struct mm_struct *mm, struct folio *folio, bool split);
 
 /**
  * s390_uv_destroy_range - Destroy a range of pages in the given mm.
diff --git a/arch/s390/include/asm/uv.h b/arch/s390/include/asm/uv.h
index dc332609f2c3..b11f5b6d0bd1 100644
--- a/arch/s390/include/asm/uv.h
+++ b/arch/s390/include/asm/uv.h
@@ -628,12 +628,12 @@ static inline int is_prot_virt_host(void)
 }
 
 int uv_pin_shared(unsigned long paddr);
-int gmap_make_secure(struct gmap *gmap, unsigned long gaddr, void *uvcb);
-int gmap_destroy_page(struct gmap *gmap, unsigned long gaddr);
 int uv_destroy_folio(struct folio *folio);
 int uv_destroy_pte(pte_t pte);
 int uv_convert_from_secure_pte(pte_t pte);
-int gmap_convert_to_secure(struct gmap *gmap, unsigned long gaddr);
+int make_folio_secure(struct folio *folio, struct uv_cb_header *uvcb);
+int uv_convert_from_secure(unsigned long paddr);
+int uv_convert_from_secure_folio(struct folio *folio);
 
 void setup_uv(void);
 
diff --git a/arch/s390/kernel/uv.c b/arch/s390/kernel/uv.c
index 6f9654a191ad..9f05df2da2f7 100644
--- a/arch/s390/kernel/uv.c
+++ b/arch/s390/kernel/uv.c
@@ -19,19 +19,6 @@
 #include <asm/sections.h>
 #include <asm/uv.h>
 
-#if !IS_ENABLED(CONFIG_KVM)
-unsigned long __gmap_translate(struct gmap *gmap, unsigned long gaddr)
-{
-	return 0;
-}
-
-int gmap_fault(struct gmap *gmap, unsigned long gaddr,
-	       unsigned int fault_flags)
-{
-	return 0;
-}
-#endif
-
 /* the bootdata_preserved fields come from ones in arch/s390/boot/uv.c */
 int __bootdata_preserved(prot_virt_guest);
 EXPORT_SYMBOL(prot_virt_guest);
@@ -159,6 +146,7 @@ int uv_destroy_folio(struct folio *folio)
 	folio_put(folio);
 	return rc;
 }
+EXPORT_SYMBOL(uv_destroy_folio);
 
 /*
  * The present PTE still indirectly holds a folio reference through the mapping.
@@ -175,7 +163,7 @@ int uv_destroy_pte(pte_t pte)
  *
  * @paddr: Absolute host address of page to be exported
  */
-static int uv_convert_from_secure(unsigned long paddr)
+int uv_convert_from_secure(unsigned long paddr)
 {
 	struct uv_cb_cfs uvcb = {
 		.header.cmd = UVC_CMD_CONV_FROM_SEC_STOR,
@@ -187,11 +175,12 @@ static int uv_convert_from_secure(unsigned long paddr)
 		return -EINVAL;
 	return 0;
 }
+EXPORT_SYMBOL_GPL(uv_convert_from_secure);
 
 /*
  * The caller must already hold a reference to the folio.
  */
-static int uv_convert_from_secure_folio(struct folio *folio)
+int uv_convert_from_secure_folio(struct folio *folio)
 {
 	int rc;
 
@@ -206,6 +195,7 @@ static int uv_convert_from_secure_folio(struct folio *folio)
 	folio_put(folio);
 	return rc;
 }
+EXPORT_SYMBOL_GPL(uv_convert_from_secure_folio);
 
 /*
  * The present PTE still indirectly holds a folio reference through the mapping.
@@ -237,13 +227,33 @@ static int expected_folio_refs(struct folio *folio)
 	return res;
 }
 
-static int make_folio_secure(struct folio *folio, struct uv_cb_header *uvcb)
+/**
+ * make_folio_secure() - make a folio secure
+ * @folio: the folio to make secure
+ * @uvcb: the uvcb that describes the UVC to be used
+ *
+ * The folio @folio will be made secure if possible, @uvcb will be passed
+ * as-is to the UVC.
+ *
+ * Return: 0 on success;
+ *         -EBUSY if the folio is in writeback or has too many references;
+ *         -E2BIG if the folio is large;
+ *         -EAGAIN if the UVC needs to be attempted again;
+ *         -ENXIO if the address is not mapped;
+ *         -EINVAL if the UVC failed for other reasons.
+ *
+ * Context: The caller must hold exactly one extra reference on the folio
+ *          (it's the same logic as split_folio())
+ */
+int make_folio_secure(struct folio *folio, struct uv_cb_header *uvcb)
 {
 	int expected, cc = 0;
 
+	if (folio_test_large(folio))
+		return -E2BIG;
 	if (folio_test_writeback(folio))
-		return -EAGAIN;
-	expected = expected_folio_refs(folio);
+		return -EBUSY;
+	expected = expected_folio_refs(folio) + 1;
 	if (!folio_ref_freeze(folio, expected))
 		return -EBUSY;
 	set_bit(PG_arch_1, &folio->flags);
@@ -267,251 +277,7 @@ static int make_folio_secure(struct folio *folio, struct uv_cb_header *uvcb)
 		return -EAGAIN;
 	return uvcb->rc == 0x10a ? -ENXIO : -EINVAL;
 }
-
-/**
- * should_export_before_import - Determine whether an export is needed
- * before an import-like operation
- * @uvcb: the Ultravisor control block of the UVC to be performed
- * @mm: the mm of the process
- *
- * Returns whether an export is needed before every import-like operation.
- * This is needed for shared pages, which don't trigger a secure storage
- * exception when accessed from a different guest.
- *
- * Although considered as one, the Unpin Page UVC is not an actual import,
- * so it is not affected.
- *
- * No export is needed also when there is only one protected VM, because the
- * page cannot belong to the wrong VM in that case (there is no "other VM"
- * it can belong to).
- *
- * Return: true if an export is needed before every import, otherwise false.
- */
-static bool should_export_before_import(struct uv_cb_header *uvcb, struct mm_struct *mm)
-{
-	/*
-	 * The misc feature indicates, among other things, that importing a
-	 * shared page from a different protected VM will automatically also
-	 * transfer its ownership.
-	 */
-	if (uv_has_feature(BIT_UV_FEAT_MISC))
-		return false;
-	if (uvcb->cmd == UVC_CMD_UNPIN_PAGE_SHARED)
-		return false;
-	return atomic_read(&mm->context.protected_count) > 1;
-}
-
-/*
- * Drain LRU caches: the local one on first invocation and the ones of all
- * CPUs on successive invocations. Returns "true" on the first invocation.
- */
-static bool drain_lru(bool *drain_lru_called)
-{
-	/*
-	 * If we have tried a local drain and the folio refcount
-	 * still does not match our expected safe value, try with a
-	 * system wide drain. This is needed if the pagevecs holding
-	 * the page are on a different CPU.
-	 */
-	if (*drain_lru_called) {
-		lru_add_drain_all();
-		/* We give up here, don't retry immediately. */
-		return false;
-	}
-	/*
-	 * We are here if the folio refcount does not match the
-	 * expected safe value. The main culprits are usually
-	 * pagevecs. With lru_add_drain() we drain the pagevecs
-	 * on the local CPU so that hopefully the refcount will
-	 * reach the expected safe value.
-	 */
-	lru_add_drain();
-	*drain_lru_called = true;
-	/* The caller should try again immediately */
-	return true;
-}
-
-/*
- * Requests the Ultravisor to make a page accessible to a guest.
- * If it's brought in the first time, it will be cleared. If
- * it has been exported before, it will be decrypted and integrity
- * checked.
- */
-int gmap_make_secure(struct gmap *gmap, unsigned long gaddr, void *uvcb)
-{
-	struct vm_area_struct *vma;
-	bool drain_lru_called = false;
-	spinlock_t *ptelock;
-	unsigned long uaddr;
-	struct folio *folio;
-	pte_t *ptep;
-	int rc;
-
-again:
-	rc = -EFAULT;
-	mmap_read_lock(gmap->mm);
-
-	uaddr = __gmap_translate(gmap, gaddr);
-	if (IS_ERR_VALUE(uaddr))
-		goto out;
-	vma = vma_lookup(gmap->mm, uaddr);
-	if (!vma)
-		goto out;
-	/*
-	 * Secure pages cannot be huge and userspace should not combine both.
-	 * In case userspace does it anyway this will result in an -EFAULT for
-	 * the unpack. The guest is thus never reaching secure mode. If
-	 * userspace is playing dirty tricky with mapping huge pages later
-	 * on this will result in a segmentation fault.
-	 */
-	if (is_vm_hugetlb_page(vma))
-		goto out;
-
-	rc = -ENXIO;
-	ptep = get_locked_pte(gmap->mm, uaddr, &ptelock);
-	if (!ptep)
-		goto out;
-	if (pte_present(*ptep) && !(pte_val(*ptep) & _PAGE_INVALID) && pte_write(*ptep)) {
-		folio = page_folio(pte_page(*ptep));
-		rc = -EAGAIN;
-		if (folio_test_large(folio)) {
-			rc = -E2BIG;
-		} else if (folio_trylock(folio)) {
-			if (should_export_before_import(uvcb, gmap->mm))
-				uv_convert_from_secure(PFN_PHYS(folio_pfn(folio)));
-			rc = make_folio_secure(folio, uvcb);
-			folio_unlock(folio);
-		}
-
-		/*
-		 * Once we drop the PTL, the folio may get unmapped and
-		 * freed immediately. We need a temporary reference.
-		 */
-		if (rc == -EAGAIN || rc == -E2BIG)
-			folio_get(folio);
-	}
-	pte_unmap_unlock(ptep, ptelock);
-out:
-	mmap_read_unlock(gmap->mm);
-
-	switch (rc) {
-	case -E2BIG:
-		folio_lock(folio);
-		rc = split_folio(folio);
-		folio_unlock(folio);
-		folio_put(folio);
-
-		switch (rc) {
-		case 0:
-			/* Splitting succeeded, try again immediately. */
-			goto again;
-		case -EAGAIN:
-			/* Additional folio references. */
-			if (drain_lru(&drain_lru_called))
-				goto again;
-			return -EAGAIN;
-		case -EBUSY:
-			/* Unexpected race. */
-			return -EAGAIN;
-		}
-		WARN_ON_ONCE(1);
-		return -ENXIO;
-	case -EAGAIN:
-		/*
-		 * If we are here because the UVC returned busy or partial
-		 * completion, this is just a useless check, but it is safe.
-		 */
-		folio_wait_writeback(folio);
-		folio_put(folio);
-		return -EAGAIN;
-	case -EBUSY:
-		/* Additional folio references. */
-		if (drain_lru(&drain_lru_called))
-			goto again;
-		return -EAGAIN;
-	case -ENXIO:
-		if (gmap_fault(gmap, gaddr, FAULT_FLAG_WRITE))
-			return -EFAULT;
-		return -EAGAIN;
-	}
-	return rc;
-}
-EXPORT_SYMBOL_GPL(gmap_make_secure);
-
-int gmap_convert_to_secure(struct gmap *gmap, unsigned long gaddr)
-{
-	struct uv_cb_cts uvcb = {
-		.header.cmd = UVC_CMD_CONV_TO_SEC_STOR,
-		.header.len = sizeof(uvcb),
-		.guest_handle = gmap->guest_handle,
-		.gaddr = gaddr,
-	};
-
-	return gmap_make_secure(gmap, gaddr, &uvcb);
-}
-EXPORT_SYMBOL_GPL(gmap_convert_to_secure);
-
-/**
- * gmap_destroy_page - Destroy a guest page.
- * @gmap: the gmap of the guest
- * @gaddr: the guest address to destroy
- *
- * An attempt will be made to destroy the given guest page. If the attempt
- * fails, an attempt is made to export the page. If both attempts fail, an
- * appropriate error is returned.
- */
-int gmap_destroy_page(struct gmap *gmap, unsigned long gaddr)
-{
-	struct vm_area_struct *vma;
-	struct folio_walk fw;
-	unsigned long uaddr;
-	struct folio *folio;
-	int rc;
-
-	rc = -EFAULT;
-	mmap_read_lock(gmap->mm);
-
-	uaddr = __gmap_translate(gmap, gaddr);
-	if (IS_ERR_VALUE(uaddr))
-		goto out;
-	vma = vma_lookup(gmap->mm, uaddr);
-	if (!vma)
-		goto out;
-	/*
-	 * Huge pages should not be able to become secure
-	 */
-	if (is_vm_hugetlb_page(vma))
-		goto out;
-
-	rc = 0;
-	folio = folio_walk_start(&fw, vma, uaddr, 0);
-	if (!folio)
-		goto out;
-	/*
-	 * See gmap_make_secure(): large folios cannot be secure. Small
-	 * folio implies FW_LEVEL_PTE.
-	 */
-	if (folio_test_large(folio) || !pte_write(fw.pte))
-		goto out_walk_end;
-	rc = uv_destroy_folio(folio);
-	/*
-	 * Fault handlers can race; it is possible that two CPUs will fault
-	 * on the same secure page. One CPU can destroy the page, reboot,
-	 * re-enter secure mode and import it, while the second CPU was
-	 * stuck at the beginning of the handler. At some point the second
-	 * CPU will be able to progress, and it will not be able to destroy
-	 * the page. In that case we do not want to terminate the process,
-	 * we instead try to export the page.
-	 */
-	if (rc)
-		rc = uv_convert_from_secure_folio(folio);
-out_walk_end:
-	folio_walk_end(&fw, vma);
-out:
-	mmap_read_unlock(gmap->mm);
-	return rc;
-}
-EXPORT_SYMBOL_GPL(gmap_destroy_page);
+EXPORT_SYMBOL_GPL(make_folio_secure);
 
 /*
  * To be called with the folio locked or with an extra reference! This will
diff --git a/arch/s390/kvm/Makefile b/arch/s390/kvm/Makefile
index 02217fb4ae10..d972dea657fd 100644
--- a/arch/s390/kvm/Makefile
+++ b/arch/s390/kvm/Makefile
@@ -8,7 +8,7 @@ include $(srctree)/virt/kvm/Makefile.kvm
 ccflags-y := -Ivirt/kvm -Iarch/s390/kvm
 
 kvm-y += kvm-s390.o intercept.o interrupt.o priv.o sigp.o
-kvm-y += diag.o gaccess.o guestdbg.o vsie.o pv.o
+kvm-y += diag.o gaccess.o guestdbg.o vsie.o pv.o gmap.o
 
 kvm-$(CONFIG_VFIO_PCI_ZDEV_KVM) += pci.o
 obj-$(CONFIG_KVM) += kvm.o
diff --git a/arch/s390/kvm/gmap.c b/arch/s390/kvm/gmap.c
new file mode 100644
index 000000000000..dcd192ed580a
--- /dev/null
+++ b/arch/s390/kvm/gmap.c
@@ -0,0 +1,206 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Guest memory management for KVM/s390
+ *
+ * Copyright IBM Corp. 2008, 2020, 2024
+ *
+ *    Author(s): Claudio Imbrenda <imbrenda@linux.ibm.com>
+ *               Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *               David Hildenbrand <david@redhat.com>
+ *               Janosch Frank <frankja@linux.vnet.ibm.com>
+ */
+
+#include <linux/compiler.h>
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <linux/pgtable.h>
+#include <linux/pagemap.h>
+
+#include <asm/lowcore.h>
+#include <asm/gmap.h>
+#include <asm/uv.h>
+
+#include "gmap.h"
+
+/**
+ * should_export_before_import - Determine whether an export is needed
+ * before an import-like operation
+ * @uvcb: the Ultravisor control block of the UVC to be performed
+ * @mm: the mm of the process
+ *
+ * Returns whether an export is needed before every import-like operation.
+ * This is needed for shared pages, which don't trigger a secure storage
+ * exception when accessed from a different guest.
+ *
+ * Although considered as one, the Unpin Page UVC is not an actual import,
+ * so it is not affected.
+ *
+ * No export is needed also when there is only one protected VM, because the
+ * page cannot belong to the wrong VM in that case (there is no "other VM"
+ * it can belong to).
+ *
+ * Return: true if an export is needed before every import, otherwise false.
+ */
+static bool should_export_before_import(struct uv_cb_header *uvcb, struct mm_struct *mm)
+{
+	/*
+	 * The misc feature indicates, among other things, that importing a
+	 * shared page from a different protected VM will automatically also
+	 * transfer its ownership.
+	 */
+	if (uv_has_feature(BIT_UV_FEAT_MISC))
+		return false;
+	if (uvcb->cmd == UVC_CMD_UNPIN_PAGE_SHARED)
+		return false;
+	return atomic_read(&mm->context.protected_count) > 1;
+}
+
+static int __gmap_make_secure(struct gmap *gmap, struct page *page, void *uvcb)
+{
+	struct folio *folio = page_folio(page);
+	int rc;
+
+	/*
+	 * Secure pages cannot be huge and userspace should not combine both.
+	 * In case userspace does it anyway this will result in an -EFAULT for
+	 * the unpack. The guest is thus never reaching secure mode.
+	 * If userspace plays dirty tricks and decides to map huge pages at a
+	 * later point in time, it will receive a segmentation fault or
+	 * KVM_RUN will return -EFAULT.
+	 */
+	if (folio_test_hugetlb(folio))
+		return -EFAULT;
+	if (folio_test_large(folio)) {
+		mmap_read_unlock(gmap->mm);
+		rc = kvm_s390_wiggle_split_folio(gmap->mm, folio, true);
+		mmap_read_lock(gmap->mm);
+		if (rc)
+			return rc;
+		folio = page_folio(page);
+	}
+
+	if (!folio_trylock(folio))
+		return -EAGAIN;
+	if (should_export_before_import(uvcb, gmap->mm))
+		uv_convert_from_secure(folio_to_phys(folio));
+	rc = make_folio_secure(folio, uvcb);
+	folio_unlock(folio);
+
+	/*
+	 * In theory a race is possible and the folio might have become
+	 * large again before the folio_trylock() above. In that case, no
+	 * action is performed and -EAGAIN is returned; the callers will
+	 * have to try again later.
+	 * In most cases this implies running the VM again, getting the same
+	 * exception again, and make another attempt in this function.
+	 * This is expected to happen extremely rarely.
+	 */
+	if (rc == -E2BIG)
+		return -EAGAIN;
+	/*
+	 * Unlikely case: the page is not mapped anymore. Return success
+	 * and let the proper fault handler fault in the page again.
+	 */
+	if (rc == -ENXIO)
+		return 0;
+	/* The folio has too many references, try to shake some off */
+	if (rc == -EBUSY) {
+		mmap_read_unlock(gmap->mm);
+		kvm_s390_wiggle_split_folio(gmap->mm, folio, false);
+		mmap_read_lock(gmap->mm);
+		return -EAGAIN;
+	}
+
+	return rc;
+}
+
+int gmap_make_secure(struct gmap *gmap, unsigned long gaddr, void *uvcb)
+{
+	struct page *page;
+	int rc = 0;
+
+	mmap_read_lock(gmap->mm);
+	page = gfn_to_page(gmap->private, gpa_to_gfn(gaddr));
+	if (page)
+		rc = __gmap_make_secure(gmap, page, uvcb);
+	kvm_release_page_clean(page);
+	mmap_read_unlock(gmap->mm);
+
+	return rc;
+}
+
+int gmap_convert_to_secure(struct gmap *gmap, unsigned long gaddr)
+{
+	struct uv_cb_cts uvcb = {
+		.header.cmd = UVC_CMD_CONV_TO_SEC_STOR,
+		.header.len = sizeof(uvcb),
+		.guest_handle = gmap->guest_handle,
+		.gaddr = gaddr,
+	};
+
+	return gmap_make_secure(gmap, gaddr, &uvcb);
+}
+
+/**
+ * __gmap_destroy_page() - Destroy a guest page.
+ * @gmap: the gmap of the guest
+ * @page: the page to destroy
+ *
+ * An attempt will be made to destroy the given guest page. If the attempt
+ * fails, an attempt is made to export the page. If both attempts fail, an
+ * appropriate error is returned.
+ *
+ * Context: must be called holding the mm lock for gmap->mm
+ */
+static int __gmap_destroy_page(struct gmap *gmap, struct page *page)
+{
+	struct folio *folio = page_folio(page);
+	int rc;
+
+	/*
+	 * See gmap_make_secure(): large folios cannot be secure. Small
+	 * folio implies FW_LEVEL_PTE.
+	 */
+	if (folio_test_large(folio))
+		return -EFAULT;
+
+	rc = uv_destroy_folio(folio);
+	/*
+	 * Fault handlers can race; it is possible that two CPUs will fault
+	 * on the same secure page. One CPU can destroy the page, reboot,
+	 * re-enter secure mode and import it, while the second CPU was
+	 * stuck at the beginning of the handler. At some point the second
+	 * CPU will be able to progress, and it will not be able to destroy
+	 * the page. In that case we do not want to terminate the process,
+	 * we instead try to export the page.
+	 */
+	if (rc)
+		rc = uv_convert_from_secure_folio(folio);
+
+	return rc;
+}
+
+/**
+ * gmap_destroy_page() - Destroy a guest page.
+ * @gmap: the gmap of the guest
+ * @gaddr: the guest address to destroy
+ *
+ * An attempt will be made to destroy the given guest page. If the attempt
+ * fails, an attempt is made to export the page. If both attempts fail, an
+ * appropriate error is returned.
+ *
+ * Context: may sleep.
+ */
+int gmap_destroy_page(struct gmap *gmap, unsigned long gaddr)
+{
+	struct page *page;
+	int rc = 0;
+
+	mmap_read_lock(gmap->mm);
+	page = gfn_to_page(gmap->private, gpa_to_gfn(gaddr));
+	if (page)
+		rc = __gmap_destroy_page(gmap, page);
+	kvm_release_page_clean(page);
+	mmap_read_unlock(gmap->mm);
+	return rc;
+}
diff --git a/arch/s390/kvm/gmap.h b/arch/s390/kvm/gmap.h
new file mode 100644
index 000000000000..f2b52ce29be3
--- /dev/null
+++ b/arch/s390/kvm/gmap.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ *  KVM guest address space mapping code
+ *
+ *    Copyright IBM Corp. 2007, 2016, 2025
+ *    Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *               Claudio Imbrenda <imbrenda@linux.ibm.com>
+ */
+
+#ifndef ARCH_KVM_S390_GMAP_H
+#define ARCH_KVM_S390_GMAP_H
+
+int gmap_make_secure(struct gmap *gmap, unsigned long gaddr, void *uvcb);
+int gmap_convert_to_secure(struct gmap *gmap, unsigned long gaddr);
+int gmap_destroy_page(struct gmap *gmap, unsigned long gaddr);
+
+#endif
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c
index 5bbaadf75dc6..92ae003cd215 100644
--- a/arch/s390/kvm/intercept.c
+++ b/arch/s390/kvm/intercept.c
@@ -21,6 +21,7 @@
 #include "gaccess.h"
 #include "trace.h"
 #include "trace-s390.h"
+#include "gmap.h"
 
 u8 kvm_s390_get_ilen(struct kvm_vcpu *vcpu)
 {
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 58cc7f7444e5..c9496d23470c 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -50,6 +50,7 @@
 #include "kvm-s390.h"
 #include "gaccess.h"
 #include "pci.h"
+#include "gmap.h"
 
 #define CREATE_TRACE_POINTS
 #include "trace.h"
diff --git a/arch/s390/kvm/pv.c b/arch/s390/kvm/pv.c
index 75e81ba26d04..f0301e673810 100644
--- a/arch/s390/kvm/pv.c
+++ b/arch/s390/kvm/pv.c
@@ -17,6 +17,7 @@
 #include <linux/sched/mm.h>
 #include <linux/mmu_notifier.h>
 #include "kvm-s390.h"
+#include "gmap.h"
 
 bool kvm_s390_pv_is_protected(struct kvm *kvm)
 {
diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c
index 16b8a36c56de..3e6e25119a96 100644
--- a/arch/s390/mm/gmap.c
+++ b/arch/s390/mm/gmap.c
@@ -3035,3 +3035,31 @@ int s390_replace_asce(struct gmap *gmap)
 	return 0;
 }
 EXPORT_SYMBOL_GPL(s390_replace_asce);
+
+/**
+ * kvm_s390_wiggle_split_folio() - try to drain extra references to a folio and optionally split
+ * @mm:    the mm containing the folio to work on
+ * @folio: the folio
+ * @split: whether to split a large folio
+ *
+ * Context: Must be called while holding an extra reference to the folio;
+ *          the mm lock should not be held.
+ */
+int kvm_s390_wiggle_split_folio(struct mm_struct *mm, struct folio *folio, bool split)
+{
+	int rc;
+
+	lockdep_assert_not_held(&mm->mmap_lock);
+	folio_wait_writeback(folio);
+	lru_add_drain_all();
+	if (split) {
+		folio_lock(folio);
+		rc = split_folio(folio);
+		folio_unlock(folio);
+
+		if (rc != -EBUSY)
+			return rc;
+	}
+	return -EAGAIN;
+}
+EXPORT_SYMBOL_GPL(kvm_s390_wiggle_split_folio);
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v3 06/15] KVM: s390: use __kvm_faultin_pfn()
  2025-01-17 19:09 [PATCH v3 00/15] KVM: s390: Stop using page->index and other things Claudio Imbrenda
                   ` (4 preceding siblings ...)
  2025-01-17 19:09 ` [PATCH v3 05/15] KVM: s390: move pv gmap functions into kvm Claudio Imbrenda
@ 2025-01-17 19:09 ` Claudio Imbrenda
  2025-01-21 15:11   ` Christoph Schlameuss
  2025-01-17 19:09 ` [PATCH v3 07/15] KVM: s390: get rid of gmap_fault() Claudio Imbrenda
                   ` (8 subsequent siblings)
  14 siblings, 1 reply; 42+ messages in thread
From: Claudio Imbrenda @ 2025-01-17 19:09 UTC (permalink / raw)
  To: kvm
  Cc: linux-s390, frankja, borntraeger, schlameuss, david, willy, hca,
	svens, agordeev, gor, nrb, nsg, seanjc, seiden

Refactor the existing page fault handling code to use __kvm_faultin_pfn().

This possible now that memslots are always present.

Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Acked-by: Janosch Frank <frankja@linux.ibm.com>
---
 arch/s390/kvm/kvm-s390.c | 122 ++++++++++++++++++++++++++++++---------
 arch/s390/kvm/kvm-s390.h |   6 ++
 arch/s390/mm/gmap.c      |   1 +
 3 files changed, 102 insertions(+), 27 deletions(-)

diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index c9496d23470c..b626c87480ed 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -4784,11 +4784,102 @@ static void kvm_s390_assert_primary_as(struct kvm_vcpu *vcpu)
 		current->thread.gmap_int_code, current->thread.gmap_teid.val);
 }
 
+/*
+ * __kvm_s390_handle_dat_fault() - handle a dat fault for the gmap of a vcpu
+ * @vcpu: the vCPU whose gmap is to be fixed up
+ * @gfn: the guest frame number used for memslots (including fake memslots)
+ * @gaddr: the gmap address, does not have to match @gfn for ucontrol gmaps
+ * @flags: FOLL_* flags
+ *
+ * Return: 0 on success, < 0 in case of error.
+ * Context: The mm lock must not be held before calling.
+ */
+int __kvm_s390_handle_dat_fault(struct kvm_vcpu *vcpu, gfn_t gfn, gpa_t gaddr, unsigned int flags)
+{
+	struct kvm_memory_slot *slot;
+	unsigned int fault_flags;
+	bool writable, unlocked;
+	unsigned long vmaddr;
+	struct page *page;
+	kvm_pfn_t pfn;
+	int rc;
+
+	slot = kvm_vcpu_gfn_to_memslot(vcpu, gfn);
+	if (!slot || slot->flags & KVM_MEMSLOT_INVALID)
+		return vcpu_post_run_addressing_exception(vcpu);
+
+	fault_flags = flags & FOLL_WRITE ? FAULT_FLAG_WRITE : 0;
+	if (vcpu->arch.gmap->pfault_enabled)
+		flags |= FOLL_NOWAIT;
+	vmaddr = __gfn_to_hva_memslot(slot, gfn);
+
+try_again:
+	pfn = __kvm_faultin_pfn(slot, gfn, flags, &writable, &page);
+
+	/* Access outside memory, inject addressing exception */
+	if (is_noslot_pfn(pfn))
+		return vcpu_post_run_addressing_exception(vcpu);
+	/* Signal pending: try again */
+	if (pfn == KVM_PFN_ERR_SIGPENDING)
+		return -EAGAIN;
+
+	/* Needs I/O, try to setup async pfault (only possible with FOLL_NOWAIT) */
+	if (pfn == KVM_PFN_ERR_NEEDS_IO) {
+		trace_kvm_s390_major_guest_pfault(vcpu);
+		if (kvm_arch_setup_async_pf(vcpu))
+			return 0;
+		vcpu->stat.pfault_sync++;
+		/* Could not setup async pfault, try again synchronously */
+		flags &= ~FOLL_NOWAIT;
+		goto try_again;
+	}
+	/* Any other error */
+	if (is_error_pfn(pfn))
+		return -EFAULT;
+
+	/* Success */
+	mmap_read_lock(vcpu->arch.gmap->mm);
+	/* Mark the userspace PTEs as young and/or dirty, to avoid page fault loops */
+	rc = fixup_user_fault(vcpu->arch.gmap->mm, vmaddr, fault_flags, &unlocked);
+	if (!rc)
+		rc = __gmap_link(vcpu->arch.gmap, gaddr, vmaddr);
+	kvm_release_faultin_page(vcpu->kvm, page, false, writable);
+	mmap_read_unlock(vcpu->arch.gmap->mm);
+	return rc;
+}
+
+static int vcpu_dat_fault_handler(struct kvm_vcpu *vcpu, unsigned long gaddr, unsigned int flags)
+{
+	unsigned long gaddr_tmp;
+	gfn_t gfn;
+
+	gfn = gpa_to_gfn(gaddr);
+	if (kvm_is_ucontrol(vcpu->kvm)) {
+		/*
+		 * This translates the per-vCPU guest address into a
+		 * fake guest address, which can then be used with the
+		 * fake memslots that are identity mapping userspace.
+		 * This allows ucontrol VMs to use the normal fault
+		 * resolution path, like normal VMs.
+		 */
+		mmap_read_lock(vcpu->arch.gmap->mm);
+		gaddr_tmp = __gmap_translate(vcpu->arch.gmap, gaddr);
+		mmap_read_unlock(vcpu->arch.gmap->mm);
+		if (gaddr_tmp == -EFAULT) {
+			vcpu->run->exit_reason = KVM_EXIT_S390_UCONTROL;
+			vcpu->run->s390_ucontrol.trans_exc_code = gaddr;
+			vcpu->run->s390_ucontrol.pgm_code = PGM_SEGMENT_TRANSLATION;
+			return -EREMOTE;
+		}
+		gfn = gpa_to_gfn(gaddr_tmp);
+	}
+	return __kvm_s390_handle_dat_fault(vcpu, gfn, gaddr, flags);
+}
+
 static int vcpu_post_run_handle_fault(struct kvm_vcpu *vcpu)
 {
 	unsigned int flags = 0;
 	unsigned long gaddr;
-	int rc = 0;
 
 	gaddr = current->thread.gmap_teid.addr * PAGE_SIZE;
 	if (kvm_s390_cur_gmap_fault_is_write())
@@ -4840,37 +4931,14 @@ static int vcpu_post_run_handle_fault(struct kvm_vcpu *vcpu)
 	case PGM_REGION_SECOND_TRANS:
 	case PGM_REGION_THIRD_TRANS:
 		kvm_s390_assert_primary_as(vcpu);
-		if (vcpu->arch.gmap->pfault_enabled) {
-			rc = gmap_fault(vcpu->arch.gmap, gaddr, flags | FAULT_FLAG_RETRY_NOWAIT);
-			if (rc == -EFAULT)
-				return vcpu_post_run_addressing_exception(vcpu);
-			if (rc == -EAGAIN) {
-				trace_kvm_s390_major_guest_pfault(vcpu);
-				if (kvm_arch_setup_async_pf(vcpu))
-					return 0;
-				vcpu->stat.pfault_sync++;
-			} else {
-				return rc;
-			}
-		}
-		rc = gmap_fault(vcpu->arch.gmap, gaddr, flags);
-		if (rc == -EFAULT) {
-			if (kvm_is_ucontrol(vcpu->kvm)) {
-				vcpu->run->exit_reason = KVM_EXIT_S390_UCONTROL;
-				vcpu->run->s390_ucontrol.trans_exc_code = gaddr;
-				vcpu->run->s390_ucontrol.pgm_code = 0x10;
-				return -EREMOTE;
-			}
-			return vcpu_post_run_addressing_exception(vcpu);
-		}
-		break;
+		return vcpu_dat_fault_handler(vcpu, gaddr, flags);
 	default:
 		KVM_BUG(1, vcpu->kvm, "Unexpected program interrupt 0x%x, TEID 0x%016lx",
 			current->thread.gmap_int_code, current->thread.gmap_teid.val);
 		send_sig(SIGSEGV, current, 0);
 		break;
 	}
-	return rc;
+	return 0;
 }
 
 static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason)
@@ -5749,7 +5817,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
 	}
 #endif
 	case KVM_S390_VCPU_FAULT: {
-		r = gmap_fault(vcpu->arch.gmap, arg, 0);
+		r = vcpu_dat_fault_handler(vcpu, arg, 0);
 		break;
 	}
 	case KVM_ENABLE_CAP:
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index 30736ac16f84..3be5291723c8 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -410,6 +410,12 @@ void kvm_s390_vcpu_unsetup_cmma(struct kvm_vcpu *vcpu);
 void kvm_s390_set_cpu_timer(struct kvm_vcpu *vcpu, __u64 cputm);
 __u64 kvm_s390_get_cpu_timer(struct kvm_vcpu *vcpu);
 int kvm_s390_cpus_from_pv(struct kvm *kvm, u16 *rc, u16 *rrc);
+int __kvm_s390_handle_dat_fault(struct kvm_vcpu *vcpu, gfn_t gfn, gpa_t gaddr, unsigned int flags);
+
+static inline int kvm_s390_handle_dat_fault(struct kvm_vcpu *vcpu, gpa_t gaddr, unsigned int flags)
+{
+	return __kvm_s390_handle_dat_fault(vcpu, gpa_to_gfn(gaddr), gaddr, flags);
+}
 
 /* implemented in diag.c */
 int kvm_s390_handle_diag(struct kvm_vcpu *vcpu);
diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c
index 3e6e25119a96..bfaba7733306 100644
--- a/arch/s390/mm/gmap.c
+++ b/arch/s390/mm/gmap.c
@@ -605,6 +605,7 @@ int __gmap_link(struct gmap *gmap, unsigned long gaddr, unsigned long vmaddr)
 	radix_tree_preload_end();
 	return rc;
 }
+EXPORT_SYMBOL(__gmap_link);
 
 /**
  * fixup_user_fault_nowait - manually resolve a user page fault without waiting
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v3 07/15] KVM: s390: get rid of gmap_fault()
  2025-01-17 19:09 [PATCH v3 00/15] KVM: s390: Stop using page->index and other things Claudio Imbrenda
                   ` (5 preceding siblings ...)
  2025-01-17 19:09 ` [PATCH v3 06/15] KVM: s390: use __kvm_faultin_pfn() Claudio Imbrenda
@ 2025-01-17 19:09 ` Claudio Imbrenda
  2025-01-22  9:44   ` Christoph Schlameuss
  2025-01-17 19:09 ` [PATCH v3 08/15] KVM: s390: get rid of gmap_translate() Claudio Imbrenda
                   ` (7 subsequent siblings)
  14 siblings, 1 reply; 42+ messages in thread
From: Claudio Imbrenda @ 2025-01-17 19:09 UTC (permalink / raw)
  To: kvm
  Cc: linux-s390, frankja, borntraeger, schlameuss, david, willy, hca,
	svens, agordeev, gor, nrb, nsg, seanjc, seiden

All gmap page faults are already handled in kvm by the function
kvm_s390_handle_dat_fault(); only few users of gmap_fault remained, all
within kvm.

Convert those calls to use kvm_s390_handle_dat_fault() instead.

Remove gmap_fault() entirely since it has no more users.

Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Acked-by: Janosch Frank <frankja@linux.ibm.com>
---
 arch/s390/include/asm/gmap.h |   1 -
 arch/s390/kvm/intercept.c    |   4 +-
 arch/s390/mm/gmap.c          | 124 -----------------------------------
 3 files changed, 2 insertions(+), 127 deletions(-)

diff --git a/arch/s390/include/asm/gmap.h b/arch/s390/include/asm/gmap.h
index 3e66f53fe3cc..d4572729269f 100644
--- a/arch/s390/include/asm/gmap.h
+++ b/arch/s390/include/asm/gmap.h
@@ -113,7 +113,6 @@ int gmap_unmap_segment(struct gmap *gmap, unsigned long to, unsigned long len);
 unsigned long __gmap_translate(struct gmap *, unsigned long gaddr);
 unsigned long gmap_translate(struct gmap *, unsigned long gaddr);
 int __gmap_link(struct gmap *gmap, unsigned long gaddr, unsigned long vmaddr);
-int gmap_fault(struct gmap *, unsigned long gaddr, unsigned int fault_flags);
 void gmap_discard(struct gmap *, unsigned long from, unsigned long to);
 void __gmap_zap(struct gmap *, unsigned long gaddr);
 void gmap_unlink(struct mm_struct *, unsigned long *table, unsigned long vmaddr);
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c
index 92ae003cd215..83a4b0edf239 100644
--- a/arch/s390/kvm/intercept.c
+++ b/arch/s390/kvm/intercept.c
@@ -368,7 +368,7 @@ static int handle_mvpg_pei(struct kvm_vcpu *vcpu)
 					      reg2, &srcaddr, GACC_FETCH, 0);
 	if (rc)
 		return kvm_s390_inject_prog_cond(vcpu, rc);
-	rc = gmap_fault(vcpu->arch.gmap, srcaddr, 0);
+	rc = kvm_s390_handle_dat_fault(vcpu, srcaddr, 0);
 	if (rc != 0)
 		return rc;
 
@@ -377,7 +377,7 @@ static int handle_mvpg_pei(struct kvm_vcpu *vcpu)
 					      reg1, &dstaddr, GACC_STORE, 0);
 	if (rc)
 		return kvm_s390_inject_prog_cond(vcpu, rc);
-	rc = gmap_fault(vcpu->arch.gmap, dstaddr, FAULT_FLAG_WRITE);
+	rc = kvm_s390_handle_dat_fault(vcpu, dstaddr, FOLL_WRITE);
 	if (rc != 0)
 		return rc;
 
diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c
index bfaba7733306..e124fca14737 100644
--- a/arch/s390/mm/gmap.c
+++ b/arch/s390/mm/gmap.c
@@ -607,130 +607,6 @@ int __gmap_link(struct gmap *gmap, unsigned long gaddr, unsigned long vmaddr)
 }
 EXPORT_SYMBOL(__gmap_link);
 
-/**
- * fixup_user_fault_nowait - manually resolve a user page fault without waiting
- * @mm:		mm_struct of target mm
- * @address:	user address
- * @fault_flags:flags to pass down to handle_mm_fault()
- * @unlocked:	did we unlock the mmap_lock while retrying
- *
- * This function behaves similarly to fixup_user_fault(), but it guarantees
- * that the fault will be resolved without waiting. The function might drop
- * and re-acquire the mm lock, in which case @unlocked will be set to true.
- *
- * The guarantee is that the fault is handled without waiting, but the
- * function itself might sleep, due to the lock.
- *
- * Context: Needs to be called with mm->mmap_lock held in read mode, and will
- * return with the lock held in read mode; @unlocked will indicate whether
- * the lock has been dropped and re-acquired. This is the same behaviour as
- * fixup_user_fault().
- *
- * Return: 0 on success, -EAGAIN if the fault cannot be resolved without
- * waiting, -EFAULT if the fault cannot be resolved, -ENOMEM if out of
- * memory.
- */
-static int fixup_user_fault_nowait(struct mm_struct *mm, unsigned long address,
-				   unsigned int fault_flags, bool *unlocked)
-{
-	struct vm_area_struct *vma;
-	unsigned int test_flags;
-	vm_fault_t fault;
-	int rc;
-
-	fault_flags |= FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_RETRY_NOWAIT;
-	test_flags = fault_flags & FAULT_FLAG_WRITE ? VM_WRITE : VM_READ;
-
-	vma = find_vma(mm, address);
-	if (unlikely(!vma || address < vma->vm_start))
-		return -EFAULT;
-	if (unlikely(!(vma->vm_flags & test_flags)))
-		return -EFAULT;
-
-	fault = handle_mm_fault(vma, address, fault_flags, NULL);
-	/* the mm lock has been dropped, take it again */
-	if (fault & VM_FAULT_COMPLETED) {
-		*unlocked = true;
-		mmap_read_lock(mm);
-		return 0;
-	}
-	/* the mm lock has not been dropped */
-	if (fault & VM_FAULT_ERROR) {
-		rc = vm_fault_to_errno(fault, 0);
-		BUG_ON(!rc);
-		return rc;
-	}
-	/* the mm lock has not been dropped because of FAULT_FLAG_RETRY_NOWAIT */
-	if (fault & VM_FAULT_RETRY)
-		return -EAGAIN;
-	/* nothing needed to be done and the mm lock has not been dropped */
-	return 0;
-}
-
-/**
- * __gmap_fault - resolve a fault on a guest address
- * @gmap: pointer to guest mapping meta data structure
- * @gaddr: guest address
- * @fault_flags: flags to pass down to handle_mm_fault()
- *
- * Context: Needs to be called with mm->mmap_lock held in read mode. Might
- * drop and re-acquire the lock. Will always return with the lock held.
- */
-static int __gmap_fault(struct gmap *gmap, unsigned long gaddr, unsigned int fault_flags)
-{
-	unsigned long vmaddr;
-	bool unlocked;
-	int rc = 0;
-
-retry:
-	unlocked = false;
-
-	vmaddr = __gmap_translate(gmap, gaddr);
-	if (IS_ERR_VALUE(vmaddr))
-		return vmaddr;
-
-	if (fault_flags & FAULT_FLAG_RETRY_NOWAIT)
-		rc = fixup_user_fault_nowait(gmap->mm, vmaddr, fault_flags, &unlocked);
-	else
-		rc = fixup_user_fault(gmap->mm, vmaddr, fault_flags, &unlocked);
-	if (rc)
-		return rc;
-	/*
-	 * In the case that fixup_user_fault unlocked the mmap_lock during
-	 * fault-in, redo __gmap_translate() to avoid racing with a
-	 * map/unmap_segment.
-	 * In particular, __gmap_translate(), fixup_user_fault{,_nowait}(),
-	 * and __gmap_link() must all be called atomically in one go; if the
-	 * lock had been dropped in between, a retry is needed.
-	 */
-	if (unlocked)
-		goto retry;
-
-	return __gmap_link(gmap, gaddr, vmaddr);
-}
-
-/**
- * gmap_fault - resolve a fault on a guest address
- * @gmap: pointer to guest mapping meta data structure
- * @gaddr: guest address
- * @fault_flags: flags to pass down to handle_mm_fault()
- *
- * Returns 0 on success, -ENOMEM for out of memory conditions, -EFAULT if the
- * vm address is already mapped to a different guest segment, and -EAGAIN if
- * FAULT_FLAG_RETRY_NOWAIT was specified and the fault could not be processed
- * immediately.
- */
-int gmap_fault(struct gmap *gmap, unsigned long gaddr, unsigned int fault_flags)
-{
-	int rc;
-
-	mmap_read_lock(gmap->mm);
-	rc = __gmap_fault(gmap, gaddr, fault_flags);
-	mmap_read_unlock(gmap->mm);
-	return rc;
-}
-EXPORT_SYMBOL_GPL(gmap_fault);
-
 /*
  * this function is assumed to be called with mmap_lock held
  */
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v3 08/15] KVM: s390: get rid of gmap_translate()
  2025-01-17 19:09 [PATCH v3 00/15] KVM: s390: Stop using page->index and other things Claudio Imbrenda
                   ` (6 preceding siblings ...)
  2025-01-17 19:09 ` [PATCH v3 07/15] KVM: s390: get rid of gmap_fault() Claudio Imbrenda
@ 2025-01-17 19:09 ` Claudio Imbrenda
  2025-01-22  9:59   ` Christoph Schlameuss
  2025-01-17 19:09 ` [PATCH v3 09/15] KVM: s390: move some gmap shadowing functions away from mm/gmap.c Claudio Imbrenda
                   ` (6 subsequent siblings)
  14 siblings, 1 reply; 42+ messages in thread
From: Claudio Imbrenda @ 2025-01-17 19:09 UTC (permalink / raw)
  To: kvm
  Cc: linux-s390, frankja, borntraeger, schlameuss, david, willy, hca,
	svens, agordeev, gor, nrb, nsg, seanjc, seiden

Add gpa_to_hva(), which uses memslots, and use it to replace all uses
of gmap_translate().

Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Reviewed-by: Janosch Frank <frankja@linux.ibm.com>
---
 arch/s390/include/asm/gmap.h |  1 -
 arch/s390/kvm/interrupt.c    | 19 +++++++++++--------
 arch/s390/kvm/kvm-s390.h     |  9 +++++++++
 arch/s390/mm/gmap.c          | 20 --------------------
 4 files changed, 20 insertions(+), 29 deletions(-)

diff --git a/arch/s390/include/asm/gmap.h b/arch/s390/include/asm/gmap.h
index d4572729269f..74b48f2e608a 100644
--- a/arch/s390/include/asm/gmap.h
+++ b/arch/s390/include/asm/gmap.h
@@ -111,7 +111,6 @@ int gmap_map_segment(struct gmap *gmap, unsigned long from,
 		     unsigned long to, unsigned long len);
 int gmap_unmap_segment(struct gmap *gmap, unsigned long to, unsigned long len);
 unsigned long __gmap_translate(struct gmap *, unsigned long gaddr);
-unsigned long gmap_translate(struct gmap *, unsigned long gaddr);
 int __gmap_link(struct gmap *gmap, unsigned long gaddr, unsigned long vmaddr);
 void gmap_discard(struct gmap *, unsigned long from, unsigned long to);
 void __gmap_zap(struct gmap *, unsigned long gaddr);
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index d4f031e086fc..07ff0e10cb7f 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -2893,7 +2893,8 @@ int kvm_set_routing_entry(struct kvm *kvm,
 			  struct kvm_kernel_irq_routing_entry *e,
 			  const struct kvm_irq_routing_entry *ue)
 {
-	u64 uaddr;
+	u64 uaddr_s, uaddr_i;
+	int idx;
 
 	switch (ue->type) {
 	/* we store the userspace addresses instead of the guest addresses */
@@ -2901,14 +2902,16 @@ int kvm_set_routing_entry(struct kvm *kvm,
 		if (kvm_is_ucontrol(kvm))
 			return -EINVAL;
 		e->set = set_adapter_int;
-		uaddr =  gmap_translate(kvm->arch.gmap, ue->u.adapter.summary_addr);
-		if (uaddr == -EFAULT)
-			return -EFAULT;
-		e->adapter.summary_addr = uaddr;
-		uaddr =  gmap_translate(kvm->arch.gmap, ue->u.adapter.ind_addr);
-		if (uaddr == -EFAULT)
+
+		idx = srcu_read_lock(&kvm->srcu);
+		uaddr_s = gpa_to_hva(kvm, ue->u.adapter.summary_addr);
+		uaddr_i = gpa_to_hva(kvm, ue->u.adapter.ind_addr);
+		srcu_read_unlock(&kvm->srcu, idx);
+
+		if (kvm_is_error_hva(uaddr_s) || kvm_is_error_hva(uaddr_i))
 			return -EFAULT;
-		e->adapter.ind_addr = uaddr;
+		e->adapter.summary_addr = uaddr_s;
+		e->adapter.ind_addr = uaddr_i;
 		e->adapter.summary_offset = ue->u.adapter.summary_offset;
 		e->adapter.ind_offset = ue->u.adapter.ind_offset;
 		e->adapter.adapter_id = ue->u.adapter.adapter_id;
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index 3be5291723c8..61e8544924b3 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -281,6 +281,15 @@ static inline u32 kvm_s390_get_gisa_desc(struct kvm *kvm)
 	return gd;
 }
 
+static inline hva_t gpa_to_hva(struct kvm *kvm, gpa_t gpa)
+{
+	hva_t hva = gfn_to_hva(kvm, gpa_to_gfn(gpa));
+
+	if (!kvm_is_error_hva(hva))
+		hva |= offset_in_page(gpa);
+	return hva;
+}
+
 /* implemented in pv.c */
 int kvm_s390_pv_destroy_cpu(struct kvm_vcpu *vcpu, u16 *rc, u16 *rrc);
 int kvm_s390_pv_create_cpu(struct kvm_vcpu *vcpu, u16 *rc, u16 *rrc);
diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c
index e124fca14737..7fd298732d1e 100644
--- a/arch/s390/mm/gmap.c
+++ b/arch/s390/mm/gmap.c
@@ -463,26 +463,6 @@ unsigned long __gmap_translate(struct gmap *gmap, unsigned long gaddr)
 }
 EXPORT_SYMBOL_GPL(__gmap_translate);
 
-/**
- * gmap_translate - translate a guest address to a user space address
- * @gmap: pointer to guest mapping meta data structure
- * @gaddr: guest address
- *
- * Returns user space address which corresponds to the guest address or
- * -EFAULT if no such mapping exists.
- * This function does not establish potentially missing page table entries.
- */
-unsigned long gmap_translate(struct gmap *gmap, unsigned long gaddr)
-{
-	unsigned long rc;
-
-	mmap_read_lock(gmap->mm);
-	rc = __gmap_translate(gmap, gaddr);
-	mmap_read_unlock(gmap->mm);
-	return rc;
-}
-EXPORT_SYMBOL_GPL(gmap_translate);
-
 /**
  * gmap_unlink - disconnect a page table from the gmap shadow tables
  * @mm: pointer to the parent mm_struct
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v3 09/15] KVM: s390: move some gmap shadowing functions away from mm/gmap.c
  2025-01-17 19:09 [PATCH v3 00/15] KVM: s390: Stop using page->index and other things Claudio Imbrenda
                   ` (7 preceding siblings ...)
  2025-01-17 19:09 ` [PATCH v3 08/15] KVM: s390: get rid of gmap_translate() Claudio Imbrenda
@ 2025-01-17 19:09 ` Claudio Imbrenda
  2025-01-21 13:30   ` Janosch Frank
  2025-01-22 12:50   ` Christoph Schlameuss
  2025-01-17 19:09 ` [PATCH v3 10/15] KVM: s390: stop using page->index for non-shadow gmaps Claudio Imbrenda
                   ` (5 subsequent siblings)
  14 siblings, 2 replies; 42+ messages in thread
From: Claudio Imbrenda @ 2025-01-17 19:09 UTC (permalink / raw)
  To: kvm
  Cc: linux-s390, frankja, borntraeger, schlameuss, david, willy, hca,
	svens, agordeev, gor, nrb, nsg, seanjc, seiden

Move some gmap shadowing functions from mm/gmap.c to kvm/kvm-s390.c and
the newly created kvm/gmap-vsie.c

This is a step toward removing gmap from mm.

Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
---
 arch/s390/include/asm/gmap.h |   9 +-
 arch/s390/kvm/Makefile       |   2 +-
 arch/s390/kvm/gmap-vsie.c    | 142 +++++++++++++++++++++
 arch/s390/kvm/gmap.h         |  20 +++
 arch/s390/kvm/kvm-s390.c     |  62 ++++++++-
 arch/s390/kvm/kvm-s390.h     |   2 +
 arch/s390/kvm/vsie.c         |   2 +
 arch/s390/mm/gmap.c          | 238 +++++------------------------------
 8 files changed, 259 insertions(+), 218 deletions(-)
 create mode 100644 arch/s390/kvm/gmap-vsie.c

diff --git a/arch/s390/include/asm/gmap.h b/arch/s390/include/asm/gmap.h
index 74b48f2e608a..dbf2329281d2 100644
--- a/arch/s390/include/asm/gmap.h
+++ b/arch/s390/include/asm/gmap.h
@@ -106,6 +106,8 @@ struct gmap *gmap_create(struct mm_struct *mm, unsigned long limit);
 void gmap_remove(struct gmap *gmap);
 struct gmap *gmap_get(struct gmap *gmap);
 void gmap_put(struct gmap *gmap);
+void gmap_free(struct gmap *gmap);
+struct gmap *gmap_alloc(unsigned long limit);
 
 int gmap_map_segment(struct gmap *gmap, unsigned long from,
 		     unsigned long to, unsigned long len);
@@ -118,9 +120,7 @@ void gmap_unlink(struct mm_struct *, unsigned long *table, unsigned long vmaddr)
 
 int gmap_read_table(struct gmap *gmap, unsigned long gaddr, unsigned long *val);
 
-struct gmap *gmap_shadow(struct gmap *parent, unsigned long asce,
-			 int edat_level);
-int gmap_shadow_valid(struct gmap *sg, unsigned long asce, int edat_level);
+void gmap_unshadow(struct gmap *sg);
 int gmap_shadow_r2t(struct gmap *sg, unsigned long saddr, unsigned long r2t,
 		    int fake);
 int gmap_shadow_r3t(struct gmap *sg, unsigned long saddr, unsigned long r3t,
@@ -136,8 +136,7 @@ int gmap_shadow_page(struct gmap *sg, unsigned long saddr, pte_t pte);
 void gmap_register_pte_notifier(struct gmap_notifier *);
 void gmap_unregister_pte_notifier(struct gmap_notifier *);
 
-int gmap_mprotect_notify(struct gmap *, unsigned long start,
-			 unsigned long len, int prot);
+int gmap_protect_one(struct gmap *gmap, unsigned long gaddr, int prot, unsigned long bits);
 
 void gmap_sync_dirty_log_pmd(struct gmap *gmap, unsigned long dirty_bitmap[4],
 			     unsigned long gaddr, unsigned long vmaddr);
diff --git a/arch/s390/kvm/Makefile b/arch/s390/kvm/Makefile
index d972dea657fd..f0ffe874adc2 100644
--- a/arch/s390/kvm/Makefile
+++ b/arch/s390/kvm/Makefile
@@ -8,7 +8,7 @@ include $(srctree)/virt/kvm/Makefile.kvm
 ccflags-y := -Ivirt/kvm -Iarch/s390/kvm
 
 kvm-y += kvm-s390.o intercept.o interrupt.o priv.o sigp.o
-kvm-y += diag.o gaccess.o guestdbg.o vsie.o pv.o gmap.o
+kvm-y += diag.o gaccess.o guestdbg.o vsie.o pv.o gmap.o gmap-vsie.o
 
 kvm-$(CONFIG_VFIO_PCI_ZDEV_KVM) += pci.o
 obj-$(CONFIG_KVM) += kvm.o
diff --git a/arch/s390/kvm/gmap-vsie.c b/arch/s390/kvm/gmap-vsie.c
new file mode 100644
index 000000000000..90427f114995
--- /dev/null
+++ b/arch/s390/kvm/gmap-vsie.c
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Guest memory management for KVM/s390 nested VMs.
+ *
+ * Copyright IBM Corp. 2008, 2020, 2024
+ *
+ *    Author(s): Claudio Imbrenda <imbrenda@linux.ibm.com>
+ *               Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *               David Hildenbrand <david@redhat.com>
+ *               Janosch Frank <frankja@linux.vnet.ibm.com>
+ */
+
+#include <linux/compiler.h>
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <linux/pgtable.h>
+#include <linux/pagemap.h>
+#include <linux/mman.h>
+
+#include <asm/lowcore.h>
+#include <asm/gmap.h>
+#include <asm/uv.h>
+
+#include "kvm-s390.h"
+#include "gmap.h"
+
+/**
+ * gmap_find_shadow - find a specific asce in the list of shadow tables
+ * @parent: pointer to the parent gmap
+ * @asce: ASCE for which the shadow table is created
+ * @edat_level: edat level to be used for the shadow translation
+ *
+ * Returns the pointer to a gmap if a shadow table with the given asce is
+ * already available, ERR_PTR(-EAGAIN) if another one is just being created,
+ * otherwise NULL
+ */
+static struct gmap *gmap_find_shadow(struct gmap *parent, unsigned long asce,
+				     int edat_level)
+{
+	struct gmap *sg;
+
+	list_for_each_entry(sg, &parent->children, list) {
+		if (sg->orig_asce != asce || sg->edat_level != edat_level ||
+		    sg->removed)
+			continue;
+		if (!sg->initialized)
+			return ERR_PTR(-EAGAIN);
+		refcount_inc(&sg->ref_count);
+		return sg;
+	}
+	return NULL;
+}
+
+/**
+ * gmap_shadow - create/find a shadow guest address space
+ * @parent: pointer to the parent gmap
+ * @asce: ASCE for which the shadow table is created
+ * @edat_level: edat level to be used for the shadow translation
+ *
+ * The pages of the top level page table referred by the asce parameter
+ * will be set to read-only and marked in the PGSTEs of the kvm process.
+ * The shadow table will be removed automatically on any change to the
+ * PTE mapping for the source table.
+ *
+ * Returns a guest address space structure, ERR_PTR(-ENOMEM) if out of memory,
+ * ERR_PTR(-EAGAIN) if the caller has to retry and ERR_PTR(-EFAULT) if the
+ * parent gmap table could not be protected.
+ */
+struct gmap *gmap_shadow(struct gmap *parent, unsigned long asce,
+			 int edat_level)
+{
+	struct gmap *sg, *new;
+	unsigned long limit;
+	int rc;
+
+	if (KVM_BUG_ON(parent->mm->context.allow_gmap_hpage_1m, (struct kvm *)parent->private) ||
+	    KVM_BUG_ON(gmap_is_shadow(parent), (struct kvm *)parent->private))
+		return ERR_PTR(-EFAULT);
+	spin_lock(&parent->shadow_lock);
+	sg = gmap_find_shadow(parent, asce, edat_level);
+	spin_unlock(&parent->shadow_lock);
+	if (sg)
+		return sg;
+	/* Create a new shadow gmap */
+	limit = -1UL >> (33 - (((asce & _ASCE_TYPE_MASK) >> 2) * 11));
+	if (asce & _ASCE_REAL_SPACE)
+		limit = -1UL;
+	new = gmap_alloc(limit);
+	if (!new)
+		return ERR_PTR(-ENOMEM);
+	new->mm = parent->mm;
+	new->parent = gmap_get(parent);
+	new->private = parent->private;
+	new->orig_asce = asce;
+	new->edat_level = edat_level;
+	new->initialized = false;
+	spin_lock(&parent->shadow_lock);
+	/* Recheck if another CPU created the same shadow */
+	sg = gmap_find_shadow(parent, asce, edat_level);
+	if (sg) {
+		spin_unlock(&parent->shadow_lock);
+		gmap_free(new);
+		return sg;
+	}
+	if (asce & _ASCE_REAL_SPACE) {
+		/* only allow one real-space gmap shadow */
+		list_for_each_entry(sg, &parent->children, list) {
+			if (sg->orig_asce & _ASCE_REAL_SPACE) {
+				spin_lock(&sg->guest_table_lock);
+				gmap_unshadow(sg);
+				spin_unlock(&sg->guest_table_lock);
+				list_del(&sg->list);
+				gmap_put(sg);
+				break;
+			}
+		}
+	}
+	refcount_set(&new->ref_count, 2);
+	list_add(&new->list, &parent->children);
+	if (asce & _ASCE_REAL_SPACE) {
+		/* nothing to protect, return right away */
+		new->initialized = true;
+		spin_unlock(&parent->shadow_lock);
+		return new;
+	}
+	spin_unlock(&parent->shadow_lock);
+	/* protect after insertion, so it will get properly invalidated */
+	mmap_read_lock(parent->mm);
+	rc = __kvm_s390_mprotect_many(parent, asce & _ASCE_ORIGIN,
+				      ((asce & _ASCE_TABLE_LENGTH) + 1),
+				      PROT_READ, GMAP_NOTIFY_SHADOW);
+	mmap_read_unlock(parent->mm);
+	spin_lock(&parent->shadow_lock);
+	new->initialized = true;
+	if (rc) {
+		list_del(&new->list);
+		gmap_free(new);
+		new = ERR_PTR(rc);
+	}
+	spin_unlock(&parent->shadow_lock);
+	return new;
+}
diff --git a/arch/s390/kvm/gmap.h b/arch/s390/kvm/gmap.h
index f2b52ce29be3..978f541059f0 100644
--- a/arch/s390/kvm/gmap.h
+++ b/arch/s390/kvm/gmap.h
@@ -13,5 +13,25 @@
 int gmap_make_secure(struct gmap *gmap, unsigned long gaddr, void *uvcb);
 int gmap_convert_to_secure(struct gmap *gmap, unsigned long gaddr);
 int gmap_destroy_page(struct gmap *gmap, unsigned long gaddr);
+struct gmap *gmap_shadow(struct gmap *parent, unsigned long asce, int edat_level);
+
+/**
+ * gmap_shadow_valid - check if a shadow guest address space matches the
+ *                     given properties and is still valid
+ * @sg: pointer to the shadow guest address space structure
+ * @asce: ASCE for which the shadow table is requested
+ * @edat_level: edat level to be used for the shadow translation
+ *
+ * Returns 1 if the gmap shadow is still valid and matches the given
+ * properties, the caller can continue using it. Returns 0 otherwise, the
+ * caller has to request a new shadow gmap in this case.
+ *
+ */
+static inline int gmap_shadow_valid(struct gmap *sg, unsigned long asce, int edat_level)
+{
+	if (sg->removed)
+		return 0;
+	return sg->orig_asce == asce && sg->edat_level == edat_level;
+}
 
 #endif
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index b626c87480ed..482f0968abfa 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -4509,6 +4509,63 @@ static bool ibs_enabled(struct kvm_vcpu *vcpu)
 	return kvm_s390_test_cpuflags(vcpu, CPUSTAT_IBS);
 }
 
+static int __kvm_s390_fixup_fault_sync(struct gmap *gmap, gpa_t gaddr, unsigned int flags)
+{
+	struct kvm *kvm = gmap->private;
+	gfn_t gfn = gpa_to_gfn(gaddr);
+	bool unlocked;
+	hva_t vmaddr;
+	gpa_t tmp;
+	int rc;
+
+	if (kvm_is_ucontrol(kvm)) {
+		tmp = __gmap_translate(gmap, gaddr);
+		gfn = gpa_to_gfn(tmp);
+	}
+
+	vmaddr = gfn_to_hva(kvm, gfn);
+	rc = fixup_user_fault(gmap->mm, vmaddr, FAULT_FLAG_WRITE, &unlocked);
+	if (!rc)
+		rc = __gmap_link(gmap, gaddr, vmaddr);
+	return rc;
+}
+
+int __kvm_s390_mprotect_many(struct gmap *gmap, gpa_t gpa, u8 npages, unsigned int prot,
+			     unsigned long bits)
+{
+	unsigned int fault_flag = (prot & PROT_WRITE) ? FAULT_FLAG_WRITE : 0;
+	gpa_t end = gpa + npages * PAGE_SIZE;
+	int rc;
+
+	for (; gpa < end; gpa = ALIGN(gpa + 1, rc)) {
+		rc = gmap_protect_one(gmap, gpa, prot, bits);
+		if (rc == -EAGAIN) {
+			__kvm_s390_fixup_fault_sync(gmap, gpa, fault_flag);
+			rc = gmap_protect_one(gmap, gpa, prot, bits);
+		}
+		if (rc < 0)
+			return rc;
+	}
+
+	return 0;
+}
+
+static int kvm_s390_mprotect_notify_prefix(struct kvm_vcpu *vcpu)
+{
+	gpa_t gaddr = kvm_s390_get_prefix(vcpu);
+	int idx, rc;
+
+	idx = srcu_read_lock(&vcpu->kvm->srcu);
+	mmap_read_lock(vcpu->arch.gmap->mm);
+
+	rc = __kvm_s390_mprotect_many(vcpu->arch.gmap, gaddr, 2, PROT_WRITE, GMAP_NOTIFY_MPROT);
+
+	mmap_read_unlock(vcpu->arch.gmap->mm);
+	srcu_read_unlock(&vcpu->kvm->srcu, idx);
+
+	return rc;
+}
+
 static int kvm_s390_handle_requests(struct kvm_vcpu *vcpu)
 {
 retry:
@@ -4524,9 +4581,8 @@ static int kvm_s390_handle_requests(struct kvm_vcpu *vcpu)
 	 */
 	if (kvm_check_request(KVM_REQ_REFRESH_GUEST_PREFIX, vcpu)) {
 		int rc;
-		rc = gmap_mprotect_notify(vcpu->arch.gmap,
-					  kvm_s390_get_prefix(vcpu),
-					  PAGE_SIZE * 2, PROT_WRITE);
+
+		rc = kvm_s390_mprotect_notify_prefix(vcpu);
 		if (rc) {
 			kvm_make_request(KVM_REQ_REFRESH_GUEST_PREFIX, vcpu);
 			return rc;
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index 61e8544924b3..8d3bbb2dd8d2 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -420,6 +420,8 @@ void kvm_s390_set_cpu_timer(struct kvm_vcpu *vcpu, __u64 cputm);
 __u64 kvm_s390_get_cpu_timer(struct kvm_vcpu *vcpu);
 int kvm_s390_cpus_from_pv(struct kvm *kvm, u16 *rc, u16 *rrc);
 int __kvm_s390_handle_dat_fault(struct kvm_vcpu *vcpu, gfn_t gfn, gpa_t gaddr, unsigned int flags);
+int __kvm_s390_mprotect_many(struct gmap *gmap, gpa_t gpa, u8 npages, unsigned int prot,
+			     unsigned long bits);
 
 static inline int kvm_s390_handle_dat_fault(struct kvm_vcpu *vcpu, gpa_t gaddr, unsigned int flags)
 {
diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c
index a687695d8f68..4fef3b38bd70 100644
--- a/arch/s390/kvm/vsie.c
+++ b/arch/s390/kvm/vsie.c
@@ -13,6 +13,7 @@
 #include <linux/bitmap.h>
 #include <linux/sched/signal.h>
 #include <linux/io.h>
+#include <linux/mman.h>
 
 #include <asm/gmap.h>
 #include <asm/mmu_context.h>
@@ -22,6 +23,7 @@
 #include <asm/facility.h>
 #include "kvm-s390.h"
 #include "gaccess.h"
+#include "gmap.h"
 
 struct vsie_page {
 	struct kvm_s390_sie_block scb_s;	/* 0x0000 */
diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c
index 7fd298732d1e..ae71b401312b 100644
--- a/arch/s390/mm/gmap.c
+++ b/arch/s390/mm/gmap.c
@@ -43,7 +43,7 @@ static struct page *gmap_alloc_crst(void)
  *
  * Returns a guest address space structure.
  */
-static struct gmap *gmap_alloc(unsigned long limit)
+struct gmap *gmap_alloc(unsigned long limit)
 {
 	struct gmap *gmap;
 	struct page *page;
@@ -97,6 +97,7 @@ static struct gmap *gmap_alloc(unsigned long limit)
 out:
 	return NULL;
 }
+EXPORT_SYMBOL_GPL(gmap_alloc);
 
 /**
  * gmap_create - create a guest address space
@@ -191,7 +192,7 @@ static void gmap_rmap_radix_tree_free(struct radix_tree_root *root)
  *
  * No locks required. There are no references to this gmap anymore.
  */
-static void gmap_free(struct gmap *gmap)
+void gmap_free(struct gmap *gmap)
 {
 	struct page *page, *next;
 
@@ -218,6 +219,7 @@ static void gmap_free(struct gmap *gmap)
 
 	kfree(gmap);
 }
+EXPORT_SYMBOL_GPL(gmap_free);
 
 /**
  * gmap_get - increase reference counter for guest address space
@@ -958,86 +960,40 @@ static int gmap_protect_pte(struct gmap *gmap, unsigned long gaddr,
  * @prot: indicates access rights: PROT_NONE, PROT_READ or PROT_WRITE
  * @bits: pgste notification bits to set
  *
- * Returns 0 if successfully protected, -ENOMEM if out of memory and
- * -EFAULT if gaddr is invalid (or mapping for shadows is missing).
+ * Returns:
+ *   PAGE_SIZE if a small page was successfully protected;
+ *   HPAGE_SIZE if a large page was successfully protected;
+ *   -ENOMEM if out of memory;
+ *   -EFAULT if gaddr is invalid (or mapping for shadows is missing);
+ *   -EAGAIN if the guest mapping is missing and should be fixed by the caller.
  *
- * Called with sg->mm->mmap_lock in read.
+ * Context: Called with sg->mm->mmap_lock in read.
  */
-static int gmap_protect_range(struct gmap *gmap, unsigned long gaddr,
-			      unsigned long len, int prot, unsigned long bits)
+int gmap_protect_one(struct gmap *gmap, unsigned long gaddr, int prot, unsigned long bits)
 {
-	unsigned long vmaddr, dist;
 	pmd_t *pmdp;
-	int rc;
+	int rc = 0;
 
 	BUG_ON(gmap_is_shadow(gmap));
-	while (len) {
-		rc = -EAGAIN;
-		pmdp = gmap_pmd_op_walk(gmap, gaddr);
-		if (pmdp) {
-			if (!pmd_leaf(*pmdp)) {
-				rc = gmap_protect_pte(gmap, gaddr, pmdp, prot,
-						      bits);
-				if (!rc) {
-					len -= PAGE_SIZE;
-					gaddr += PAGE_SIZE;
-				}
-			} else {
-				rc = gmap_protect_pmd(gmap, gaddr, pmdp, prot,
-						      bits);
-				if (!rc) {
-					dist = HPAGE_SIZE - (gaddr & ~HPAGE_MASK);
-					len = len < dist ? 0 : len - dist;
-					gaddr = (gaddr & HPAGE_MASK) + HPAGE_SIZE;
-				}
-			}
-			gmap_pmd_op_end(gmap, pmdp);
-		}
-		if (rc) {
-			if (rc == -EINVAL)
-				return rc;
 
-			/* -EAGAIN, fixup of userspace mm and gmap */
-			vmaddr = __gmap_translate(gmap, gaddr);
-			if (IS_ERR_VALUE(vmaddr))
-				return vmaddr;
-			rc = gmap_pte_op_fixup(gmap, gaddr, vmaddr, prot);
-			if (rc)
-				return rc;
-		}
-	}
-	return 0;
-}
+	pmdp = gmap_pmd_op_walk(gmap, gaddr);
+	if (!pmdp)
+		return -EAGAIN;
 
-/**
- * gmap_mprotect_notify - change access rights for a range of ptes and
- *                        call the notifier if any pte changes again
- * @gmap: pointer to guest mapping meta data structure
- * @gaddr: virtual address in the guest address space
- * @len: size of area
- * @prot: indicates access rights: PROT_NONE, PROT_READ or PROT_WRITE
- *
- * Returns 0 if for each page in the given range a gmap mapping exists,
- * the new access rights could be set and the notifier could be armed.
- * If the gmap mapping is missing for one or more pages -EFAULT is
- * returned. If no memory could be allocated -ENOMEM is returned.
- * This function establishes missing page table entries.
- */
-int gmap_mprotect_notify(struct gmap *gmap, unsigned long gaddr,
-			 unsigned long len, int prot)
-{
-	int rc;
+	if (!pmd_leaf(*pmdp)) {
+		rc = gmap_protect_pte(gmap, gaddr, pmdp, prot, bits);
+		if (!rc)
+			rc = PAGE_SIZE;
+	} else {
+		rc = gmap_protect_pmd(gmap, gaddr, pmdp, prot, bits);
+		if (!rc)
+			rc = HPAGE_SIZE;
+	}
+	gmap_pmd_op_end(gmap, pmdp);
 
-	if ((gaddr & ~PAGE_MASK) || (len & ~PAGE_MASK) || gmap_is_shadow(gmap))
-		return -EINVAL;
-	if (!MACHINE_HAS_ESOP && prot == PROT_READ)
-		return -EINVAL;
-	mmap_read_lock(gmap->mm);
-	rc = gmap_protect_range(gmap, gaddr, len, prot, GMAP_NOTIFY_MPROT);
-	mmap_read_unlock(gmap->mm);
 	return rc;
 }
-EXPORT_SYMBOL_GPL(gmap_mprotect_notify);
+EXPORT_SYMBOL_GPL(gmap_protect_one);
 
 /**
  * gmap_read_table - get an unsigned long value from a guest page table using
@@ -1488,7 +1444,7 @@ static void __gmap_unshadow_r1t(struct gmap *sg, unsigned long raddr,
  *
  * Called with sg->guest_table_lock
  */
-static void gmap_unshadow(struct gmap *sg)
+void gmap_unshadow(struct gmap *sg)
 {
 	unsigned long *table;
 
@@ -1514,143 +1470,7 @@ static void gmap_unshadow(struct gmap *sg)
 		break;
 	}
 }
-
-/**
- * gmap_find_shadow - find a specific asce in the list of shadow tables
- * @parent: pointer to the parent gmap
- * @asce: ASCE for which the shadow table is created
- * @edat_level: edat level to be used for the shadow translation
- *
- * Returns the pointer to a gmap if a shadow table with the given asce is
- * already available, ERR_PTR(-EAGAIN) if another one is just being created,
- * otherwise NULL
- */
-static struct gmap *gmap_find_shadow(struct gmap *parent, unsigned long asce,
-				     int edat_level)
-{
-	struct gmap *sg;
-
-	list_for_each_entry(sg, &parent->children, list) {
-		if (sg->orig_asce != asce || sg->edat_level != edat_level ||
-		    sg->removed)
-			continue;
-		if (!sg->initialized)
-			return ERR_PTR(-EAGAIN);
-		refcount_inc(&sg->ref_count);
-		return sg;
-	}
-	return NULL;
-}
-
-/**
- * gmap_shadow_valid - check if a shadow guest address space matches the
- *                     given properties and is still valid
- * @sg: pointer to the shadow guest address space structure
- * @asce: ASCE for which the shadow table is requested
- * @edat_level: edat level to be used for the shadow translation
- *
- * Returns 1 if the gmap shadow is still valid and matches the given
- * properties, the caller can continue using it. Returns 0 otherwise, the
- * caller has to request a new shadow gmap in this case.
- *
- */
-int gmap_shadow_valid(struct gmap *sg, unsigned long asce, int edat_level)
-{
-	if (sg->removed)
-		return 0;
-	return sg->orig_asce == asce && sg->edat_level == edat_level;
-}
-EXPORT_SYMBOL_GPL(gmap_shadow_valid);
-
-/**
- * gmap_shadow - create/find a shadow guest address space
- * @parent: pointer to the parent gmap
- * @asce: ASCE for which the shadow table is created
- * @edat_level: edat level to be used for the shadow translation
- *
- * The pages of the top level page table referred by the asce parameter
- * will be set to read-only and marked in the PGSTEs of the kvm process.
- * The shadow table will be removed automatically on any change to the
- * PTE mapping for the source table.
- *
- * Returns a guest address space structure, ERR_PTR(-ENOMEM) if out of memory,
- * ERR_PTR(-EAGAIN) if the caller has to retry and ERR_PTR(-EFAULT) if the
- * parent gmap table could not be protected.
- */
-struct gmap *gmap_shadow(struct gmap *parent, unsigned long asce,
-			 int edat_level)
-{
-	struct gmap *sg, *new;
-	unsigned long limit;
-	int rc;
-
-	BUG_ON(parent->mm->context.allow_gmap_hpage_1m);
-	BUG_ON(gmap_is_shadow(parent));
-	spin_lock(&parent->shadow_lock);
-	sg = gmap_find_shadow(parent, asce, edat_level);
-	spin_unlock(&parent->shadow_lock);
-	if (sg)
-		return sg;
-	/* Create a new shadow gmap */
-	limit = -1UL >> (33 - (((asce & _ASCE_TYPE_MASK) >> 2) * 11));
-	if (asce & _ASCE_REAL_SPACE)
-		limit = -1UL;
-	new = gmap_alloc(limit);
-	if (!new)
-		return ERR_PTR(-ENOMEM);
-	new->mm = parent->mm;
-	new->parent = gmap_get(parent);
-	new->private = parent->private;
-	new->orig_asce = asce;
-	new->edat_level = edat_level;
-	new->initialized = false;
-	spin_lock(&parent->shadow_lock);
-	/* Recheck if another CPU created the same shadow */
-	sg = gmap_find_shadow(parent, asce, edat_level);
-	if (sg) {
-		spin_unlock(&parent->shadow_lock);
-		gmap_free(new);
-		return sg;
-	}
-	if (asce & _ASCE_REAL_SPACE) {
-		/* only allow one real-space gmap shadow */
-		list_for_each_entry(sg, &parent->children, list) {
-			if (sg->orig_asce & _ASCE_REAL_SPACE) {
-				spin_lock(&sg->guest_table_lock);
-				gmap_unshadow(sg);
-				spin_unlock(&sg->guest_table_lock);
-				list_del(&sg->list);
-				gmap_put(sg);
-				break;
-			}
-		}
-	}
-	refcount_set(&new->ref_count, 2);
-	list_add(&new->list, &parent->children);
-	if (asce & _ASCE_REAL_SPACE) {
-		/* nothing to protect, return right away */
-		new->initialized = true;
-		spin_unlock(&parent->shadow_lock);
-		return new;
-	}
-	spin_unlock(&parent->shadow_lock);
-	/* protect after insertion, so it will get properly invalidated */
-	mmap_read_lock(parent->mm);
-	rc = gmap_protect_range(parent, asce & _ASCE_ORIGIN,
-				((asce & _ASCE_TABLE_LENGTH) + 1) * PAGE_SIZE,
-				PROT_READ, GMAP_NOTIFY_SHADOW);
-	mmap_read_unlock(parent->mm);
-	spin_lock(&parent->shadow_lock);
-	new->initialized = true;
-	if (rc) {
-		list_del(&new->list);
-		gmap_free(new);
-		new = ERR_PTR(rc);
-	}
-	spin_unlock(&parent->shadow_lock);
-	return new;
-}
-EXPORT_SYMBOL_GPL(gmap_shadow);
+EXPORT_SYMBOL(gmap_unshadow);
 
 /**
  * gmap_shadow_r2t - create an empty shadow region 2 table
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v3 10/15] KVM: s390: stop using page->index for non-shadow gmaps
  2025-01-17 19:09 [PATCH v3 00/15] KVM: s390: Stop using page->index and other things Claudio Imbrenda
                   ` (8 preceding siblings ...)
  2025-01-17 19:09 ` [PATCH v3 09/15] KVM: s390: move some gmap shadowing functions away from mm/gmap.c Claudio Imbrenda
@ 2025-01-17 19:09 ` Claudio Imbrenda
  2025-01-21 13:41   ` Janosch Frank
  2025-01-17 19:09 ` [PATCH v3 11/15] KVM: s390: stop using lists to keep track of used dat tables Claudio Imbrenda
                   ` (4 subsequent siblings)
  14 siblings, 1 reply; 42+ messages in thread
From: Claudio Imbrenda @ 2025-01-17 19:09 UTC (permalink / raw)
  To: kvm
  Cc: linux-s390, frankja, borntraeger, schlameuss, david, willy, hca,
	svens, agordeev, gor, nrb, nsg, seanjc, seiden

The host_to_guest radix tree will now map userspace addresses to guest
addresses, instead of userspace addresses to segment tables.

When segment tables and page tables are needed, they are found using an
additional gmap_table_walk().

This gets rid of all usage of page->index for non-shadow gmaps.

Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
---
 arch/s390/mm/gmap.c | 105 +++++++++++++++++++++++---------------------
 1 file changed, 54 insertions(+), 51 deletions(-)

diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c
index ae71b401312b..1f83262a5a55 100644
--- a/arch/s390/mm/gmap.c
+++ b/arch/s390/mm/gmap.c
@@ -24,8 +24,20 @@
 #include <asm/page.h>
 #include <asm/tlb.h>
 
+/*
+ * The address is saved in a radix tree directly; NULL would be ambiguous,
+ * since 0 is a valid address, and NULL is returned when nothing was found.
+ * The lower bits are ignored by all users of the macro, so it can be used
+ * to distinguish a valid address 0 from a NULL.
+ */
+#define VALID_GADDR_FLAG 1
+#define IS_GADDR_VALID(gaddr) ((gaddr) & VALID_GADDR_FLAG)
+#define MAKE_VALID_GADDR(gaddr) (((gaddr) & HPAGE_MASK) | VALID_GADDR_FLAG)
+
 #define GMAP_SHADOW_FAKE_TABLE 1ULL
 
+static inline unsigned long *gmap_table_walk(struct gmap *gmap, unsigned long gaddr, int level);
+
 static struct page *gmap_alloc_crst(void)
 {
 	struct page *page;
@@ -82,7 +94,6 @@ struct gmap *gmap_alloc(unsigned long limit)
 	page = gmap_alloc_crst();
 	if (!page)
 		goto out_free;
-	page->index = 0;
 	list_add(&page->lru, &gmap->crst_list);
 	table = page_to_virt(page);
 	crst_table_init(table, etype);
@@ -303,7 +314,6 @@ static int gmap_alloc_table(struct gmap *gmap, unsigned long *table,
 		list_add(&page->lru, &gmap->crst_list);
 		*table = __pa(new) | _REGION_ENTRY_LENGTH |
 			(*table & _REGION_ENTRY_TYPE_MASK);
-		page->index = gaddr;
 		page = NULL;
 	}
 	spin_unlock(&gmap->guest_table_lock);
@@ -312,21 +322,23 @@ static int gmap_alloc_table(struct gmap *gmap, unsigned long *table,
 	return 0;
 }
 
-/**
- * __gmap_segment_gaddr - find virtual address from segment pointer
- * @entry: pointer to a segment table entry in the guest address space
- *
- * Returns the virtual address in the guest address space for the segment
- */
-static unsigned long __gmap_segment_gaddr(unsigned long *entry)
+static unsigned long host_to_guest_lookup(struct gmap *gmap, unsigned long vmaddr)
 {
-	struct page *page;
-	unsigned long offset;
+	return (unsigned long)radix_tree_lookup(&gmap->host_to_guest, vmaddr >> PMD_SHIFT);
+}
 
-	offset = (unsigned long) entry / sizeof(unsigned long);
-	offset = (offset & (PTRS_PER_PMD - 1)) * PMD_SIZE;
-	page = pmd_pgtable_page((pmd_t *) entry);
-	return page->index + offset;
+static unsigned long host_to_guest_delete(struct gmap *gmap, unsigned long vmaddr)
+{
+	return (unsigned long)radix_tree_delete(&gmap->host_to_guest, vmaddr >> PMD_SHIFT);
+}
+
+static pmd_t *host_to_guest_pmd_delete(struct gmap *gmap, unsigned long vmaddr,
+				       unsigned long *gaddr)
+{
+	*gaddr = host_to_guest_delete(gmap, vmaddr);
+	if (IS_GADDR_VALID(*gaddr))
+		return (pmd_t *)gmap_table_walk(gmap, *gaddr, 1);
+	return NULL;
 }
 
 /**
@@ -338,16 +350,19 @@ static unsigned long __gmap_segment_gaddr(unsigned long *entry)
  */
 static int __gmap_unlink_by_vmaddr(struct gmap *gmap, unsigned long vmaddr)
 {
-	unsigned long *entry;
+	unsigned long gaddr;
 	int flush = 0;
+	pmd_t *pmdp;
 
 	BUG_ON(gmap_is_shadow(gmap));
 	spin_lock(&gmap->guest_table_lock);
-	entry = radix_tree_delete(&gmap->host_to_guest, vmaddr >> PMD_SHIFT);
-	if (entry) {
-		flush = (*entry != _SEGMENT_ENTRY_EMPTY);
-		*entry = _SEGMENT_ENTRY_EMPTY;
+
+	pmdp = host_to_guest_pmd_delete(gmap, vmaddr, &gaddr);
+	if (pmdp) {
+		flush = (pmd_val(*pmdp) != _SEGMENT_ENTRY_EMPTY);
+		*pmdp = __pmd(_SEGMENT_ENTRY_EMPTY);
 	}
+
 	spin_unlock(&gmap->guest_table_lock);
 	return flush;
 }
@@ -564,7 +579,8 @@ int __gmap_link(struct gmap *gmap, unsigned long gaddr, unsigned long vmaddr)
 	spin_lock(&gmap->guest_table_lock);
 	if (*table == _SEGMENT_ENTRY_EMPTY) {
 		rc = radix_tree_insert(&gmap->host_to_guest,
-				       vmaddr >> PMD_SHIFT, table);
+				       vmaddr >> PMD_SHIFT,
+				       (void *)MAKE_VALID_GADDR(gaddr));
 		if (!rc) {
 			if (pmd_leaf(*pmd)) {
 				*table = (pmd_val(*pmd) &
@@ -1995,7 +2011,6 @@ void ptep_notify(struct mm_struct *mm, unsigned long vmaddr,
 		 pte_t *pte, unsigned long bits)
 {
 	unsigned long offset, gaddr = 0;
-	unsigned long *table;
 	struct gmap *gmap, *sg, *next;
 
 	offset = ((unsigned long) pte) & (255 * sizeof(pte_t));
@@ -2003,12 +2018,9 @@ void ptep_notify(struct mm_struct *mm, unsigned long vmaddr,
 	rcu_read_lock();
 	list_for_each_entry_rcu(gmap, &mm->context.gmap_list, list) {
 		spin_lock(&gmap->guest_table_lock);
-		table = radix_tree_lookup(&gmap->host_to_guest,
-					  vmaddr >> PMD_SHIFT);
-		if (table)
-			gaddr = __gmap_segment_gaddr(table) + offset;
+		gaddr = host_to_guest_lookup(gmap, vmaddr) + offset;
 		spin_unlock(&gmap->guest_table_lock);
-		if (!table)
+		if (!IS_GADDR_VALID(gaddr))
 			continue;
 
 		if (!list_empty(&gmap->children) && (bits & PGSTE_VSIE_BIT)) {
@@ -2068,10 +2080,8 @@ static void gmap_pmdp_clear(struct mm_struct *mm, unsigned long vmaddr,
 	rcu_read_lock();
 	list_for_each_entry_rcu(gmap, &mm->context.gmap_list, list) {
 		spin_lock(&gmap->guest_table_lock);
-		pmdp = (pmd_t *)radix_tree_delete(&gmap->host_to_guest,
-						  vmaddr >> PMD_SHIFT);
+		pmdp = host_to_guest_pmd_delete(gmap, vmaddr, &gaddr);
 		if (pmdp) {
-			gaddr = __gmap_segment_gaddr((unsigned long *)pmdp);
 			pmdp_notify_gmap(gmap, pmdp, gaddr);
 			WARN_ON(pmd_val(*pmdp) & ~(_SEGMENT_ENTRY_HARDWARE_BITS_LARGE |
 						   _SEGMENT_ENTRY_GMAP_UC |
@@ -2115,28 +2125,25 @@ EXPORT_SYMBOL_GPL(gmap_pmdp_csp);
  */
 void gmap_pmdp_idte_local(struct mm_struct *mm, unsigned long vmaddr)
 {
-	unsigned long *entry, gaddr;
+	unsigned long gaddr;
 	struct gmap *gmap;
 	pmd_t *pmdp;
 
 	rcu_read_lock();
 	list_for_each_entry_rcu(gmap, &mm->context.gmap_list, list) {
 		spin_lock(&gmap->guest_table_lock);
-		entry = radix_tree_delete(&gmap->host_to_guest,
-					  vmaddr >> PMD_SHIFT);
-		if (entry) {
-			pmdp = (pmd_t *)entry;
-			gaddr = __gmap_segment_gaddr(entry);
+		pmdp = host_to_guest_pmd_delete(gmap, vmaddr, &gaddr);
+		if (pmdp) {
 			pmdp_notify_gmap(gmap, pmdp, gaddr);
-			WARN_ON(*entry & ~(_SEGMENT_ENTRY_HARDWARE_BITS_LARGE |
-					   _SEGMENT_ENTRY_GMAP_UC |
-					   _SEGMENT_ENTRY));
+			WARN_ON(pmd_val(*pmdp) & ~(_SEGMENT_ENTRY_HARDWARE_BITS_LARGE |
+						   _SEGMENT_ENTRY_GMAP_UC |
+						   _SEGMENT_ENTRY));
 			if (MACHINE_HAS_TLB_GUEST)
 				__pmdp_idte(gaddr, pmdp, IDTE_GUEST_ASCE,
 					    gmap->asce, IDTE_LOCAL);
 			else if (MACHINE_HAS_IDTE)
 				__pmdp_idte(gaddr, pmdp, 0, 0, IDTE_LOCAL);
-			*entry = _SEGMENT_ENTRY_EMPTY;
+			*pmdp = __pmd(_SEGMENT_ENTRY_EMPTY);
 		}
 		spin_unlock(&gmap->guest_table_lock);
 	}
@@ -2151,22 +2158,19 @@ EXPORT_SYMBOL_GPL(gmap_pmdp_idte_local);
  */
 void gmap_pmdp_idte_global(struct mm_struct *mm, unsigned long vmaddr)
 {
-	unsigned long *entry, gaddr;
+	unsigned long gaddr;
 	struct gmap *gmap;
 	pmd_t *pmdp;
 
 	rcu_read_lock();
 	list_for_each_entry_rcu(gmap, &mm->context.gmap_list, list) {
 		spin_lock(&gmap->guest_table_lock);
-		entry = radix_tree_delete(&gmap->host_to_guest,
-					  vmaddr >> PMD_SHIFT);
-		if (entry) {
-			pmdp = (pmd_t *)entry;
-			gaddr = __gmap_segment_gaddr(entry);
+		pmdp = host_to_guest_pmd_delete(gmap, vmaddr, &gaddr);
+		if (pmdp) {
 			pmdp_notify_gmap(gmap, pmdp, gaddr);
-			WARN_ON(*entry & ~(_SEGMENT_ENTRY_HARDWARE_BITS_LARGE |
-					   _SEGMENT_ENTRY_GMAP_UC |
-					   _SEGMENT_ENTRY));
+			WARN_ON(pmd_val(*pmdp) & ~(_SEGMENT_ENTRY_HARDWARE_BITS_LARGE |
+						   _SEGMENT_ENTRY_GMAP_UC |
+						   _SEGMENT_ENTRY));
 			if (MACHINE_HAS_TLB_GUEST)
 				__pmdp_idte(gaddr, pmdp, IDTE_GUEST_ASCE,
 					    gmap->asce, IDTE_GLOBAL);
@@ -2174,7 +2178,7 @@ void gmap_pmdp_idte_global(struct mm_struct *mm, unsigned long vmaddr)
 				__pmdp_idte(gaddr, pmdp, 0, 0, IDTE_GLOBAL);
 			else
 				__pmdp_csp(pmdp);
-			*entry = _SEGMENT_ENTRY_EMPTY;
+			*pmdp = __pmd(_SEGMENT_ENTRY_EMPTY);
 		}
 		spin_unlock(&gmap->guest_table_lock);
 	}
@@ -2690,7 +2694,6 @@ int s390_replace_asce(struct gmap *gmap)
 	page = gmap_alloc_crst();
 	if (!page)
 		return -ENOMEM;
-	page->index = 0;
 	table = page_to_virt(page);
 	memcpy(table, gmap->table, 1UL << (CRST_ALLOC_ORDER + PAGE_SHIFT));
 
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v3 11/15] KVM: s390: stop using lists to keep track of used dat tables
  2025-01-17 19:09 [PATCH v3 00/15] KVM: s390: Stop using page->index and other things Claudio Imbrenda
                   ` (9 preceding siblings ...)
  2025-01-17 19:09 ` [PATCH v3 10/15] KVM: s390: stop using page->index for non-shadow gmaps Claudio Imbrenda
@ 2025-01-17 19:09 ` Claudio Imbrenda
  2025-01-20 15:10   ` Steffen Eiden
                     ` (2 more replies)
  2025-01-17 19:09 ` [PATCH v3 12/15] KVM: s390: move gmap_shadow_pgt_lookup() into kvm Claudio Imbrenda
                   ` (3 subsequent siblings)
  14 siblings, 3 replies; 42+ messages in thread
From: Claudio Imbrenda @ 2025-01-17 19:09 UTC (permalink / raw)
  To: kvm
  Cc: linux-s390, frankja, borntraeger, schlameuss, david, willy, hca,
	svens, agordeev, gor, nrb, nsg, seanjc, seiden

Until now, every dat table allocated to map a guest was put in a
linked list. The page->lru field of struct page was used to keep track
of which pages were being used, and when the gmap is torn down, the
list was walked and all pages freed.

This patch gets rid of the usage of page->lru. Page tables are now
freed by recursively walking the dat table tree.

Since s390_unlist_old_asce() becomes useless now, remove it.

Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
---
 arch/s390/include/asm/gmap.h |   3 --
 arch/s390/mm/gmap.c          | 102 ++++++++---------------------------
 2 files changed, 23 insertions(+), 82 deletions(-)

diff --git a/arch/s390/include/asm/gmap.h b/arch/s390/include/asm/gmap.h
index dbf2329281d2..904d97f0bc5e 100644
--- a/arch/s390/include/asm/gmap.h
+++ b/arch/s390/include/asm/gmap.h
@@ -45,7 +45,6 @@
  */
 struct gmap {
 	struct list_head list;
-	struct list_head crst_list;
 	struct mm_struct *mm;
 	struct radix_tree_root guest_to_host;
 	struct radix_tree_root host_to_guest;
@@ -61,7 +60,6 @@ struct gmap {
 	/* Additional data for shadow guest address spaces */
 	struct radix_tree_root host_to_rmap;
 	struct list_head children;
-	struct list_head pt_list;
 	spinlock_t shadow_lock;
 	struct gmap *parent;
 	unsigned long orig_asce;
@@ -141,7 +139,6 @@ int gmap_protect_one(struct gmap *gmap, unsigned long gaddr, int prot, unsigned
 void gmap_sync_dirty_log_pmd(struct gmap *gmap, unsigned long dirty_bitmap[4],
 			     unsigned long gaddr, unsigned long vmaddr);
 int s390_disable_cow_sharing(void);
-void s390_unlist_old_asce(struct gmap *gmap);
 int s390_replace_asce(struct gmap *gmap);
 void s390_uv_destroy_pfns(unsigned long count, unsigned long *pfns);
 int __s390_uv_destroy_range(struct mm_struct *mm, unsigned long start,
diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c
index 1f83262a5a55..07df1a7b5ebe 100644
--- a/arch/s390/mm/gmap.c
+++ b/arch/s390/mm/gmap.c
@@ -82,9 +82,7 @@ struct gmap *gmap_alloc(unsigned long limit)
 	gmap = kzalloc(sizeof(struct gmap), GFP_KERNEL_ACCOUNT);
 	if (!gmap)
 		goto out;
-	INIT_LIST_HEAD(&gmap->crst_list);
 	INIT_LIST_HEAD(&gmap->children);
-	INIT_LIST_HEAD(&gmap->pt_list);
 	INIT_RADIX_TREE(&gmap->guest_to_host, GFP_KERNEL_ACCOUNT);
 	INIT_RADIX_TREE(&gmap->host_to_guest, GFP_ATOMIC | __GFP_ACCOUNT);
 	INIT_RADIX_TREE(&gmap->host_to_rmap, GFP_ATOMIC | __GFP_ACCOUNT);
@@ -94,7 +92,6 @@ struct gmap *gmap_alloc(unsigned long limit)
 	page = gmap_alloc_crst();
 	if (!page)
 		goto out_free;
-	list_add(&page->lru, &gmap->crst_list);
 	table = page_to_virt(page);
 	crst_table_init(table, etype);
 	gmap->table = table;
@@ -197,6 +194,27 @@ static void gmap_rmap_radix_tree_free(struct radix_tree_root *root)
 	} while (nr > 0);
 }
 
+static void gmap_free_crst(unsigned long *table, bool free_ptes)
+{
+	bool is_segment = (table[0] & _SEGMENT_ENTRY_TYPE_MASK) == 0;
+	int i;
+
+	if (is_segment) {
+		if (!free_ptes)
+			goto out;
+		for (i = 0; i < _CRST_ENTRIES; i++)
+			if (!(table[i] & _SEGMENT_ENTRY_INVALID))
+				page_table_free_pgste(page_ptdesc(phys_to_page(table[i])));
+	} else {
+		for (i = 0; i < _CRST_ENTRIES; i++)
+			if (!(table[i] & _REGION_ENTRY_INVALID))
+				gmap_free_crst(__va(table[i] & PAGE_MASK), free_ptes);
+	}
+
+out:
+	free_pages((unsigned long)table, CRST_ALLOC_ORDER);
+}
+
 /**
  * gmap_free - free a guest address space
  * @gmap: pointer to the guest address space structure
@@ -205,24 +223,17 @@ static void gmap_rmap_radix_tree_free(struct radix_tree_root *root)
  */
 void gmap_free(struct gmap *gmap)
 {
-	struct page *page, *next;
-
 	/* Flush tlb of all gmaps (if not already done for shadows) */
 	if (!(gmap_is_shadow(gmap) && gmap->removed))
 		gmap_flush_tlb(gmap);
 	/* Free all segment & region tables. */
-	list_for_each_entry_safe(page, next, &gmap->crst_list, lru)
-		__free_pages(page, CRST_ALLOC_ORDER);
+	gmap_free_crst(gmap->table, gmap_is_shadow(gmap));
+
 	gmap_radix_tree_free(&gmap->guest_to_host);
 	gmap_radix_tree_free(&gmap->host_to_guest);
 
 	/* Free additional data for a shadow gmap */
 	if (gmap_is_shadow(gmap)) {
-		struct ptdesc *ptdesc, *n;
-
-		/* Free all page tables. */
-		list_for_each_entry_safe(ptdesc, n, &gmap->pt_list, pt_list)
-			page_table_free_pgste(ptdesc);
 		gmap_rmap_radix_tree_free(&gmap->host_to_rmap);
 		/* Release reference to the parent */
 		gmap_put(gmap->parent);
@@ -311,7 +322,6 @@ static int gmap_alloc_table(struct gmap *gmap, unsigned long *table,
 	crst_table_init(new, init);
 	spin_lock(&gmap->guest_table_lock);
 	if (*table & _REGION_ENTRY_INVALID) {
-		list_add(&page->lru, &gmap->crst_list);
 		*table = __pa(new) | _REGION_ENTRY_LENGTH |
 			(*table & _REGION_ENTRY_TYPE_MASK);
 		page = NULL;
@@ -1243,7 +1253,6 @@ static void gmap_unshadow_pgt(struct gmap *sg, unsigned long raddr)
 	__gmap_unshadow_pgt(sg, raddr, __va(pgt));
 	/* Free page table */
 	ptdesc = page_ptdesc(phys_to_page(pgt));
-	list_del(&ptdesc->pt_list);
 	page_table_free_pgste(ptdesc);
 }
 
@@ -1271,7 +1280,6 @@ static void __gmap_unshadow_sgt(struct gmap *sg, unsigned long raddr,
 		__gmap_unshadow_pgt(sg, raddr, __va(pgt));
 		/* Free page table */
 		ptdesc = page_ptdesc(phys_to_page(pgt));
-		list_del(&ptdesc->pt_list);
 		page_table_free_pgste(ptdesc);
 	}
 }
@@ -1301,7 +1309,6 @@ static void gmap_unshadow_sgt(struct gmap *sg, unsigned long raddr)
 	__gmap_unshadow_sgt(sg, raddr, __va(sgt));
 	/* Free segment table */
 	page = phys_to_page(sgt);
-	list_del(&page->lru);
 	__free_pages(page, CRST_ALLOC_ORDER);
 }
 
@@ -1329,7 +1336,6 @@ static void __gmap_unshadow_r3t(struct gmap *sg, unsigned long raddr,
 		__gmap_unshadow_sgt(sg, raddr, __va(sgt));
 		/* Free segment table */
 		page = phys_to_page(sgt);
-		list_del(&page->lru);
 		__free_pages(page, CRST_ALLOC_ORDER);
 	}
 }
@@ -1359,7 +1365,6 @@ static void gmap_unshadow_r3t(struct gmap *sg, unsigned long raddr)
 	__gmap_unshadow_r3t(sg, raddr, __va(r3t));
 	/* Free region 3 table */
 	page = phys_to_page(r3t);
-	list_del(&page->lru);
 	__free_pages(page, CRST_ALLOC_ORDER);
 }
 
@@ -1387,7 +1392,6 @@ static void __gmap_unshadow_r2t(struct gmap *sg, unsigned long raddr,
 		__gmap_unshadow_r3t(sg, raddr, __va(r3t));
 		/* Free region 3 table */
 		page = phys_to_page(r3t);
-		list_del(&page->lru);
 		__free_pages(page, CRST_ALLOC_ORDER);
 	}
 }
@@ -1417,7 +1421,6 @@ static void gmap_unshadow_r2t(struct gmap *sg, unsigned long raddr)
 	__gmap_unshadow_r2t(sg, raddr, __va(r2t));
 	/* Free region 2 table */
 	page = phys_to_page(r2t);
-	list_del(&page->lru);
 	__free_pages(page, CRST_ALLOC_ORDER);
 }
 
@@ -1449,7 +1452,6 @@ static void __gmap_unshadow_r1t(struct gmap *sg, unsigned long raddr,
 		r1t[i] = _REGION1_ENTRY_EMPTY;
 		/* Free region 2 table */
 		page = phys_to_page(r2t);
-		list_del(&page->lru);
 		__free_pages(page, CRST_ALLOC_ORDER);
 	}
 }
@@ -1544,7 +1546,6 @@ int gmap_shadow_r2t(struct gmap *sg, unsigned long saddr, unsigned long r2t,
 		 _REGION_ENTRY_TYPE_R1 | _REGION_ENTRY_INVALID;
 	if (sg->edat_level >= 1)
 		*table |= (r2t & _REGION_ENTRY_PROTECT);
-	list_add(&page->lru, &sg->crst_list);
 	if (fake) {
 		/* nothing to protect for fake tables */
 		*table &= ~_REGION_ENTRY_INVALID;
@@ -1628,7 +1629,6 @@ int gmap_shadow_r3t(struct gmap *sg, unsigned long saddr, unsigned long r3t,
 		 _REGION_ENTRY_TYPE_R2 | _REGION_ENTRY_INVALID;
 	if (sg->edat_level >= 1)
 		*table |= (r3t & _REGION_ENTRY_PROTECT);
-	list_add(&page->lru, &sg->crst_list);
 	if (fake) {
 		/* nothing to protect for fake tables */
 		*table &= ~_REGION_ENTRY_INVALID;
@@ -1712,7 +1712,6 @@ int gmap_shadow_sgt(struct gmap *sg, unsigned long saddr, unsigned long sgt,
 		 _REGION_ENTRY_TYPE_R3 | _REGION_ENTRY_INVALID;
 	if (sg->edat_level >= 1)
 		*table |= sgt & _REGION_ENTRY_PROTECT;
-	list_add(&page->lru, &sg->crst_list);
 	if (fake) {
 		/* nothing to protect for fake tables */
 		*table &= ~_REGION_ENTRY_INVALID;
@@ -1833,7 +1832,6 @@ int gmap_shadow_pgt(struct gmap *sg, unsigned long saddr, unsigned long pgt,
 	/* mark as invalid as long as the parent table is not protected */
 	*table = (unsigned long) s_pgt | _SEGMENT_ENTRY |
 		 (pgt & _SEGMENT_ENTRY_PROTECT) | _SEGMENT_ENTRY_INVALID;
-	list_add(&ptdesc->pt_list, &sg->pt_list);
 	if (fake) {
 		/* nothing to protect for fake tables */
 		*table &= ~_SEGMENT_ENTRY_INVALID;
@@ -2623,49 +2621,6 @@ int __s390_uv_destroy_range(struct mm_struct *mm, unsigned long start,
 }
 EXPORT_SYMBOL_GPL(__s390_uv_destroy_range);
 
-/**
- * s390_unlist_old_asce - Remove the topmost level of page tables from the
- * list of page tables of the gmap.
- * @gmap: the gmap whose table is to be removed
- *
- * On s390x, KVM keeps a list of all pages containing the page tables of the
- * gmap (the CRST list). This list is used at tear down time to free all
- * pages that are now not needed anymore.
- *
- * This function removes the topmost page of the tree (the one pointed to by
- * the ASCE) from the CRST list.
- *
- * This means that it will not be freed when the VM is torn down, and needs
- * to be handled separately by the caller, unless a leak is actually
- * intended. Notice that this function will only remove the page from the
- * list, the page will still be used as a top level page table (and ASCE).
- */
-void s390_unlist_old_asce(struct gmap *gmap)
-{
-	struct page *old;
-
-	old = virt_to_page(gmap->table);
-	spin_lock(&gmap->guest_table_lock);
-	list_del(&old->lru);
-	/*
-	 * Sometimes the topmost page might need to be "removed" multiple
-	 * times, for example if the VM is rebooted into secure mode several
-	 * times concurrently, or if s390_replace_asce fails after calling
-	 * s390_remove_old_asce and is attempted again later. In that case
-	 * the old asce has been removed from the list, and therefore it
-	 * will not be freed when the VM terminates, but the ASCE is still
-	 * in use and still pointed to.
-	 * A subsequent call to replace_asce will follow the pointer and try
-	 * to remove the same page from the list again.
-	 * Therefore it's necessary that the page of the ASCE has valid
-	 * pointers, so list_del can work (and do nothing) without
-	 * dereferencing stale or invalid pointers.
-	 */
-	INIT_LIST_HEAD(&old->lru);
-	spin_unlock(&gmap->guest_table_lock);
-}
-EXPORT_SYMBOL_GPL(s390_unlist_old_asce);
-
 /**
  * s390_replace_asce - Try to replace the current ASCE of a gmap with a copy
  * @gmap: the gmap whose ASCE needs to be replaced
@@ -2685,8 +2640,6 @@ int s390_replace_asce(struct gmap *gmap)
 	struct page *page;
 	void *table;
 
-	s390_unlist_old_asce(gmap);
-
 	/* Replacing segment type ASCEs would cause serious issues */
 	if ((gmap->asce & _ASCE_TYPE_MASK) == _ASCE_TYPE_SEGMENT)
 		return -EINVAL;
@@ -2697,15 +2650,6 @@ int s390_replace_asce(struct gmap *gmap)
 	table = page_to_virt(page);
 	memcpy(table, gmap->table, 1UL << (CRST_ALLOC_ORDER + PAGE_SHIFT));
 
-	/*
-	 * The caller has to deal with the old ASCE, but here we make sure
-	 * the new one is properly added to the CRST list, so that
-	 * it will be freed when the VM is torn down.
-	 */
-	spin_lock(&gmap->guest_table_lock);
-	list_add(&page->lru, &gmap->crst_list);
-	spin_unlock(&gmap->guest_table_lock);
-
 	/* Set new table origin while preserving existing ASCE control bits */
 	asce = (gmap->asce & ~_ASCE_ORIGIN) | __pa(table);
 	WRITE_ONCE(gmap->asce, asce);
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v3 12/15] KVM: s390: move gmap_shadow_pgt_lookup() into kvm
  2025-01-17 19:09 [PATCH v3 00/15] KVM: s390: Stop using page->index and other things Claudio Imbrenda
                   ` (10 preceding siblings ...)
  2025-01-17 19:09 ` [PATCH v3 11/15] KVM: s390: stop using lists to keep track of used dat tables Claudio Imbrenda
@ 2025-01-17 19:09 ` Claudio Imbrenda
  2025-01-21 14:23   ` Janosch Frank
  2025-01-17 19:09 ` [PATCH v3 13/15] KVM: s390: remove useless page->index usage Claudio Imbrenda
                   ` (2 subsequent siblings)
  14 siblings, 1 reply; 42+ messages in thread
From: Claudio Imbrenda @ 2025-01-17 19:09 UTC (permalink / raw)
  To: kvm
  Cc: linux-s390, frankja, borntraeger, schlameuss, david, willy, hca,
	svens, agordeev, gor, nrb, nsg, seanjc, seiden

Move gmap_shadow_pgt_lookup() from mm/gmap.c into kvm/gaccess.c .

Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
---
 arch/s390/include/asm/gmap.h |  3 +--
 arch/s390/kvm/gaccess.c      | 40 +++++++++++++++++++++++++++++++
 arch/s390/kvm/gmap.h         |  2 ++
 arch/s390/mm/gmap.c          | 46 ++----------------------------------
 4 files changed, 45 insertions(+), 46 deletions(-)

diff --git a/arch/s390/include/asm/gmap.h b/arch/s390/include/asm/gmap.h
index 904d97f0bc5e..bc264c1469f3 100644
--- a/arch/s390/include/asm/gmap.h
+++ b/arch/s390/include/asm/gmap.h
@@ -127,8 +127,6 @@ int gmap_shadow_sgt(struct gmap *sg, unsigned long saddr, unsigned long sgt,
 		    int fake);
 int gmap_shadow_pgt(struct gmap *sg, unsigned long saddr, unsigned long pgt,
 		    int fake);
-int gmap_shadow_pgt_lookup(struct gmap *sg, unsigned long saddr,
-			   unsigned long *pgt, int *dat_protection, int *fake);
 int gmap_shadow_page(struct gmap *sg, unsigned long saddr, pte_t pte);
 
 void gmap_register_pte_notifier(struct gmap_notifier *);
@@ -144,6 +142,7 @@ void s390_uv_destroy_pfns(unsigned long count, unsigned long *pfns);
 int __s390_uv_destroy_range(struct mm_struct *mm, unsigned long start,
 			    unsigned long end, bool interruptible);
 int kvm_s390_wiggle_split_folio(struct mm_struct *mm, struct folio *folio, bool split);
+unsigned long *gmap_table_walk(struct gmap *gmap, unsigned long gaddr, int level);
 
 /**
  * s390_uv_destroy_range - Destroy a range of pages in the given mm.
diff --git a/arch/s390/kvm/gaccess.c b/arch/s390/kvm/gaccess.c
index 9816b0060fbe..560b5677929b 100644
--- a/arch/s390/kvm/gaccess.c
+++ b/arch/s390/kvm/gaccess.c
@@ -16,6 +16,7 @@
 #include <asm/gmap.h>
 #include <asm/dat-bits.h>
 #include "kvm-s390.h"
+#include "gmap.h"
 #include "gaccess.h"
 
 /*
@@ -1392,6 +1393,42 @@ static int kvm_s390_shadow_tables(struct gmap *sg, unsigned long saddr,
 	return 0;
 }
 
+/**
+ * gmap_shadow_pgt_lookup - find a shadow page table
+ * @sg: pointer to the shadow guest address space structure
+ * @saddr: the address in the shadow aguest address space
+ * @pgt: parent gmap address of the page table to get shadowed
+ * @dat_protection: if the pgtable is marked as protected by dat
+ * @fake: pgt references contiguous guest memory block, not a pgtable
+ *
+ * Returns 0 if the shadow page table was found and -EAGAIN if the page
+ * table was not found.
+ *
+ * Called with sg->mm->mmap_lock in read.
+ */
+static int gmap_shadow_pgt_lookup(struct gmap *sg, unsigned long saddr, unsigned long *pgt,
+				  int *dat_protection, int *fake)
+{
+	unsigned long *table;
+	struct page *page;
+	int rc;
+
+	spin_lock(&sg->guest_table_lock);
+	table = gmap_table_walk(sg, saddr, 1); /* get segment pointer */
+	if (table && !(*table & _SEGMENT_ENTRY_INVALID)) {
+		/* Shadow page tables are full pages (pte+pgste) */
+		page = pfn_to_page(*table >> PAGE_SHIFT);
+		*pgt = page->index & ~GMAP_SHADOW_FAKE_TABLE;
+		*dat_protection = !!(*table & _SEGMENT_ENTRY_PROTECT);
+		*fake = !!(page->index & GMAP_SHADOW_FAKE_TABLE);
+		rc = 0;
+	} else  {
+		rc = -EAGAIN;
+	}
+	spin_unlock(&sg->guest_table_lock);
+	return rc;
+}
+
 /**
  * kvm_s390_shadow_fault - handle fault on a shadow page table
  * @vcpu: virtual cpu
@@ -1415,6 +1452,9 @@ int kvm_s390_shadow_fault(struct kvm_vcpu *vcpu, struct gmap *sg,
 	int dat_protection, fake;
 	int rc;
 
+	if (KVM_BUG_ON(!gmap_is_shadow(sg), vcpu->kvm))
+		return -EFAULT;
+
 	mmap_read_lock(sg->mm);
 	/*
 	 * We don't want any guest-2 tables to change - so the parent
diff --git a/arch/s390/kvm/gmap.h b/arch/s390/kvm/gmap.h
index 978f541059f0..c8f031c9ea5f 100644
--- a/arch/s390/kvm/gmap.h
+++ b/arch/s390/kvm/gmap.h
@@ -10,6 +10,8 @@
 #ifndef ARCH_KVM_S390_GMAP_H
 #define ARCH_KVM_S390_GMAP_H
 
+#define GMAP_SHADOW_FAKE_TABLE 1ULL
+
 int gmap_make_secure(struct gmap *gmap, unsigned long gaddr, void *uvcb);
 int gmap_convert_to_secure(struct gmap *gmap, unsigned long gaddr);
 int gmap_destroy_page(struct gmap *gmap, unsigned long gaddr);
diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c
index 07df1a7b5ebe..918ea14515a1 100644
--- a/arch/s390/mm/gmap.c
+++ b/arch/s390/mm/gmap.c
@@ -36,8 +36,6 @@
 
 #define GMAP_SHADOW_FAKE_TABLE 1ULL
 
-static inline unsigned long *gmap_table_walk(struct gmap *gmap, unsigned long gaddr, int level);
-
 static struct page *gmap_alloc_crst(void)
 {
 	struct page *page;
@@ -738,8 +736,7 @@ static void gmap_call_notifier(struct gmap *gmap, unsigned long start,
  *
  * Note: Can also be called for shadow gmaps.
  */
-static inline unsigned long *gmap_table_walk(struct gmap *gmap,
-					     unsigned long gaddr, int level)
+unsigned long *gmap_table_walk(struct gmap *gmap, unsigned long gaddr, int level)
 {
 	const int asce_type = gmap->asce & _ASCE_TYPE_MASK;
 	unsigned long *table = gmap->table;
@@ -790,6 +787,7 @@ static inline unsigned long *gmap_table_walk(struct gmap *gmap,
 	}
 	return table;
 }
+EXPORT_SYMBOL(gmap_table_walk);
 
 /**
  * gmap_pte_op_walk - walk the gmap page table, get the page table lock
@@ -1744,46 +1742,6 @@ int gmap_shadow_sgt(struct gmap *sg, unsigned long saddr, unsigned long sgt,
 }
 EXPORT_SYMBOL_GPL(gmap_shadow_sgt);
 
-/**
- * gmap_shadow_pgt_lookup - find a shadow page table
- * @sg: pointer to the shadow guest address space structure
- * @saddr: the address in the shadow aguest address space
- * @pgt: parent gmap address of the page table to get shadowed
- * @dat_protection: if the pgtable is marked as protected by dat
- * @fake: pgt references contiguous guest memory block, not a pgtable
- *
- * Returns 0 if the shadow page table was found and -EAGAIN if the page
- * table was not found.
- *
- * Called with sg->mm->mmap_lock in read.
- */
-int gmap_shadow_pgt_lookup(struct gmap *sg, unsigned long saddr,
-			   unsigned long *pgt, int *dat_protection,
-			   int *fake)
-{
-	unsigned long *table;
-	struct page *page;
-	int rc;
-
-	BUG_ON(!gmap_is_shadow(sg));
-	spin_lock(&sg->guest_table_lock);
-	table = gmap_table_walk(sg, saddr, 1); /* get segment pointer */
-	if (table && !(*table & _SEGMENT_ENTRY_INVALID)) {
-		/* Shadow page tables are full pages (pte+pgste) */
-		page = pfn_to_page(*table >> PAGE_SHIFT);
-		*pgt = page->index & ~GMAP_SHADOW_FAKE_TABLE;
-		*dat_protection = !!(*table & _SEGMENT_ENTRY_PROTECT);
-		*fake = !!(page->index & GMAP_SHADOW_FAKE_TABLE);
-		rc = 0;
-	} else  {
-		rc = -EAGAIN;
-	}
-	spin_unlock(&sg->guest_table_lock);
-	return rc;
-
-}
-EXPORT_SYMBOL_GPL(gmap_shadow_pgt_lookup);
-
 /**
  * gmap_shadow_pgt - instantiate a shadow page table
  * @sg: pointer to the shadow guest address space structure
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v3 13/15] KVM: s390: remove useless page->index usage
  2025-01-17 19:09 [PATCH v3 00/15] KVM: s390: Stop using page->index and other things Claudio Imbrenda
                   ` (11 preceding siblings ...)
  2025-01-17 19:09 ` [PATCH v3 12/15] KVM: s390: move gmap_shadow_pgt_lookup() into kvm Claudio Imbrenda
@ 2025-01-17 19:09 ` Claudio Imbrenda
  2025-01-17 19:09 ` [PATCH v3 14/15] KVM: s390: move PGSTE softbits Claudio Imbrenda
  2025-01-17 19:09 ` [PATCH v3 15/15] KVM: s390: remove the last user of page->index Claudio Imbrenda
  14 siblings, 0 replies; 42+ messages in thread
From: Claudio Imbrenda @ 2025-01-17 19:09 UTC (permalink / raw)
  To: kvm
  Cc: linux-s390, frankja, borntraeger, schlameuss, david, willy, hca,
	svens, agordeev, gor, nrb, nsg, seanjc, seiden

The page->index field for VSIE dat tables is only used for segment
tables.

Stop setting the field for all region tables.

Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
---
 arch/s390/mm/gmap.c | 9 ---------
 1 file changed, 9 deletions(-)

diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c
index 918ea14515a1..38f044321704 100644
--- a/arch/s390/mm/gmap.c
+++ b/arch/s390/mm/gmap.c
@@ -1520,9 +1520,6 @@ int gmap_shadow_r2t(struct gmap *sg, unsigned long saddr, unsigned long r2t,
 	page = gmap_alloc_crst();
 	if (!page)
 		return -ENOMEM;
-	page->index = r2t & _REGION_ENTRY_ORIGIN;
-	if (fake)
-		page->index |= GMAP_SHADOW_FAKE_TABLE;
 	s_r2t = page_to_phys(page);
 	/* Install shadow region second table */
 	spin_lock(&sg->guest_table_lock);
@@ -1603,9 +1600,6 @@ int gmap_shadow_r3t(struct gmap *sg, unsigned long saddr, unsigned long r3t,
 	page = gmap_alloc_crst();
 	if (!page)
 		return -ENOMEM;
-	page->index = r3t & _REGION_ENTRY_ORIGIN;
-	if (fake)
-		page->index |= GMAP_SHADOW_FAKE_TABLE;
 	s_r3t = page_to_phys(page);
 	/* Install shadow region second table */
 	spin_lock(&sg->guest_table_lock);
@@ -1686,9 +1680,6 @@ int gmap_shadow_sgt(struct gmap *sg, unsigned long saddr, unsigned long sgt,
 	page = gmap_alloc_crst();
 	if (!page)
 		return -ENOMEM;
-	page->index = sgt & _REGION_ENTRY_ORIGIN;
-	if (fake)
-		page->index |= GMAP_SHADOW_FAKE_TABLE;
 	s_sgt = page_to_phys(page);
 	/* Install shadow region second table */
 	spin_lock(&sg->guest_table_lock);
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v3 14/15] KVM: s390: move PGSTE softbits
  2025-01-17 19:09 [PATCH v3 00/15] KVM: s390: Stop using page->index and other things Claudio Imbrenda
                   ` (12 preceding siblings ...)
  2025-01-17 19:09 ` [PATCH v3 13/15] KVM: s390: remove useless page->index usage Claudio Imbrenda
@ 2025-01-17 19:09 ` Claudio Imbrenda
  2025-01-17 19:09 ` [PATCH v3 15/15] KVM: s390: remove the last user of page->index Claudio Imbrenda
  14 siblings, 0 replies; 42+ messages in thread
From: Claudio Imbrenda @ 2025-01-17 19:09 UTC (permalink / raw)
  To: kvm
  Cc: linux-s390, frankja, borntraeger, schlameuss, david, willy, hca,
	svens, agordeev, gor, nrb, nsg, seanjc, seiden

Move the softbits in the PGSTEs to the other usable area.

This leaves the 16-bit block of usable bits free, which will be used in the
next patch for something else.

Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
---
 arch/s390/include/asm/pgtable.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index 48268095b0a3..151488bb9ed7 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -419,9 +419,9 @@ static inline int is_module_addr(void *addr)
 #define PGSTE_HC_BIT	0x0020000000000000UL
 #define PGSTE_GR_BIT	0x0004000000000000UL
 #define PGSTE_GC_BIT	0x0002000000000000UL
-#define PGSTE_UC_BIT	0x0000800000000000UL	/* user dirty (migration) */
-#define PGSTE_IN_BIT	0x0000400000000000UL	/* IPTE notify bit */
-#define PGSTE_VSIE_BIT	0x0000200000000000UL	/* ref'd in a shadow table */
+#define PGSTE_UC_BIT	0x0000000000008000UL	/* user dirty (migration) */
+#define PGSTE_IN_BIT	0x0000000000004000UL	/* IPTE notify bit */
+#define PGSTE_VSIE_BIT	0x0000000000002000UL	/* ref'd in a shadow table */
 
 /* Guest Page State used for virtualization */
 #define _PGSTE_GPS_ZERO			0x0000000080000000UL
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v3 15/15] KVM: s390: remove the last user of page->index
  2025-01-17 19:09 [PATCH v3 00/15] KVM: s390: Stop using page->index and other things Claudio Imbrenda
                   ` (13 preceding siblings ...)
  2025-01-17 19:09 ` [PATCH v3 14/15] KVM: s390: move PGSTE softbits Claudio Imbrenda
@ 2025-01-17 19:09 ` Claudio Imbrenda
  2025-01-21 14:44   ` Janosch Frank
  14 siblings, 1 reply; 42+ messages in thread
From: Claudio Imbrenda @ 2025-01-17 19:09 UTC (permalink / raw)
  To: kvm
  Cc: linux-s390, frankja, borntraeger, schlameuss, david, willy, hca,
	svens, agordeev, gor, nrb, nsg, seanjc, seiden

Shadow page tables use page->index to keep the g2 address of the guest
page table being shadowed.

Instead of keeping the information in page->index, split the address
and smear it over the 16-bit softbits areas of 4 PGSTEs.

This removes the last s390 user of page->index.

Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
---
 arch/s390/include/asm/pgtable.h | 15 +++++++++++++++
 arch/s390/kvm/gaccess.c         |  6 ++++--
 arch/s390/mm/gmap.c             | 22 ++++++++++++++++++++--
 3 files changed, 39 insertions(+), 4 deletions(-)

diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index 151488bb9ed7..948100a8fa7e 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -419,6 +419,7 @@ static inline int is_module_addr(void *addr)
 #define PGSTE_HC_BIT	0x0020000000000000UL
 #define PGSTE_GR_BIT	0x0004000000000000UL
 #define PGSTE_GC_BIT	0x0002000000000000UL
+#define PGSTE_ST2_MASK	0x0000ffff00000000UL
 #define PGSTE_UC_BIT	0x0000000000008000UL	/* user dirty (migration) */
 #define PGSTE_IN_BIT	0x0000000000004000UL	/* IPTE notify bit */
 #define PGSTE_VSIE_BIT	0x0000000000002000UL	/* ref'd in a shadow table */
@@ -2001,4 +2002,18 @@ extern void s390_reset_cmma(struct mm_struct *mm);
 #define pmd_pgtable(pmd) \
 	((pgtable_t)__va(pmd_val(pmd) & -sizeof(pte_t)*PTRS_PER_PTE))
 
+static inline unsigned long gmap_pgste_get_index(unsigned long *pgt)
+{
+	unsigned long *pgstes, res;
+
+	pgstes = pgt + _PAGE_ENTRIES;
+
+	res = (pgstes[0] & PGSTE_ST2_MASK) << 16;
+	res |= pgstes[1] & PGSTE_ST2_MASK;
+	res |= (pgstes[2] & PGSTE_ST2_MASK) >> 16;
+	res |= (pgstes[3] & PGSTE_ST2_MASK) >> 32;
+
+	return res;
+}
+
 #endif /* _S390_PAGE_H */
diff --git a/arch/s390/kvm/gaccess.c b/arch/s390/kvm/gaccess.c
index 560b5677929b..3bf3a80942de 100644
--- a/arch/s390/kvm/gaccess.c
+++ b/arch/s390/kvm/gaccess.c
@@ -1409,6 +1409,7 @@ static int kvm_s390_shadow_tables(struct gmap *sg, unsigned long saddr,
 static int gmap_shadow_pgt_lookup(struct gmap *sg, unsigned long saddr, unsigned long *pgt,
 				  int *dat_protection, int *fake)
 {
+	unsigned long pt_index;
 	unsigned long *table;
 	struct page *page;
 	int rc;
@@ -1418,9 +1419,10 @@ static int gmap_shadow_pgt_lookup(struct gmap *sg, unsigned long saddr, unsigned
 	if (table && !(*table & _SEGMENT_ENTRY_INVALID)) {
 		/* Shadow page tables are full pages (pte+pgste) */
 		page = pfn_to_page(*table >> PAGE_SHIFT);
-		*pgt = page->index & ~GMAP_SHADOW_FAKE_TABLE;
+		pt_index = gmap_pgste_get_index(page_to_virt(page));
+		*pgt = pt_index & ~GMAP_SHADOW_FAKE_TABLE;
 		*dat_protection = !!(*table & _SEGMENT_ENTRY_PROTECT);
-		*fake = !!(page->index & GMAP_SHADOW_FAKE_TABLE);
+		*fake = !!(pt_index & GMAP_SHADOW_FAKE_TABLE);
 		rc = 0;
 	} else  {
 		rc = -EAGAIN;
diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c
index 38f044321704..d678b3fa331d 100644
--- a/arch/s390/mm/gmap.c
+++ b/arch/s390/mm/gmap.c
@@ -1733,6 +1733,23 @@ int gmap_shadow_sgt(struct gmap *sg, unsigned long saddr, unsigned long sgt,
 }
 EXPORT_SYMBOL_GPL(gmap_shadow_sgt);
 
+static void gmap_pgste_set_index(struct ptdesc *ptdesc, unsigned long pgt_addr)
+{
+	unsigned long *pgstes = page_to_virt(ptdesc_page(ptdesc));
+
+	pgstes += _PAGE_ENTRIES;
+
+	pgstes[0] &= ~PGSTE_ST2_MASK;
+	pgstes[1] &= ~PGSTE_ST2_MASK;
+	pgstes[2] &= ~PGSTE_ST2_MASK;
+	pgstes[3] &= ~PGSTE_ST2_MASK;
+
+	pgstes[0] |= (pgt_addr >> 16) & PGSTE_ST2_MASK;
+	pgstes[1] |= pgt_addr & PGSTE_ST2_MASK;
+	pgstes[2] |= (pgt_addr << 16) & PGSTE_ST2_MASK;
+	pgstes[3] |= (pgt_addr << 32) & PGSTE_ST2_MASK;
+}
+
 /**
  * gmap_shadow_pgt - instantiate a shadow page table
  * @sg: pointer to the shadow guest address space structure
@@ -1760,9 +1777,10 @@ int gmap_shadow_pgt(struct gmap *sg, unsigned long saddr, unsigned long pgt,
 	ptdesc = page_table_alloc_pgste(sg->mm);
 	if (!ptdesc)
 		return -ENOMEM;
-	ptdesc->pt_index = pgt & _SEGMENT_ENTRY_ORIGIN;
+	origin = pgt & _SEGMENT_ENTRY_ORIGIN;
 	if (fake)
-		ptdesc->pt_index |= GMAP_SHADOW_FAKE_TABLE;
+		origin |= GMAP_SHADOW_FAKE_TABLE;
+	gmap_pgste_set_index(ptdesc, origin);
 	s_pgt = page_to_phys(ptdesc_page(ptdesc));
 	/* Install shadow page table */
 	spin_lock(&sg->guest_table_lock);
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 01/15] KVM: Do not restrict the size of KVM-internal memory regions
  2025-01-17 19:09 ` [PATCH v3 01/15] KVM: Do not restrict the size of KVM-internal memory regions Claudio Imbrenda
@ 2025-01-20 12:06   ` David Hildenbrand
  0 siblings, 0 replies; 42+ messages in thread
From: David Hildenbrand @ 2025-01-20 12:06 UTC (permalink / raw)
  To: Claudio Imbrenda, kvm
  Cc: linux-s390, frankja, borntraeger, schlameuss, willy, hca, svens,
	agordeev, gor, nrb, nsg, seanjc, seiden

On 17.01.25 20:09, Claudio Imbrenda wrote:
> From: Sean Christopherson <seanjc@google.com>
> 
> Exempt KVM-internal memslots from the KVM_MEM_MAX_NR_PAGES restriction, as
> the limit on the number of pages exists purely to play nice with dirty
> bitmap operations, which use 32-bit values to index the bitmaps, and dirty
> logging isn't supported for KVM-internal memslots.
> 
> Link: https://lore.kernel.org/all/20240802205003.353672-6-seanjc@google.com
> Signed-off-by: Sean Christopherson <seanjc@google.com>
> Reviewed-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
> ---
>   virt/kvm/kvm_main.c | 10 +++++++++-
>   1 file changed, 9 insertions(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
> index a8a84bf450f9..ee3f040a4891 100644
> --- a/virt/kvm/kvm_main.c
> +++ b/virt/kvm/kvm_main.c
> @@ -1966,7 +1966,15 @@ static int kvm_set_memory_region(struct kvm *kvm,
>   		return -EINVAL;
>   	if (mem->guest_phys_addr + mem->memory_size < mem->guest_phys_addr)
>   		return -EINVAL;
> -	if ((mem->memory_size >> PAGE_SHIFT) > KVM_MEM_MAX_NR_PAGES)
> +
> +	/*
> +	 * The size of userspace-defined memory regions is restricted in order
> +	 * to play nice with dirty bitmap operations, which are indexed with an
> +	 * "unsigned int".  KVM's internal memory regions don't support dirty
> +	 * logging, and so are exempt.
> +	 */
> +	if (id < KVM_USER_MEM_SLOTS &&
> +	    (mem->memory_size >> PAGE_SHIFT) > KVM_MEM_MAX_NR_PAGES)
>   		return -EINVAL;
>   
>   	slots = __kvm_memslots(kvm, as_id);


Reviewed-by: David Hildenbrand <david@redhat.com>

-- 
Cheers,

David / dhildenb


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 02/15] KVM: s390: wrapper for KVM_BUG
  2025-01-17 19:09 ` [PATCH v3 02/15] KVM: s390: wrapper for KVM_BUG Claudio Imbrenda
@ 2025-01-20 12:07   ` David Hildenbrand
  0 siblings, 0 replies; 42+ messages in thread
From: David Hildenbrand @ 2025-01-20 12:07 UTC (permalink / raw)
  To: Claudio Imbrenda, kvm
  Cc: linux-s390, frankja, borntraeger, schlameuss, willy, hca, svens,
	agordeev, gor, nrb, nsg, seanjc, seiden

On 17.01.25 20:09, Claudio Imbrenda wrote:
> Wrap the call to KVM_BUG; this reduces code duplication and improves
> readability.
> 
> Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
> Reviewed-by: Christian Borntraeger <borntraeger@linux.ibm.com>
> Reviewed-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
> Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
> ---

Reviewed-by: David Hildenbrand <david@redhat.com>

-- 
Cheers,

David / dhildenb


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 03/15] KVM: s390: fake memslot for ucontrol VMs
  2025-01-17 19:09 ` [PATCH v3 03/15] KVM: s390: fake memslot for ucontrol VMs Claudio Imbrenda
@ 2025-01-20 12:09   ` David Hildenbrand
  2025-01-20 15:27   ` Christoph Schlameuss
  2025-01-21 12:23   ` Janosch Frank
  2 siblings, 0 replies; 42+ messages in thread
From: David Hildenbrand @ 2025-01-20 12:09 UTC (permalink / raw)
  To: Claudio Imbrenda, kvm
  Cc: linux-s390, frankja, borntraeger, schlameuss, willy, hca, svens,
	agordeev, gor, nrb, nsg, seanjc, seiden

On 17.01.25 20:09, Claudio Imbrenda wrote:
> Create a fake memslot for ucontrol VMs. The fake memslot identity-maps
> userspace.
> 
> Now memslots will always be present, and ucontrol is not a special case
> anymore.
> 
> Suggested-by: Sean Christopherson <seanjc@google.com>
> Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
> ---

Reviewed-by: David Hildenbrand <david@redhat.com>

-- 
Cheers,

David / dhildenb


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 04/15] KVM: s390: selftests: fix ucontrol memory region test
  2025-01-17 19:09 ` [PATCH v3 04/15] KVM: s390: selftests: fix ucontrol memory region test Claudio Imbrenda
@ 2025-01-20 12:12   ` David Hildenbrand
  2025-01-20 12:25     ` Claudio Imbrenda
  0 siblings, 1 reply; 42+ messages in thread
From: David Hildenbrand @ 2025-01-20 12:12 UTC (permalink / raw)
  To: Claudio Imbrenda, kvm
  Cc: linux-s390, frankja, borntraeger, schlameuss, willy, hca, svens,
	agordeev, gor, nrb, nsg, seanjc, seiden

On 17.01.25 20:09, Claudio Imbrenda wrote:
> With the latest patch, attempting to create a memslot from userspace
> will result in an EEXIST error for UCONTROL VMs, instead of EINVAL,
> since the new memslot will collide with the internal memslot. There is
> no simple way to bring back the previous behaviour.
> 
> This is not a problem, but the test needs to be fixed accordingly.
> 
> Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
> ---
>   tools/testing/selftests/kvm/s390x/ucontrol_test.c | 6 ++++--
>   1 file changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/tools/testing/selftests/kvm/s390x/ucontrol_test.c b/tools/testing/selftests/kvm/s390x/ucontrol_test.c
> index 135ee22856cf..ca18736257f8 100644
> --- a/tools/testing/selftests/kvm/s390x/ucontrol_test.c
> +++ b/tools/testing/selftests/kvm/s390x/ucontrol_test.c
> @@ -459,10 +459,12 @@ TEST_F(uc_kvm, uc_no_user_region)
>   	};
>   
>   	ASSERT_EQ(-1, ioctl(self->vm_fd, KVM_SET_USER_MEMORY_REGION, &region));
> -	ASSERT_EQ(EINVAL, errno);
> +	if (errno != EEXIST)
> +		ASSERT_EQ(EINVAL, errno);

ASSERT_TRUE(errno == EEXIST || errno == EINVAL)'

?

-- 
Cheers,

David / dhildenb


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 04/15] KVM: s390: selftests: fix ucontrol memory region test
  2025-01-20 12:12   ` David Hildenbrand
@ 2025-01-20 12:25     ` Claudio Imbrenda
  2025-01-20 15:40       ` Christoph Schlameuss
  0 siblings, 1 reply; 42+ messages in thread
From: Claudio Imbrenda @ 2025-01-20 12:25 UTC (permalink / raw)
  To: David Hildenbrand
  Cc: kvm, linux-s390, frankja, borntraeger, schlameuss, willy, hca,
	svens, agordeev, gor, nrb, nsg, seanjc, seiden

On Mon, 20 Jan 2025 13:12:31 +0100
David Hildenbrand <david@redhat.com> wrote:

> On 17.01.25 20:09, Claudio Imbrenda wrote:
> > With the latest patch, attempting to create a memslot from userspace
> > will result in an EEXIST error for UCONTROL VMs, instead of EINVAL,
> > since the new memslot will collide with the internal memslot. There is
> > no simple way to bring back the previous behaviour.
> > 
> > This is not a problem, but the test needs to be fixed accordingly.
> > 
> > Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
> > ---
> >   tools/testing/selftests/kvm/s390x/ucontrol_test.c | 6 ++++--
> >   1 file changed, 4 insertions(+), 2 deletions(-)
> > 
> > diff --git a/tools/testing/selftests/kvm/s390x/ucontrol_test.c b/tools/testing/selftests/kvm/s390x/ucontrol_test.c
> > index 135ee22856cf..ca18736257f8 100644
> > --- a/tools/testing/selftests/kvm/s390x/ucontrol_test.c
> > +++ b/tools/testing/selftests/kvm/s390x/ucontrol_test.c
> > @@ -459,10 +459,12 @@ TEST_F(uc_kvm, uc_no_user_region)
> >   	};
> >   
> >   	ASSERT_EQ(-1, ioctl(self->vm_fd, KVM_SET_USER_MEMORY_REGION, &region));
> > -	ASSERT_EQ(EINVAL, errno);
> > +	if (errno != EEXIST)
> > +		ASSERT_EQ(EINVAL, errno);  
> 
> ASSERT_TRUE(errno == EEXIST || errno == EINVAL)'
> 
> ?
> 

I had thought about that, but in case of failure it won't print the
failing value.

It's probably more readable with the ASSERT_EQ, I will change it.

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 11/15] KVM: s390: stop using lists to keep track of used dat tables
  2025-01-17 19:09 ` [PATCH v3 11/15] KVM: s390: stop using lists to keep track of used dat tables Claudio Imbrenda
@ 2025-01-20 15:10   ` Steffen Eiden
  2025-01-20 15:29     ` Claudio Imbrenda
  2025-01-21 14:09   ` Janosch Frank
  2025-01-22 16:13   ` Christoph Schlameuss
  2 siblings, 1 reply; 42+ messages in thread
From: Steffen Eiden @ 2025-01-20 15:10 UTC (permalink / raw)
  To: Claudio Imbrenda
  Cc: kvm, linux-s390, frankja, borntraeger, schlameuss, david, willy,
	hca, svens, agordeev, gor, nrb, nsg, seanjc

On Fri, Jan 17, 2025 at 08:09:34PM +0100, Claudio Imbrenda wrote:
> Until now, every dat table allocated to map a guest was put in a
> linked list. The page->lru field of struct page was used to keep track
> of which pages were being used, and when the gmap is torn down, the
> list was walked and all pages freed.
> 
> This patch gets rid of the usage of page->lru. Page tables are now
> freed by recursively walking the dat table tree.
> 
> Since s390_unlist_old_asce() becomes useless now, remove it.
> 
> Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>

Acked-by: Steffen Eiden <seiden@linux.ibm.com>

Nit:

You missed one `ptdeѕec->pt_list` reference at

arch/s390/mm/pgalloc.c
	unsigned long *page_table_alloc(struct mm_struct *mm)
		INIT_LIST_HEAD(&ptdesc->pt_list);



Steffen


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 03/15] KVM: s390: fake memslot for ucontrol VMs
  2025-01-17 19:09 ` [PATCH v3 03/15] KVM: s390: fake memslot for ucontrol VMs Claudio Imbrenda
  2025-01-20 12:09   ` David Hildenbrand
@ 2025-01-20 15:27   ` Christoph Schlameuss
  2025-01-21 16:33     ` Claudio Imbrenda
  2025-01-21 12:23   ` Janosch Frank
  2 siblings, 1 reply; 42+ messages in thread
From: Christoph Schlameuss @ 2025-01-20 15:27 UTC (permalink / raw)
  To: Claudio Imbrenda, kvm
  Cc: linux-s390, frankja, borntraeger, david, willy, hca, svens,
	agordeev, gor, nrb, nsg, seanjc, seiden

On Fri Jan 17, 2025 at 8:09 PM CET, Claudio Imbrenda wrote:
> Create a fake memslot for ucontrol VMs. The fake memslot identity-maps
> userspace.
>
> Now memslots will always be present, and ucontrol is not a special case
> anymore.
>
> Suggested-by: Sean Christopherson <seanjc@google.com>
> Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>

LGTM assuming the triggered warning about the slot_lock can be resolved in
another patch.
Tested in G1 and G2 using the ucontrol selftests.

Reviewed-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
Tested-by: Christoph Schlameuss <schlameuss@linux.ibm.com>

> ---
>  Documentation/virt/kvm/api.rst   |  2 +-
>  arch/s390/include/asm/kvm_host.h |  2 ++
>  arch/s390/kvm/kvm-s390.c         | 15 ++++++++++++++-
>  arch/s390/kvm/kvm-s390.h         |  2 ++
>  4 files changed, 19 insertions(+), 2 deletions(-)
>
> diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
> index f15b61317aad..cc98115a96d7 100644
> --- a/Documentation/virt/kvm/api.rst
> +++ b/Documentation/virt/kvm/api.rst
> @@ -1419,7 +1419,7 @@ fetch) is injected in the guest.
>  S390:
>  ^^^^^
>  
> -Returns -EINVAL if the VM has the KVM_VM_S390_UCONTROL flag set.
> +Returns -EINVAL or -EEXIST if the VM has the KVM_VM_S390_UCONTROL flag set.
>  Returns -EINVAL if called on a protected VM.
>  
>  4.36 KVM_SET_TSS_ADDR
> diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
> index 97c7c8127543..9df37361bc64 100644
> --- a/arch/s390/include/asm/kvm_host.h
> +++ b/arch/s390/include/asm/kvm_host.h
> @@ -30,6 +30,8 @@
>  #define KVM_S390_ESCA_CPU_SLOTS 248
>  #define KVM_MAX_VCPUS 255
>  
> +#define KVM_INTERNAL_MEM_SLOTS 1
> +
>  /*
>   * These seem to be used for allocating ->chip in the routing table, which we
>   * don't use. 1 is as small as we can get to reduce the needed memory. If we
> diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
> index ecbdd7d41230..58cc7f7444e5 100644
> --- a/arch/s390/kvm/kvm-s390.c
> +++ b/arch/s390/kvm/kvm-s390.c
> @@ -3428,8 +3428,18 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
>  	VM_EVENT(kvm, 3, "vm created with type %lu", type);
>  
>  	if (type & KVM_VM_S390_UCONTROL) {
> +		struct kvm_userspace_memory_region2 fake_memslot = {
> +			.slot = KVM_S390_UCONTROL_MEMSLOT,
> +			.guest_phys_addr = 0,
> +			.userspace_addr = 0,
> +			.memory_size = ALIGN_DOWN(TASK_SIZE, _SEGMENT_SIZE),
> +			.flags = 0,
> +		};
> +
>  		kvm->arch.gmap = NULL;
>  		kvm->arch.mem_limit = KVM_S390_NO_MEM_LIMIT;
> +		/* one flat fake memslot covering the whole address-space */
> +		KVM_BUG_ON(kvm_set_internal_memslot(kvm, &fake_memslot), kvm);

In the current state of kvm_set_internal_memslot this does not acquire the
slot_lock and issues a warning. I did bring this up on Seans patch introducing
the method. So I assume at this point this here is fine.

>  	} else {
>  		if (sclp.hamax == U64_MAX)
>  			kvm->arch.mem_limit = TASK_SIZE_MAX;
> @@ -5854,7 +5864,7 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
>  {
>  	gpa_t size;
>  
> -	if (kvm_is_ucontrol(kvm))
> +	if (kvm_is_ucontrol(kvm) && new->id < KVM_USER_MEM_SLOTS)
>  		return -EINVAL;
>  
>  	/* When we are protected, we should not change the memory slots */
> @@ -5906,6 +5916,9 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
>  {
>  	int rc = 0;
>  
> +	if (kvm_is_ucontrol(kvm))
> +		return;
> +
>  	switch (change) {
>  	case KVM_MR_DELETE:
>  		rc = gmap_unmap_segment(kvm->arch.gmap, old->base_gfn * PAGE_SIZE,
> diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
> index 597d7a71deeb..30736ac16f84 100644
> --- a/arch/s390/kvm/kvm-s390.h
> +++ b/arch/s390/kvm/kvm-s390.h
> @@ -20,6 +20,8 @@
>  #include <asm/processor.h>
>  #include <asm/sclp.h>
>  
> +#define KVM_S390_UCONTROL_MEMSLOT (KVM_USER_MEM_SLOTS + 0)
> +
>  static inline void kvm_s390_fpu_store(struct kvm_run *run)
>  {
>  	fpu_stfpc(&run->s.regs.fpc);


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 11/15] KVM: s390: stop using lists to keep track of used dat tables
  2025-01-20 15:10   ` Steffen Eiden
@ 2025-01-20 15:29     ` Claudio Imbrenda
  0 siblings, 0 replies; 42+ messages in thread
From: Claudio Imbrenda @ 2025-01-20 15:29 UTC (permalink / raw)
  To: Steffen Eiden
  Cc: kvm, linux-s390, frankja, borntraeger, schlameuss, david, willy,
	hca, svens, agordeev, gor, nrb, nsg, seanjc

On Mon, 20 Jan 2025 16:10:18 +0100
Steffen Eiden <seiden@linux.ibm.com> wrote:

> On Fri, Jan 17, 2025 at 08:09:34PM +0100, Claudio Imbrenda wrote:
> > Until now, every dat table allocated to map a guest was put in a
> > linked list. The page->lru field of struct page was used to keep track
> > of which pages were being used, and when the gmap is torn down, the
> > list was walked and all pages freed.
> > 
> > This patch gets rid of the usage of page->lru. Page tables are now
> > freed by recursively walking the dat table tree.
> > 
> > Since s390_unlist_old_asce() becomes useless now, remove it.
> > 
> > Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>  
> 
> Acked-by: Steffen Eiden <seiden@linux.ibm.com>
> 
> Nit:
> 
> You missed one `ptdeѕec->pt_list` reference at
> 
> arch/s390/mm/pgalloc.c
> 	unsigned long *page_table_alloc(struct mm_struct *mm)
> 		INIT_LIST_HEAD(&ptdesc->pt_list);

yep, removed now, thanks

> 
> 
> 
> Steffen
> 


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 04/15] KVM: s390: selftests: fix ucontrol memory region test
  2025-01-20 12:25     ` Claudio Imbrenda
@ 2025-01-20 15:40       ` Christoph Schlameuss
  0 siblings, 0 replies; 42+ messages in thread
From: Christoph Schlameuss @ 2025-01-20 15:40 UTC (permalink / raw)
  To: Claudio Imbrenda, David Hildenbrand
  Cc: kvm, linux-s390, frankja, borntraeger, willy, hca, svens,
	agordeev, gor, nrb, nsg, seanjc, seiden

On Mon Jan 20, 2025 at 1:25 PM CET, Claudio Imbrenda wrote:
> On Mon, 20 Jan 2025 13:12:31 +0100
> David Hildenbrand <david@redhat.com> wrote:
>
> > On 17.01.25 20:09, Claudio Imbrenda wrote:
> > > With the latest patch, attempting to create a memslot from userspace
> > > will result in an EEXIST error for UCONTROL VMs, instead of EINVAL,
> > > since the new memslot will collide with the internal memslot. There is
> > > no simple way to bring back the previous behaviour.
> > > 
> > > This is not a problem, but the test needs to be fixed accordingly.
> > > 
> > > Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
> > > ---
> > >   tools/testing/selftests/kvm/s390x/ucontrol_test.c | 6 ++++--
> > >   1 file changed, 4 insertions(+), 2 deletions(-)
> > > 
> > > diff --git a/tools/testing/selftests/kvm/s390x/ucontrol_test.c b/tools/testing/selftests/kvm/s390x/ucontrol_test.c
> > > index 135ee22856cf..ca18736257f8 100644
> > > --- a/tools/testing/selftests/kvm/s390x/ucontrol_test.c
> > > +++ b/tools/testing/selftests/kvm/s390x/ucontrol_test.c
> > > @@ -459,10 +459,12 @@ TEST_F(uc_kvm, uc_no_user_region)
> > >   	};
> > >   
> > >   	ASSERT_EQ(-1, ioctl(self->vm_fd, KVM_SET_USER_MEMORY_REGION, &region));
> > > -	ASSERT_EQ(EINVAL, errno);
> > > +	if (errno != EEXIST)
> > > +		ASSERT_EQ(EINVAL, errno);  
> > 
> > ASSERT_TRUE(errno == EEXIST || errno == EINVAL)'
> > 
> > ?
> > 

How about this?

ASSERT_TRUE(errno == EEXIST || errno == EINVAL)
	TH_LOG("errno %s (%i) not expected for ioctl KVM_SET_USER_MEMORY_REGION",
	strerror(errno), errno);

>
> I had thought about that, but in case of failure it won't print the
> failing value.
>
> It's probably more readable with the ASSERT_EQ, I will change it.


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 05/15] KVM: s390: move pv gmap functions into kvm
  2025-01-17 19:09 ` [PATCH v3 05/15] KVM: s390: move pv gmap functions into kvm Claudio Imbrenda
@ 2025-01-21 10:55   ` Christoph Schlameuss
  2025-01-21 12:54   ` Janosch Frank
  1 sibling, 0 replies; 42+ messages in thread
From: Christoph Schlameuss @ 2025-01-21 10:55 UTC (permalink / raw)
  To: Claudio Imbrenda, kvm
  Cc: linux-s390, frankja, borntraeger, david, willy, hca, svens,
	agordeev, gor, nrb, nsg, seanjc, seiden

On Fri Jan 17, 2025 at 8:09 PM CET, Claudio Imbrenda wrote:
> Move gmap related functions from kernel/uv into kvm.
>
> Create a new file to collect gmap-related functions.
>
> Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
> ---
>  arch/s390/include/asm/gmap.h |   1 +
>  arch/s390/include/asm/uv.h   |   6 +-
>  arch/s390/kernel/uv.c        | 292 ++++-------------------------------
>  arch/s390/kvm/Makefile       |   2 +-
>  arch/s390/kvm/gmap.c         | 206 ++++++++++++++++++++++++
>  arch/s390/kvm/gmap.h         |  17 ++
>  arch/s390/kvm/intercept.c    |   1 +
>  arch/s390/kvm/kvm-s390.c     |   1 +
>  arch/s390/kvm/pv.c           |   1 +
>  arch/s390/mm/gmap.c          |  28 ++++
>  10 files changed, 288 insertions(+), 267 deletions(-)
>  create mode 100644 arch/s390/kvm/gmap.c
>  create mode 100644 arch/s390/kvm/gmap.h
>

LGTM

Acked-by: Christoph Schlameuss <schlameuss@linux.ibm.com>


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 03/15] KVM: s390: fake memslot for ucontrol VMs
  2025-01-17 19:09 ` [PATCH v3 03/15] KVM: s390: fake memslot for ucontrol VMs Claudio Imbrenda
  2025-01-20 12:09   ` David Hildenbrand
  2025-01-20 15:27   ` Christoph Schlameuss
@ 2025-01-21 12:23   ` Janosch Frank
  2 siblings, 0 replies; 42+ messages in thread
From: Janosch Frank @ 2025-01-21 12:23 UTC (permalink / raw)
  To: Claudio Imbrenda, kvm
  Cc: linux-s390, borntraeger, schlameuss, david, willy, hca, svens,
	agordeev, gor, nrb, nsg, seanjc, seiden

On 1/17/25 8:09 PM, Claudio Imbrenda wrote:
> Create a fake memslot for ucontrol VMs. The fake memslot identity-maps
> userspace.
> 
> Now memslots will always be present, and ucontrol is not a special case
> anymore.

Reviewed-by: Janosch Frank <frankja@linux.ibm.com>

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 05/15] KVM: s390: move pv gmap functions into kvm
  2025-01-17 19:09 ` [PATCH v3 05/15] KVM: s390: move pv gmap functions into kvm Claudio Imbrenda
  2025-01-21 10:55   ` Christoph Schlameuss
@ 2025-01-21 12:54   ` Janosch Frank
  1 sibling, 0 replies; 42+ messages in thread
From: Janosch Frank @ 2025-01-21 12:54 UTC (permalink / raw)
  To: Claudio Imbrenda, kvm
  Cc: linux-s390, borntraeger, schlameuss, david, willy, hca, svens,
	agordeev, gor, nrb, nsg, seanjc, seiden

On 1/17/25 8:09 PM, Claudio Imbrenda wrote:
> Move gmap related functions from kernel/uv into kvm.
> 
> Create a new file to collect gmap-related functions.
> 
> Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
> ---
>

Looks good now
Reviewed-by: Janosch Frank <frankja@linux.ibm.com>

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 09/15] KVM: s390: move some gmap shadowing functions away from mm/gmap.c
  2025-01-17 19:09 ` [PATCH v3 09/15] KVM: s390: move some gmap shadowing functions away from mm/gmap.c Claudio Imbrenda
@ 2025-01-21 13:30   ` Janosch Frank
  2025-01-22 12:50   ` Christoph Schlameuss
  1 sibling, 0 replies; 42+ messages in thread
From: Janosch Frank @ 2025-01-21 13:30 UTC (permalink / raw)
  To: Claudio Imbrenda, kvm
  Cc: linux-s390, borntraeger, schlameuss, david, willy, hca, svens,
	agordeev, gor, nrb, nsg, seanjc, seiden

On 1/17/25 8:09 PM, Claudio Imbrenda wrote:
> Move some gmap shadowing functions from mm/gmap.c to kvm/kvm-s390.c and
> the newly created kvm/gmap-vsie.c
> 
> This is a step toward removing gmap from mm.
> 
> Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
> ---
>   arch/s390/include/asm/gmap.h |   9 +-
>   arch/s390/kvm/Makefile       |   2 +-
>   arch/s390/kvm/gmap-vsie.c    | 142 +++++++++++++++++++++
>   arch/s390/kvm/gmap.h         |  20 +++
>   arch/s390/kvm/kvm-s390.c     |  62 ++++++++-
>   arch/s390/kvm/kvm-s390.h     |   2 +
>   arch/s390/kvm/vsie.c         |   2 +
>   arch/s390/mm/gmap.c          | 238 +++++------------------------------
>   8 files changed, 259 insertions(+), 218 deletions(-)
>   create mode 100644 arch/s390/kvm/gmap-vsie.c
[...]
>   /**
>    * gmap_get - increase reference counter for guest address space
> @@ -958,86 +960,40 @@ static int gmap_protect_pte(struct gmap *gmap, unsigned long gaddr,
>    * @prot: indicates access rights: PROT_NONE, PROT_READ or PROT_WRITE
>    * @bits: pgste notification bits to set
>    *
> - * Returns 0 if successfully protected, -ENOMEM if out of memory and
> - * -EFAULT if gaddr is invalid (or mapping for shadows is missing).
> + * Returns:
> + *   PAGE_SIZE if a small page was successfully protected;
> + *   HPAGE_SIZE if a large page was successfully protected;
> + *   -ENOMEM if out of memory;
> + *   -EFAULT if gaddr is invalid (or mapping for shadows is missing);
> + *   -EAGAIN if the guest mapping is missing and should be fixed by the caller.
>    *
> - * Called with sg->mm->mmap_lock in read.
> + * Context: Called with sg->mm->mmap_lock in read.
>    */
> -static int gmap_protect_range(struct gmap *gmap, unsigned long gaddr,
> -			      unsigned long len, int prot, unsigned long bits)
> +int gmap_protect_one(struct gmap *gmap, unsigned long gaddr, int prot, unsigned long bits)
>   {

That's a lot nicer than the nested conditionals that we had before.

Reviewed-by: Janosch Frank <frankja@linux.ibm.com>

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 10/15] KVM: s390: stop using page->index for non-shadow gmaps
  2025-01-17 19:09 ` [PATCH v3 10/15] KVM: s390: stop using page->index for non-shadow gmaps Claudio Imbrenda
@ 2025-01-21 13:41   ` Janosch Frank
  0 siblings, 0 replies; 42+ messages in thread
From: Janosch Frank @ 2025-01-21 13:41 UTC (permalink / raw)
  To: Claudio Imbrenda, kvm
  Cc: linux-s390, borntraeger, schlameuss, david, willy, hca, svens,
	agordeev, gor, nrb, nsg, seanjc, seiden

On 1/17/25 8:09 PM, Claudio Imbrenda wrote:
> The host_to_guest radix tree will now map userspace addresses to guest
> addresses, instead of userspace addresses to segment tables.
> 
> When segment tables and page tables are needed, they are found using an
> additional gmap_table_walk().
> 
> This gets rid of all usage of page->index for non-shadow gmaps.
> 
> Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>

Reviewed-by: Janosch Frank <frankja@linux.ibm.com>

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 11/15] KVM: s390: stop using lists to keep track of used dat tables
  2025-01-17 19:09 ` [PATCH v3 11/15] KVM: s390: stop using lists to keep track of used dat tables Claudio Imbrenda
  2025-01-20 15:10   ` Steffen Eiden
@ 2025-01-21 14:09   ` Janosch Frank
  2025-01-22 16:13   ` Christoph Schlameuss
  2 siblings, 0 replies; 42+ messages in thread
From: Janosch Frank @ 2025-01-21 14:09 UTC (permalink / raw)
  To: Claudio Imbrenda, kvm
  Cc: linux-s390, borntraeger, schlameuss, david, willy, hca, svens,
	agordeev, gor, nrb, nsg, seanjc, seiden

On 1/17/25 8:09 PM, Claudio Imbrenda wrote:
> Until now, every dat table allocated to map a guest was put in a
> linked list. The page->lru field of struct page was used to keep track
> of which pages were being used, and when the gmap is torn down, the
> list was walked and all pages freed.
> 
> This patch gets rid of the usage of page->lru. Page tables are now
> freed by recursively walking the dat table tree.
> 
> Since s390_unlist_old_asce() becomes useless now, remove it.
> 
> Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>

Acked-by: Janosch Frank <frankja@linux.ibm.com>

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 12/15] KVM: s390: move gmap_shadow_pgt_lookup() into kvm
  2025-01-17 19:09 ` [PATCH v3 12/15] KVM: s390: move gmap_shadow_pgt_lookup() into kvm Claudio Imbrenda
@ 2025-01-21 14:23   ` Janosch Frank
  0 siblings, 0 replies; 42+ messages in thread
From: Janosch Frank @ 2025-01-21 14:23 UTC (permalink / raw)
  To: Claudio Imbrenda, kvm
  Cc: linux-s390, borntraeger, schlameuss, david, willy, hca, svens,
	agordeev, gor, nrb, nsg, seanjc, seiden

On 1/17/25 8:09 PM, Claudio Imbrenda wrote:
> Move gmap_shadow_pgt_lookup() from mm/gmap.c into kvm/gaccess.c .
> 
> Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
> Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>

Once the naming is fixed:
Reviewed-by: Janosch Frank <frankja@linux.ibm.com>

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 15/15] KVM: s390: remove the last user of page->index
  2025-01-17 19:09 ` [PATCH v3 15/15] KVM: s390: remove the last user of page->index Claudio Imbrenda
@ 2025-01-21 14:44   ` Janosch Frank
  2025-01-21 14:48     ` Claudio Imbrenda
  0 siblings, 1 reply; 42+ messages in thread
From: Janosch Frank @ 2025-01-21 14:44 UTC (permalink / raw)
  To: Claudio Imbrenda, kvm
  Cc: linux-s390, borntraeger, schlameuss, david, willy, hca, svens,
	agordeev, gor, nrb, nsg, seanjc, seiden

On 1/17/25 8:09 PM, Claudio Imbrenda wrote:
> Shadow page tables use page->index to keep the g2 address of the guest
> page table being shadowed.
> 
> Instead of keeping the information in page->index, split the address
> and smear it over the 16-bit softbits areas of 4 PGSTEs.
> 
> This removes the last s390 user of page->index.
> 
> Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
> Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
> ---
>   arch/s390/include/asm/pgtable.h | 15 +++++++++++++++
>   arch/s390/kvm/gaccess.c         |  6 ++++--
>   arch/s390/mm/gmap.c             | 22 ++++++++++++++++++++--
>   3 files changed, 39 insertions(+), 4 deletions(-)

s/index/paddr/ or pgaddr?

I get that you're replacing index but you now have the opportunity to 
choose an expressive name for this field/variable.

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 15/15] KVM: s390: remove the last user of page->index
  2025-01-21 14:44   ` Janosch Frank
@ 2025-01-21 14:48     ` Claudio Imbrenda
  0 siblings, 0 replies; 42+ messages in thread
From: Claudio Imbrenda @ 2025-01-21 14:48 UTC (permalink / raw)
  To: Janosch Frank
  Cc: kvm, linux-s390, borntraeger, schlameuss, david, willy, hca,
	svens, agordeev, gor, nrb, nsg, seanjc, seiden

On Tue, 21 Jan 2025 15:44:37 +0100
Janosch Frank <frankja@linux.ibm.com> wrote:

> On 1/17/25 8:09 PM, Claudio Imbrenda wrote:
> > Shadow page tables use page->index to keep the g2 address of the guest
> > page table being shadowed.
> > 
> > Instead of keeping the information in page->index, split the address
> > and smear it over the 16-bit softbits areas of 4 PGSTEs.
> > 
> > This removes the last s390 user of page->index.
> > 
> > Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
> > Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
> > ---
> >   arch/s390/include/asm/pgtable.h | 15 +++++++++++++++
> >   arch/s390/kvm/gaccess.c         |  6 ++++--
> >   arch/s390/mm/gmap.c             | 22 ++++++++++++++++++++--
> >   3 files changed, 39 insertions(+), 4 deletions(-)  
> 
> s/index/paddr/ or pgaddr?
> 
> I get that you're replacing index but you now have the opportunity to 
> choose an expressive name for this field/variable.

yes, makes sense

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 06/15] KVM: s390: use __kvm_faultin_pfn()
  2025-01-17 19:09 ` [PATCH v3 06/15] KVM: s390: use __kvm_faultin_pfn() Claudio Imbrenda
@ 2025-01-21 15:11   ` Christoph Schlameuss
  0 siblings, 0 replies; 42+ messages in thread
From: Christoph Schlameuss @ 2025-01-21 15:11 UTC (permalink / raw)
  To: Claudio Imbrenda, kvm
  Cc: linux-s390, frankja, borntraeger, david, willy, hca, svens,
	agordeev, gor, nrb, nsg, seanjc, seiden

On Fri Jan 17, 2025 at 8:09 PM CET, Claudio Imbrenda wrote:
> Refactor the existing page fault handling code to use __kvm_faultin_pfn().
>
> This possible now that memslots are always present.
>
> Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
> Acked-by: Janosch Frank <frankja@linux.ibm.com>
> ---
>  arch/s390/kvm/kvm-s390.c | 122 ++++++++++++++++++++++++++++++---------
>  arch/s390/kvm/kvm-s390.h |   6 ++
>  arch/s390/mm/gmap.c      |   1 +
>  3 files changed, 102 insertions(+), 27 deletions(-)

LGTM

Reviewed-by: Christoph Schlameuss <schlameuss@linux.ibm.com>


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 03/15] KVM: s390: fake memslot for ucontrol VMs
  2025-01-20 15:27   ` Christoph Schlameuss
@ 2025-01-21 16:33     ` Claudio Imbrenda
  0 siblings, 0 replies; 42+ messages in thread
From: Claudio Imbrenda @ 2025-01-21 16:33 UTC (permalink / raw)
  To: Christoph Schlameuss
  Cc: kvm, linux-s390, frankja, borntraeger, david, willy, hca, svens,
	agordeev, gor, nrb, nsg, seanjc, seiden

On Mon, 20 Jan 2025 16:27:53 +0100
"Christoph Schlameuss" <schlameuss@linux.ibm.com> wrote:

> On Fri Jan 17, 2025 at 8:09 PM CET, Claudio Imbrenda wrote:
> > Create a fake memslot for ucontrol VMs. The fake memslot identity-maps
> > userspace.
> >
> > Now memslots will always be present, and ucontrol is not a special case
> > anymore.
> >
> > Suggested-by: Sean Christopherson <seanjc@google.com>
> > Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>  
> 
> LGTM assuming the triggered warning about the slot_lock can be resolved in
> another patch.
> Tested in G1 and G2 using the ucontrol selftests.
> 
> Reviewed-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
> Tested-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
> 
> > ---
> >  Documentation/virt/kvm/api.rst   |  2 +-
> >  arch/s390/include/asm/kvm_host.h |  2 ++
> >  arch/s390/kvm/kvm-s390.c         | 15 ++++++++++++++-
> >  arch/s390/kvm/kvm-s390.h         |  2 ++
> >  4 files changed, 19 insertions(+), 2 deletions(-)
> >
> > diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
> > index f15b61317aad..cc98115a96d7 100644
> > --- a/Documentation/virt/kvm/api.rst
> > +++ b/Documentation/virt/kvm/api.rst
> > @@ -1419,7 +1419,7 @@ fetch) is injected in the guest.
> >  S390:
> >  ^^^^^
> >  
> > -Returns -EINVAL if the VM has the KVM_VM_S390_UCONTROL flag set.
> > +Returns -EINVAL or -EEXIST if the VM has the KVM_VM_S390_UCONTROL flag set.
> >  Returns -EINVAL if called on a protected VM.
> >  
> >  4.36 KVM_SET_TSS_ADDR
> > diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
> > index 97c7c8127543..9df37361bc64 100644
> > --- a/arch/s390/include/asm/kvm_host.h
> > +++ b/arch/s390/include/asm/kvm_host.h
> > @@ -30,6 +30,8 @@
> >  #define KVM_S390_ESCA_CPU_SLOTS 248
> >  #define KVM_MAX_VCPUS 255
> >  
> > +#define KVM_INTERNAL_MEM_SLOTS 1
> > +
> >  /*
> >   * These seem to be used for allocating ->chip in the routing table, which we
> >   * don't use. 1 is as small as we can get to reduce the needed memory. If we
> > diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
> > index ecbdd7d41230..58cc7f7444e5 100644
> > --- a/arch/s390/kvm/kvm-s390.c
> > +++ b/arch/s390/kvm/kvm-s390.c
> > @@ -3428,8 +3428,18 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
> >  	VM_EVENT(kvm, 3, "vm created with type %lu", type);
> >  
> >  	if (type & KVM_VM_S390_UCONTROL) {
> > +		struct kvm_userspace_memory_region2 fake_memslot = {
> > +			.slot = KVM_S390_UCONTROL_MEMSLOT,
> > +			.guest_phys_addr = 0,
> > +			.userspace_addr = 0,
> > +			.memory_size = ALIGN_DOWN(TASK_SIZE, _SEGMENT_SIZE),
> > +			.flags = 0,
> > +		};
> > +
> >  		kvm->arch.gmap = NULL;
> >  		kvm->arch.mem_limit = KVM_S390_NO_MEM_LIMIT;
> > +		/* one flat fake memslot covering the whole address-space */
> > +		KVM_BUG_ON(kvm_set_internal_memslot(kvm, &fake_memslot), kvm);  
> 
> In the current state of kvm_set_internal_memslot this does not acquire the
> slot_lock and issues a warning. I did bring this up on Seans patch introducing

Oops, I have missed that

> the method. So I assume at this point this here is fine.

not really; I will add proper locking around the call

> 
> >  	} else {
> >  		if (sclp.hamax == U64_MAX)
> >  			kvm->arch.mem_limit = TASK_SIZE_MAX;
> > @@ -5854,7 +5864,7 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
> >  {
> >  	gpa_t size;
> >  
> > -	if (kvm_is_ucontrol(kvm))
> > +	if (kvm_is_ucontrol(kvm) && new->id < KVM_USER_MEM_SLOTS)
> >  		return -EINVAL;
> >  
> >  	/* When we are protected, we should not change the memory slots */
> > @@ -5906,6 +5916,9 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
> >  {
> >  	int rc = 0;
> >  
> > +	if (kvm_is_ucontrol(kvm))
> > +		return;
> > +
> >  	switch (change) {
> >  	case KVM_MR_DELETE:
> >  		rc = gmap_unmap_segment(kvm->arch.gmap, old->base_gfn * PAGE_SIZE,
> > diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
> > index 597d7a71deeb..30736ac16f84 100644
> > --- a/arch/s390/kvm/kvm-s390.h
> > +++ b/arch/s390/kvm/kvm-s390.h
> > @@ -20,6 +20,8 @@
> >  #include <asm/processor.h>
> >  #include <asm/sclp.h>
> >  
> > +#define KVM_S390_UCONTROL_MEMSLOT (KVM_USER_MEM_SLOTS + 0)
> > +
> >  static inline void kvm_s390_fpu_store(struct kvm_run *run)
> >  {
> >  	fpu_stfpc(&run->s.regs.fpc);  
> 


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 07/15] KVM: s390: get rid of gmap_fault()
  2025-01-17 19:09 ` [PATCH v3 07/15] KVM: s390: get rid of gmap_fault() Claudio Imbrenda
@ 2025-01-22  9:44   ` Christoph Schlameuss
  0 siblings, 0 replies; 42+ messages in thread
From: Christoph Schlameuss @ 2025-01-22  9:44 UTC (permalink / raw)
  To: Claudio Imbrenda, kvm
  Cc: linux-s390, frankja, borntraeger, david, willy, hca, svens,
	agordeev, gor, nrb, nsg, seanjc, seiden

On Fri Jan 17, 2025 at 8:09 PM CET, Claudio Imbrenda wrote:
> All gmap page faults are already handled in kvm by the function
> kvm_s390_handle_dat_fault(); only few users of gmap_fault remained, all
> within kvm.
>
> Convert those calls to use kvm_s390_handle_dat_fault() instead.
>
> Remove gmap_fault() entirely since it has no more users.
>
> Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
> Acked-by: Janosch Frank <frankja@linux.ibm.com>
> ---
>  arch/s390/include/asm/gmap.h |   1 -
>  arch/s390/kvm/intercept.c    |   4 +-
>  arch/s390/mm/gmap.c          | 124 -----------------------------------
>  3 files changed, 2 insertions(+), 127 deletions(-)

Reviewed-by: Christoph Schlameuss <schlameuss@linux.ibm.com>


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 08/15] KVM: s390: get rid of gmap_translate()
  2025-01-17 19:09 ` [PATCH v3 08/15] KVM: s390: get rid of gmap_translate() Claudio Imbrenda
@ 2025-01-22  9:59   ` Christoph Schlameuss
  0 siblings, 0 replies; 42+ messages in thread
From: Christoph Schlameuss @ 2025-01-22  9:59 UTC (permalink / raw)
  To: Claudio Imbrenda, kvm
  Cc: linux-s390, frankja, borntraeger, david, willy, hca, svens,
	agordeev, gor, nrb, nsg, seanjc, seiden

LGTM

On Fri Jan 17, 2025 at 8:09 PM CET, Claudio Imbrenda wrote:
> Add gpa_to_hva(), which uses memslots, and use it to replace all uses
> of gmap_translate().
>
> Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
> Reviewed-by: Janosch Frank <frankja@linux.ibm.com>

Reviewed-by: Christoph Schlameuss <schlameuss@linux.ibm.com>

> ---
>  arch/s390/include/asm/gmap.h |  1 -
>  arch/s390/kvm/interrupt.c    | 19 +++++++++++--------
>  arch/s390/kvm/kvm-s390.h     |  9 +++++++++
>  arch/s390/mm/gmap.c          | 20 --------------------
>  4 files changed, 20 insertions(+), 29 deletions(-)

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 09/15] KVM: s390: move some gmap shadowing functions away from mm/gmap.c
  2025-01-17 19:09 ` [PATCH v3 09/15] KVM: s390: move some gmap shadowing functions away from mm/gmap.c Claudio Imbrenda
  2025-01-21 13:30   ` Janosch Frank
@ 2025-01-22 12:50   ` Christoph Schlameuss
  2025-01-22 15:05     ` Janosch Frank
  1 sibling, 1 reply; 42+ messages in thread
From: Christoph Schlameuss @ 2025-01-22 12:50 UTC (permalink / raw)
  To: Claudio Imbrenda, kvm
  Cc: linux-s390, frankja, borntraeger, david, willy, hca, svens,
	agordeev, gor, nrb, nsg, seanjc, seiden

On Fri Jan 17, 2025 at 8:09 PM CET, Claudio Imbrenda wrote:
> Move some gmap shadowing functions from mm/gmap.c to kvm/kvm-s390.c and
> the newly created kvm/gmap-vsie.c
>
> This is a step toward removing gmap from mm.
>
> Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
> ---
>  arch/s390/include/asm/gmap.h |   9 +-
>  arch/s390/kvm/Makefile       |   2 +-
>  arch/s390/kvm/gmap-vsie.c    | 142 +++++++++++++++++++++
>  arch/s390/kvm/gmap.h         |  20 +++
>  arch/s390/kvm/kvm-s390.c     |  62 ++++++++-
>  arch/s390/kvm/kvm-s390.h     |   2 +
>  arch/s390/kvm/vsie.c         |   2 +
>  arch/s390/mm/gmap.c          | 238 +++++------------------------------
>  8 files changed, 259 insertions(+), 218 deletions(-)
>  create mode 100644 arch/s390/kvm/gmap-vsie.c
>

[...]

> diff --git a/arch/s390/kvm/gmap-vsie.c b/arch/s390/kvm/gmap-vsie.c
> new file mode 100644
> index 000000000000..90427f114995
> --- /dev/null
> +++ b/arch/s390/kvm/gmap-vsie.c
> @@ -0,0 +1,142 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Guest memory management for KVM/s390 nested VMs.
> + *
> + * Copyright IBM Corp. 2008, 2020, 2024
> + *
> + *    Author(s): Claudio Imbrenda <imbrenda@linux.ibm.com>
> + *               Martin Schwidefsky <schwidefsky@de.ibm.com>
> + *               David Hildenbrand <david@redhat.com>
> + *               Janosch Frank <frankja@linux.vnet.ibm.com>
> + */
> +
> +#include <linux/compiler.h>
> +#include <linux/kvm.h>
> +#include <linux/kvm_host.h>
> +#include <linux/pgtable.h>
> +#include <linux/pagemap.h>
> +#include <linux/mman.h>
> +
> +#include <asm/lowcore.h>
> +#include <asm/gmap.h>
> +#include <asm/uv.h>
> +
> +#include "kvm-s390.h"
> +#include "gmap.h"
> +
> +/**
> + * gmap_find_shadow - find a specific asce in the list of shadow tables
> + * @parent: pointer to the parent gmap
> + * @asce: ASCE for which the shadow table is created
> + * @edat_level: edat level to be used for the shadow translation
> + *
> + * Returns the pointer to a gmap if a shadow table with the given asce is
> + * already available, ERR_PTR(-EAGAIN) if another one is just being created,
> + * otherwise NULL
> + */
> +static struct gmap *gmap_find_shadow(struct gmap *parent, unsigned long asce,
> +				     int edat_level)
> +{
> +	struct gmap *sg;
> +
> +	list_for_each_entry(sg, &parent->children, list) {
> +		if (sg->orig_asce != asce || sg->edat_level != edat_level ||
> +		    sg->removed)

This is just:

if !gmap_shadow_valid(sg, asce, edat_level)

> +			continue;
> +		if (!sg->initialized)
> +			return ERR_PTR(-EAGAIN);
> +		refcount_inc(&sg->ref_count);
> +		return sg;
> +	}
> +	return NULL;
> +}

[...]

> diff --git a/arch/s390/kvm/gmap.h b/arch/s390/kvm/gmap.h
> index f2b52ce29be3..978f541059f0 100644
> --- a/arch/s390/kvm/gmap.h
> +++ b/arch/s390/kvm/gmap.h
> @@ -13,5 +13,25 @@
>  int gmap_make_secure(struct gmap *gmap, unsigned long gaddr, void *uvcb);
>  int gmap_convert_to_secure(struct gmap *gmap, unsigned long gaddr);
>  int gmap_destroy_page(struct gmap *gmap, unsigned long gaddr);
> +struct gmap *gmap_shadow(struct gmap *parent, unsigned long asce, int edat_level);
> +
> +/**
> + * gmap_shadow_valid - check if a shadow guest address space matches the
> + *                     given properties and is still valid
> + * @sg: pointer to the shadow guest address space structure
> + * @asce: ASCE for which the shadow table is requested
> + * @edat_level: edat level to be used for the shadow translation
> + *
> + * Returns 1 if the gmap shadow is still valid and matches the given
> + * properties, the caller can continue using it. Returns 0 otherwise, the
> + * caller has to request a new shadow gmap in this case.
> + *
> + */
> +static inline int gmap_shadow_valid(struct gmap *sg, unsigned long asce, int edat_level)
> +{
> +	if (sg->removed)
> +		return 0;
> +	return sg->orig_asce == asce && sg->edat_level == edat_level;

This can simply be a single return:

return !sg->removed && sg->orig_asce == asce && sg->edat_level == edat_level;

> +}
>  
>  #endif
> diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
> index b626c87480ed..482f0968abfa 100644
> --- a/arch/s390/kvm/kvm-s390.c
> +++ b/arch/s390/kvm/kvm-s390.c
> @@ -4509,6 +4509,63 @@ static bool ibs_enabled(struct kvm_vcpu *vcpu)
>  	return kvm_s390_test_cpuflags(vcpu, CPUSTAT_IBS);
>  }

[...]


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 09/15] KVM: s390: move some gmap shadowing functions away from mm/gmap.c
  2025-01-22 12:50   ` Christoph Schlameuss
@ 2025-01-22 15:05     ` Janosch Frank
  0 siblings, 0 replies; 42+ messages in thread
From: Janosch Frank @ 2025-01-22 15:05 UTC (permalink / raw)
  To: Christoph Schlameuss, Claudio Imbrenda, kvm
  Cc: linux-s390, borntraeger, david, willy, hca, svens, agordeev, gor,
	nrb, nsg, seanjc, seiden

On 1/22/25 1:50 PM, Christoph Schlameuss wrote:
> On Fri Jan 17, 2025 at 8:09 PM CET, Claudio Imbrenda wrote:
>> Move some gmap shadowing functions from mm/gmap.c to kvm/kvm-s390.c and
>> the newly created kvm/gmap-vsie.c
>>
>> This is a step toward removing gmap from mm.
>>

[...]

>> +/**
>> + * gmap_shadow_valid - check if a shadow guest address space matches the
>> + *                     given properties and is still valid
>> + * @sg: pointer to the shadow guest address space structure
>> + * @asce: ASCE for which the shadow table is requested
>> + * @edat_level: edat level to be used for the shadow translation
>> + *
>> + * Returns 1 if the gmap shadow is still valid and matches the given
>> + * properties, the caller can continue using it. Returns 0 otherwise, the
>> + * caller has to request a new shadow gmap in this case.
>> + *
>> + */
>> +static inline int gmap_shadow_valid(struct gmap *sg, unsigned long asce, int edat_level)
>> +{
>> +	if (sg->removed)
>> +		return 0;
>> +	return sg->orig_asce == asce && sg->edat_level == edat_level;
> 
> This can simply be a single return:
> 
> return !sg->removed && sg->orig_asce == asce && sg->edat_level == edat_level;

NACK, at some point (and that point might be very arbitrary) my eyes 
start bleeding

> 
>> +}
>>   
>>   #endif
>> diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
>> index b626c87480ed..482f0968abfa 100644
>> --- a/arch/s390/kvm/kvm-s390.c
>> +++ b/arch/s390/kvm/kvm-s390.c
>> @@ -4509,6 +4509,63 @@ static bool ibs_enabled(struct kvm_vcpu *vcpu)
>>   	return kvm_s390_test_cpuflags(vcpu, CPUSTAT_IBS);
>>   }
> 
> [...]
> 


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 11/15] KVM: s390: stop using lists to keep track of used dat tables
  2025-01-17 19:09 ` [PATCH v3 11/15] KVM: s390: stop using lists to keep track of used dat tables Claudio Imbrenda
  2025-01-20 15:10   ` Steffen Eiden
  2025-01-21 14:09   ` Janosch Frank
@ 2025-01-22 16:13   ` Christoph Schlameuss
  2025-01-22 16:19     ` Claudio Imbrenda
  2 siblings, 1 reply; 42+ messages in thread
From: Christoph Schlameuss @ 2025-01-22 16:13 UTC (permalink / raw)
  To: Claudio Imbrenda, kvm
  Cc: linux-s390, frankja, borntraeger, david, willy, hca, svens,
	agordeev, gor, nrb, nsg, seanjc, seiden

On Fri Jan 17, 2025 at 8:09 PM CET, Claudio Imbrenda wrote:
> Until now, every dat table allocated to map a guest was put in a
> linked list. The page->lru field of struct page was used to keep track
> of which pages were being used, and when the gmap is torn down, the
> list was walked and all pages freed.
>
> This patch gets rid of the usage of page->lru. Page tables are now
> freed by recursively walking the dat table tree.
>
> Since s390_unlist_old_asce() becomes useless now, remove it.
>
> Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>

With comment fixes done:

Reviewed-by: Christoph Schlameuss <schlameuss@linux.ibm.com>

> ---
>  arch/s390/include/asm/gmap.h |   3 --
>  arch/s390/mm/gmap.c          | 102 ++++++++---------------------------
>  2 files changed, 23 insertions(+), 82 deletions(-)
>
> diff --git a/arch/s390/include/asm/gmap.h b/arch/s390/include/asm/gmap.h
> index dbf2329281d2..904d97f0bc5e 100644
> --- a/arch/s390/include/asm/gmap.h
> +++ b/arch/s390/include/asm/gmap.h
> @@ -45,7 +45,6 @@
>   */
>  struct gmap {
>  	struct list_head list;
> -	struct list_head crst_list;

nit: Please also remove @crst_list and @pt_list from the struct gmap comment.

>  	struct mm_struct *mm;
>  	struct radix_tree_root guest_to_host;
>  	struct radix_tree_root host_to_guest;
> @@ -61,7 +60,6 @@ struct gmap {
>  	/* Additional data for shadow guest address spaces */
>  	struct radix_tree_root host_to_rmap;
>  	struct list_head children;
> -	struct list_head pt_list;
>  	spinlock_t shadow_lock;
>  	struct gmap *parent;
>  	unsigned long orig_asce;
> @@ -141,7 +139,6 @@ int gmap_protect_one(struct gmap *gmap, unsigned long gaddr, int prot, unsigned
>  void gmap_sync_dirty_log_pmd(struct gmap *gmap, unsigned long dirty_bitmap[4],
>  			     unsigned long gaddr, unsigned long vmaddr);
>  int s390_disable_cow_sharing(void);
> -void s390_unlist_old_asce(struct gmap *gmap);
>  int s390_replace_asce(struct gmap *gmap);
>  void s390_uv_destroy_pfns(unsigned long count, unsigned long *pfns);
>  int __s390_uv_destroy_range(struct mm_struct *mm, unsigned long start,

[...]


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v3 11/15] KVM: s390: stop using lists to keep track of used dat tables
  2025-01-22 16:13   ` Christoph Schlameuss
@ 2025-01-22 16:19     ` Claudio Imbrenda
  0 siblings, 0 replies; 42+ messages in thread
From: Claudio Imbrenda @ 2025-01-22 16:19 UTC (permalink / raw)
  To: Christoph Schlameuss
  Cc: kvm, linux-s390, frankja, borntraeger, david, willy, hca, svens,
	agordeev, gor, nrb, nsg, seanjc, seiden

On Wed, 22 Jan 2025 17:13:49 +0100
"Christoph Schlameuss" <schlameuss@linux.ibm.com> wrote:

> On Fri Jan 17, 2025 at 8:09 PM CET, Claudio Imbrenda wrote:
> > Until now, every dat table allocated to map a guest was put in a
> > linked list. The page->lru field of struct page was used to keep track
> > of which pages were being used, and when the gmap is torn down, the
> > list was walked and all pages freed.
> >
> > This patch gets rid of the usage of page->lru. Page tables are now
> > freed by recursively walking the dat table tree.
> >
> > Since s390_unlist_old_asce() becomes useless now, remove it.
> >
> > Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>  
> 
> With comment fixes done:
> 
> Reviewed-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
> 
> > ---
> >  arch/s390/include/asm/gmap.h |   3 --
> >  arch/s390/mm/gmap.c          | 102 ++++++++---------------------------
> >  2 files changed, 23 insertions(+), 82 deletions(-)
> >
> > diff --git a/arch/s390/include/asm/gmap.h b/arch/s390/include/asm/gmap.h
> > index dbf2329281d2..904d97f0bc5e 100644
> > --- a/arch/s390/include/asm/gmap.h
> > +++ b/arch/s390/include/asm/gmap.h
> > @@ -45,7 +45,6 @@
> >   */
> >  struct gmap {
> >  	struct list_head list;
> > -	struct list_head crst_list;  
> 
> nit: Please also remove @crst_list and @pt_list from the struct gmap comment.

ouch yes, definitely

> 
> >  	struct mm_struct *mm;
> >  	struct radix_tree_root guest_to_host;
> >  	struct radix_tree_root host_to_guest;
> > @@ -61,7 +60,6 @@ struct gmap {
> >  	/* Additional data for shadow guest address spaces */
> >  	struct radix_tree_root host_to_rmap;
> >  	struct list_head children;
> > -	struct list_head pt_list;
> >  	spinlock_t shadow_lock;
> >  	struct gmap *parent;
> >  	unsigned long orig_asce;
> > @@ -141,7 +139,6 @@ int gmap_protect_one(struct gmap *gmap, unsigned long gaddr, int prot, unsigned
> >  void gmap_sync_dirty_log_pmd(struct gmap *gmap, unsigned long dirty_bitmap[4],
> >  			     unsigned long gaddr, unsigned long vmaddr);
> >  int s390_disable_cow_sharing(void);
> > -void s390_unlist_old_asce(struct gmap *gmap);
> >  int s390_replace_asce(struct gmap *gmap);
> >  void s390_uv_destroy_pfns(unsigned long count, unsigned long *pfns);
> >  int __s390_uv_destroy_range(struct mm_struct *mm, unsigned long start,  
> 
> [...]
> 


^ permalink raw reply	[flat|nested] 42+ messages in thread

end of thread, other threads:[~2025-01-22 16:20 UTC | newest]

Thread overview: 42+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-01-17 19:09 [PATCH v3 00/15] KVM: s390: Stop using page->index and other things Claudio Imbrenda
2025-01-17 19:09 ` [PATCH v3 01/15] KVM: Do not restrict the size of KVM-internal memory regions Claudio Imbrenda
2025-01-20 12:06   ` David Hildenbrand
2025-01-17 19:09 ` [PATCH v3 02/15] KVM: s390: wrapper for KVM_BUG Claudio Imbrenda
2025-01-20 12:07   ` David Hildenbrand
2025-01-17 19:09 ` [PATCH v3 03/15] KVM: s390: fake memslot for ucontrol VMs Claudio Imbrenda
2025-01-20 12:09   ` David Hildenbrand
2025-01-20 15:27   ` Christoph Schlameuss
2025-01-21 16:33     ` Claudio Imbrenda
2025-01-21 12:23   ` Janosch Frank
2025-01-17 19:09 ` [PATCH v3 04/15] KVM: s390: selftests: fix ucontrol memory region test Claudio Imbrenda
2025-01-20 12:12   ` David Hildenbrand
2025-01-20 12:25     ` Claudio Imbrenda
2025-01-20 15:40       ` Christoph Schlameuss
2025-01-17 19:09 ` [PATCH v3 05/15] KVM: s390: move pv gmap functions into kvm Claudio Imbrenda
2025-01-21 10:55   ` Christoph Schlameuss
2025-01-21 12:54   ` Janosch Frank
2025-01-17 19:09 ` [PATCH v3 06/15] KVM: s390: use __kvm_faultin_pfn() Claudio Imbrenda
2025-01-21 15:11   ` Christoph Schlameuss
2025-01-17 19:09 ` [PATCH v3 07/15] KVM: s390: get rid of gmap_fault() Claudio Imbrenda
2025-01-22  9:44   ` Christoph Schlameuss
2025-01-17 19:09 ` [PATCH v3 08/15] KVM: s390: get rid of gmap_translate() Claudio Imbrenda
2025-01-22  9:59   ` Christoph Schlameuss
2025-01-17 19:09 ` [PATCH v3 09/15] KVM: s390: move some gmap shadowing functions away from mm/gmap.c Claudio Imbrenda
2025-01-21 13:30   ` Janosch Frank
2025-01-22 12:50   ` Christoph Schlameuss
2025-01-22 15:05     ` Janosch Frank
2025-01-17 19:09 ` [PATCH v3 10/15] KVM: s390: stop using page->index for non-shadow gmaps Claudio Imbrenda
2025-01-21 13:41   ` Janosch Frank
2025-01-17 19:09 ` [PATCH v3 11/15] KVM: s390: stop using lists to keep track of used dat tables Claudio Imbrenda
2025-01-20 15:10   ` Steffen Eiden
2025-01-20 15:29     ` Claudio Imbrenda
2025-01-21 14:09   ` Janosch Frank
2025-01-22 16:13   ` Christoph Schlameuss
2025-01-22 16:19     ` Claudio Imbrenda
2025-01-17 19:09 ` [PATCH v3 12/15] KVM: s390: move gmap_shadow_pgt_lookup() into kvm Claudio Imbrenda
2025-01-21 14:23   ` Janosch Frank
2025-01-17 19:09 ` [PATCH v3 13/15] KVM: s390: remove useless page->index usage Claudio Imbrenda
2025-01-17 19:09 ` [PATCH v3 14/15] KVM: s390: move PGSTE softbits Claudio Imbrenda
2025-01-17 19:09 ` [PATCH v3 15/15] KVM: s390: remove the last user of page->index Claudio Imbrenda
2025-01-21 14:44   ` Janosch Frank
2025-01-21 14:48     ` Claudio Imbrenda

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox