Skip to content

Commit b77f5e9

Browse files
committed
KVM: s390: Refactor and split some gmap helpers
JIRA: https://issues.redhat.com/browse/RHEL-113440 commit 2001979 Author: Claudio Imbrenda <imbrenda@linux.ibm.com> Date: Wed May 28 11:55:01 2025 +0200 KVM: s390: Refactor and split some gmap helpers Refactor some gmap functions; move the implementation into a separate file with only helper functions. The new helper functions work on vm addresses, leaving all gmap logic in the gmap functions, which mostly become just wrappers. The whole gmap handling is going to be moved inside KVM soon, but the helper functions need to touch core mm functions, and thus need to stay in the core of kernel. Reviewed-by: Steffen Eiden <seiden@linux.ibm.com> Reviewed-by: Christoph Schlameuss <schlameuss@linux.ibm.com> Acked-by: Janosch Frank <frankja@linux.ibm.com> Link: https://lore.kernel.org/r/20250528095502.226213-4-imbrenda@linux.ibm.com Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com> Message-ID: <20250528095502.226213-4-imbrenda@linux.ibm.com> Conflicts: arch/s390/mm/gmap.c (simple contextual conflict due to missing patch in downstream) Signed-off-by: Thomas Huth <thuth@redhat.com>
1 parent bf394b5 commit b77f5e9

File tree

8 files changed

+274
-187
lines changed

8 files changed

+274
-187
lines changed

MAINTAINERS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12609,12 +12609,14 @@ S: Supported
1260912609
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux.git
1261012610
F: Documentation/virt/kvm/s390*
1261112611
F: arch/s390/include/asm/gmap.h
12612+
F: arch/s390/include/asm/gmap_helpers.h
1261212613
F: arch/s390/include/asm/kvm*
1261312614
F: arch/s390/include/uapi/asm/kvm*
1261412615
F: arch/s390/include/uapi/asm/uvdevice.h
1261512616
F: arch/s390/kernel/uv.c
1261612617
F: arch/s390/kvm/
1261712618
F: arch/s390/mm/gmap.c
12619+
F: arch/s390/mm/gmap_helpers.c
1261812620
F: drivers/s390/char/uvdevice.c
1261912621
F: tools/testing/selftests/drivers/s390x/uvdevice/
1262012622
F: tools/testing/selftests/kvm/*/s390/

arch/s390/include/asm/gmap.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,6 @@ int gmap_map_segment(struct gmap *gmap, unsigned long from,
110110
int gmap_unmap_segment(struct gmap *gmap, unsigned long to, unsigned long len);
111111
unsigned long __gmap_translate(struct gmap *, unsigned long gaddr);
112112
int __gmap_link(struct gmap *gmap, unsigned long gaddr, unsigned long vmaddr);
113-
void gmap_discard(struct gmap *, unsigned long from, unsigned long to);
114113
void __gmap_zap(struct gmap *, unsigned long gaddr);
115114
void gmap_unlink(struct mm_struct *, unsigned long *table, unsigned long vmaddr);
116115

@@ -134,7 +133,6 @@ int gmap_protect_one(struct gmap *gmap, unsigned long gaddr, int prot, unsigned
134133

135134
void gmap_sync_dirty_log_pmd(struct gmap *gmap, unsigned long dirty_bitmap[4],
136135
unsigned long gaddr, unsigned long vmaddr);
137-
int s390_disable_cow_sharing(void);
138136
int s390_replace_asce(struct gmap *gmap);
139137
void s390_uv_destroy_pfns(unsigned long count, unsigned long *pfns);
140138
int __s390_uv_destroy_range(struct mm_struct *mm, unsigned long start,
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/*
3+
* Helper functions for KVM guest address space mapping code
4+
*
5+
* Copyright IBM Corp. 2025
6+
*/
7+
8+
#ifndef _ASM_S390_GMAP_HELPERS_H
9+
#define _ASM_S390_GMAP_HELPERS_H
10+
11+
void gmap_helper_zap_one_page(struct mm_struct *mm, unsigned long vmaddr);
12+
void gmap_helper_discard(struct mm_struct *mm, unsigned long vmaddr, unsigned long end);
13+
int gmap_helper_disable_cow_sharing(void);
14+
15+
#endif /* _ASM_S390_GMAP_HELPERS_H */

arch/s390/kvm/diag.c

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,30 @@
1111
#include <linux/kvm.h>
1212
#include <linux/kvm_host.h>
1313
#include <asm/gmap.h>
14+
#include <asm/gmap_helpers.h>
1415
#include <asm/virtio-ccw.h>
1516
#include "kvm-s390.h"
1617
#include "trace.h"
1718
#include "trace-s390.h"
1819
#include "gaccess.h"
1920

