Skip to content

Commit 2001979

Browse files
author
Claudio Imbrenda
committed
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 <[email protected]> Reviewed-by: Christoph Schlameuss <[email protected]> Acked-by: Janosch Frank <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Claudio Imbrenda <[email protected]> Message-ID: <[email protected]>
1 parent 7e42ad6 commit 2001979

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
@@ -13075,12 +13075,14 @@ S: Supported
1307513075
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux.git
1307613076
F: Documentation/virt/kvm/s390*
1307713077
F: arch/s390/include/asm/gmap.h
13078+
F: arch/s390/include/asm/gmap_helpers.h
1307813079
F: arch/s390/include/asm/kvm*
1307913080
F: arch/s390/include/uapi/asm/kvm*
1308013081
F: arch/s390/include/uapi/asm/uvdevice.h
1308113082
F: arch/s390/kernel/uv.c
1308213083
F: arch/s390/kvm/
1308313084
F: arch/s390/mm/gmap.c
13085+
F: arch/s390/mm/gmap_helpers.c
1308413086
F: drivers/s390/char/uvdevice.c
1308513087
F: tools/testing/selftests/drivers/s390x/uvdevice/
1308613088
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,

arch/s390/include/asm/gmap_helpers.h

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
@@ -40,6 +40,7 @@
4040
#include <asm/machine.h>
4141
#include <asm/stp.h>
4242
#include <asm/gmap.h>
43+
#include <asm/gmap_helpers.h>
4344
#include <asm/nmi.h>
4445
#include <asm/isc.h>
4546
#include <asm/sclp.h>
@@ -2674,7 +2675,9 @@ static int kvm_s390_handle_pv(struct kvm *kvm, struct kvm_pv_cmd *cmd)
26742675
if (r)
26752676
break;
26762677

2677-
r = s390_disable_cow_sharing();
2678+
mmap_write_lock(kvm->mm);
2679+
r = gmap_helper_disable_cow_sharing();
2680+
mmap_write_unlock(kvm->mm);
26782681
if (r)
26792682
break;
26802683

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) += 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
@@ -22,6 +22,7 @@
2222
#include <asm/page-states.h>
2323
#include <asm/pgalloc.h>
2424
#include <asm/machine.h>
25+
#include <asm/gmap_helpers.h>
2526
#include <asm/gmap.h>
2627
#include <asm/page.h>
2728

@@ -619,63 +620,20 @@ EXPORT_SYMBOL(__gmap_link);
619620
*/
620621
void __gmap_zap(struct gmap *gmap, unsigned long gaddr)
621622
{
622-
struct vm_area_struct *vma;
623623
unsigned long vmaddr;
624-
spinlock_t *ptl;
625-
pte_t *ptep;
624+
625+
mmap_assert_locked(gmap->mm);
626626

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

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

@@ -2268,138 +2226,6 @@ int s390_enable_sie(void)
22682226
}
22692227
EXPORT_SYMBOL_GPL(s390_enable_sie);
22702228

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

24692295
mm->context.uses_skeys = 1;
2470-
rc = __s390_disable_cow_sharing(mm);
2296+
rc = gmap_helper_disable_cow_sharing();
24712297
if (rc) {
24722298
mm->context.uses_skeys = 0;
24732299
goto out_up;

0 commit comments

Comments
 (0)