21+
static void do_discard_gfn_range(struct kvm_vcpu *vcpu, gfn_t gfn_start, gfn_t gfn_end)
22+
{
23+
struct kvm_memslot_iter iter;
24+
struct kvm_memory_slot *slot;
25+
struct kvm_memslots *slots;
26+
unsigned long start, end;
27+
28+
slots = kvm_vcpu_memslots(vcpu);
29+
30+
kvm_for_each_memslot_in_gfn_range(&iter, slots, gfn_start, gfn_end) {
31+
slot = iter.slot;
32+
start = __gfn_to_hva_memslot(slot, max(gfn_start, slot->base_gfn));
33+
end = __gfn_to_hva_memslot(slot, min(gfn_end, slot->base_gfn + slot->npages));
34+
gmap_helper_discard(vcpu->kvm->mm, start, end);
35+
}
36+
}
37+
2038
static int diag_release_pages(struct kvm_vcpu *vcpu)
2139
{
2240
unsigned long start, end;
@@ -32,26 +50,28 @@ static int diag_release_pages(struct kvm_vcpu *vcpu)
3250

3351
VCPU_EVENT(vcpu, 5, "diag release pages %lX %lX", start, end);
3452

53+
mmap_read_lock(vcpu->kvm->mm);
3554
/*
3655
* We checked for start >= end above, so lets check for the
3756
* fast path (no prefix swap page involved)
3857
*/
3958
if (end <= prefix || start >= prefix + 2 * PAGE_SIZE) {
40-
gmap_discard(vcpu->arch.gmap, start, end);
59+
do_discard_gfn_range(vcpu, gpa_to_gfn(start), gpa_to_gfn(end));
4160
} else {
4261
/*
4362
* This is slow path. gmap_discard will check for start
4463
* so lets split this into before prefix, prefix, after
4564
* prefix and let gmap_discard make some of these calls
4665
* NOPs.
4766
*/
48-
gmap_discard(vcpu->arch.gmap, start, prefix);
67+
do_discard_gfn_range(vcpu, gpa_to_gfn(start), gpa_to_gfn(prefix));
4968
if (start <= prefix)
50-
gmap_discard(vcpu->arch.gmap, 0, PAGE_SIZE);
69+
do_discard_gfn_range(vcpu, 0, 1);
5170
if (end > prefix + PAGE_SIZE)
52-
gmap_discard(vcpu->arch.gmap, PAGE_SIZE, 2 * PAGE_SIZE);
53-
gmap_discard(vcpu->arch.gmap, prefix + 2 * PAGE_SIZE, end);
71+
do_discard_gfn_range(vcpu, 1, 2);
72+
do_discard_gfn_range(vcpu, gpa_to_gfn(prefix) + 2, gpa_to_gfn(end));
5473
}
74+
mmap_read_unlock(vcpu->kvm->mm);
5575
return 0;
5676
}
5777

arch/s390/kvm/kvm-s390.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include <asm/lowcore.h>
3939
#include <asm/stp.h>
4040
#include <asm/gmap.h>
41+
#include <asm/gmap_helpers.h>
4142
#include <asm/nmi.h>
4243
#include <asm/isc.h>
4344
#include <asm/sclp.h>
@@ -2672,7 +2673,9 @@ static int kvm_s390_handle_pv(struct kvm *kvm, struct kvm_pv_cmd *cmd)
26722673
if (r)
26732674
break;
26742675

2675-
r = s390_disable_cow_sharing();
2676+
mmap_write_lock(kvm->mm);
2677+
r = gmap_helper_disable_cow_sharing();
2678+
mmap_write_unlock(kvm->mm);
26762679
if (r)
26772680
break;
26782681

arch/s390/mm/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,5 @@ obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
1212
obj-$(CONFIG_PTDUMP_CORE) += dump_pagetables.o
1313
obj-$(CONFIG_PGSTE) += gmap.o
1414
obj-$(CONFIG_PFAULT) += pfault.o
15+
16+
obj-$(subst m,y,$(CONFIG_KVM)) += gmap_helpers.o

arch/s390/mm/gmap.c

Lines changed: 5 additions & 179 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <linux/pgtable.h>
2121
#include <asm/page-states.h>
2222
#include <asm/pgalloc.h>
23+
#include <asm/gmap_helpers.h>
2324
#include <asm/gmap.h>
2425
#include <asm/page.h>
2526

@@ -617,63 +618,20 @@ EXPORT_SYMBOL(__gmap_link);
617618
*/
618619
void __gmap_zap(struct gmap *gmap, unsigned long gaddr)
619620
{
620-
struct vm_area_struct *vma;
621621
unsigned long vmaddr;
622-
spinlock_t *ptl;
623-
pte_t *ptep;
622+
623+
mmap_assert_locked(gmap->mm);
624624

625625
/* Find the vm address for the guest address */
626626
vmaddr = (unsigned long) radix_tree_lookup(&gmap->guest_to_host,
627627
gaddr >> PMD_SHIFT);
628628
if (vmaddr) {
629629
vmaddr |= gaddr & ~PMD_MASK;
630-
631-
vma = vma_lookup(gmap->mm, vmaddr);
632-
if (!vma || is_vm_hugetlb_page(vma))
633-
return;
634-
635-
/* Get pointer to the page table entry */
636-
ptep = get_locked_pte(gmap->mm, vmaddr, &ptl);
637-
if (likely(ptep)) {
638-
ptep_zap_unused(gmap->mm, vmaddr, ptep, 0);
639-
pte_unmap_unlock(ptep, ptl);
640-
}
630+
gmap_helper_zap_one_page(gmap->mm, vmaddr);
641631
}
642632
}
643633
EXPORT_SYMBOL_GPL(__gmap_zap);
644634

645-
void gmap_discard(struct gmap *gmap, unsigned long from, unsigned long to)
646-
{
647-
unsigned long gaddr, vmaddr, size;
648-
struct vm_area_struct *vma;
649-
650-
mmap_read_lock(gmap->mm);
651-
for (gaddr = from; gaddr < to;
652-
gaddr = (gaddr + PMD_SIZE) & PMD_MASK) {
653-
/* Find the vm address for the guest address */
654-
vmaddr = (unsigned long)
655-
radix_tree_lookup(&gmap->guest_to_host,
656-
gaddr >> PMD_SHIFT);
657-
if (!vmaddr)
658-
continue;
659-
vmaddr |= gaddr & ~PMD_MASK;
660-
/* Find vma in the parent mm */
661-
vma = find_vma(gmap->mm, vmaddr);
662-
if (!vma)
663-
continue;
664-
/*
665-
* We do not discard pages that are backed by
666-
* hugetlbfs, so we don't have to refault them.
667-
*/
668-
if (is_vm_hugetlb_page(vma))
669-
continue;
670-
size = min(to - gaddr, PMD_SIZE - (gaddr & ~PMD_MASK));
671-
zap_page_range_single(vma, vmaddr, size, NULL);
672-
}
673-
mmap_read_unlock(gmap->mm);
674-
}
675-
EXPORT_SYMBOL_GPL(gmap_discard);
676-
677635
static LIST_HEAD(gmap_notifier_list);
678636
static DEFINE_SPINLOCK(gmap_notifier_lock);
679637

@@ -2266,138 +2224,6 @@ int s390_enable_sie(void)
22662224
}
22672225
EXPORT_SYMBOL_GPL(s390_enable_sie);
22682226

2269-
static int find_zeropage_pte_entry(pte_t *pte, unsigned long addr,
2270-
unsigned long end, struct mm_walk *walk)
2271-
{
2272-
unsigned long *found_addr = walk->private;
2273-
2274-
/* Return 1 of the page is a zeropage. */
2275-
if (is_zero_pfn(pte_pfn(*pte))) {
2276-
/*
2277-
* Shared zeropage in e.g., a FS DAX mapping? We cannot do the
2278-
* right thing and likely don't care: FAULT_FLAG_UNSHARE
2279-
* currently only works in COW mappings, which is also where
2280-
* mm_forbids_zeropage() is checked.
2281-
*/
2282-
if (!is_cow_mapping(walk->vma->vm_flags))
2283-
return -EFAULT;
2284-
2285-
*found_addr = addr;
2286-
return 1;
2287-
}
2288-
return 0;
2289-
}
2290-
2291-
static const struct mm_walk_ops find_zeropage_ops = {
2292-
.pte_entry = find_zeropage_pte_entry,
2293-
.walk_lock = PGWALK_WRLOCK,
2294-
};
2295-
2296-
/*
2297-
* Unshare all shared zeropages, replacing them by anonymous pages. Note that
2298-
* we cannot simply zap all shared zeropages, because this could later
2299-
* trigger unexpected userfaultfd missing events.
2300-
*
2301-
* This must be called after mm->context.allow_cow_sharing was
2302-
* set to 0, to avoid future mappings of shared zeropages.
2303-
*
2304-
* mm contracts with s390, that even if mm were to remove a page table,
2305-
* and racing with walk_page_range_vma() calling pte_offset_map_lock()
2306-
* would fail, it will never insert a page table containing empty zero
2307-
* pages once mm_forbids_zeropage(mm) i.e.
2308-
* mm->context.allow_cow_sharing is set to 0.
2309-
*/
2310-
static int __s390_unshare_zeropages(struct mm_struct *mm)
2311-
{
2312-
struct vm_area_struct *vma;
2313-
VMA_ITERATOR(vmi, mm, 0);
2314-
unsigned long addr;
2315-
vm_fault_t fault;
2316-
int rc;
2317-
2318-
for_each_vma(vmi, vma) {
2319-
/*
2320-
* We could only look at COW mappings, but it's more future
2321-
* proof to catch unexpected zeropages in other mappings and
2322-
* fail.
2323-
*/
2324-
if ((vma->vm_flags & VM_PFNMAP) || is_vm_hugetlb_page(vma))
2325-
continue;
2326-
addr = vma->vm_start;
2327-
2328-
retry:
2329-
rc = walk_page_range_vma(vma, addr, vma->vm_end,
2330-
&find_zeropage_ops, &addr);
2331-
if (rc < 0)
2332-
return rc;
2333-
else if (!rc)
2334-
continue;
2335-
2336-
/* addr was updated by find_zeropage_pte_entry() */
2337-
fault = handle_mm_fault(vma, addr,
2338-
FAULT_FLAG_UNSHARE | FAULT_FLAG_REMOTE,
2339-
NULL);
2340-
if (fault & VM_FAULT_OOM)
2341-
return -ENOMEM;
2342-
/*
2343-
* See break_ksm(): even after handle_mm_fault() returned 0, we
2344-
* must start the lookup from the current address, because
2345-
* handle_mm_fault() may back out if there's any difficulty.
2346-
*
2347-
* VM_FAULT_SIGBUS and VM_FAULT_SIGSEGV are unexpected but
2348-
* maybe they could trigger in the future on concurrent
2349-
* truncation. In that case, the shared zeropage would be gone
2350-
* and we can simply retry and make progress.
2351-
*/
2352-
cond_resched();
2353-
goto retry;
2354-
}
2355-
2356-
return 0;
2357-
}
2358-
2359-
static int __s390_disable_cow_sharing(struct mm_struct *mm)
2360-
{
2361-
int rc;
2362-
2363-
if (!mm->context.allow_cow_sharing)
2364-
return 0;
2365-
2366-
mm->context.allow_cow_sharing = 0;
2367-
2368-
/* Replace all shared zeropages by anonymous pages. */
2369-
rc = __s390_unshare_zeropages(mm);
2370-
/*
2371-
* Make sure to disable KSM (if enabled for the whole process or
2372-
* individual VMAs). Note that nothing currently hinders user space
2373-
* from re-enabling it.
2374-
*/
2375-
if (!rc)
2376-
rc = ksm_disable(mm);
2377-
if (rc)
2378-
mm->context.allow_cow_sharing = 1;
2379-
return rc;
2380-
}
2381-
2382-
/*
2383-
* Disable most COW-sharing of memory pages for the whole process:
2384-
* (1) Disable KSM and unmerge/unshare any KSM pages.
2385-
* (2) Disallow shared zeropages and unshare any zerpages that are mapped.
2386-
*
2387-
* Not that we currently don't bother with COW-shared pages that are shared
2388-
* with parent/child processes due to fork().
2389-
*/
2390-
int s390_disable_cow_sharing(void)
2391-
{
2392-
int rc;
2393-
2394-
mmap_write_lock(current->mm);
2395-
rc = __s390_disable_cow_sharing(current->mm);
2396-
mmap_write_unlock(current->mm);
2397-
return rc;
2398-
}
2399-
EXPORT_SYMBOL_GPL(s390_disable_cow_sharing);
2400-
24012227
/*
24022228
* Enable storage key handling from now on and initialize the storage
24032229
* keys with the default key.
@@ -2465,7 +2291,7 @@ int s390_enable_skey(void)
24652291
goto out_up;
24662292

24672293
mm->context.uses_skeys = 1;
2468-
rc = __s390_disable_cow_sharing(mm);
2294+
rc = gmap_helper_disable_cow_sharing();
24692295
if (rc) {
24702296
mm->context.uses_skeys = 0;
24712297
goto out_up;

0 commit comments

Comments
 (0)