Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[S390] kvm: Handle diagnose 0x10 (release pages)

Linux on System z uses a ballooner based on diagnose 0x10. (aka as
collaborative memory management). This patch implements diagnose
0x10 on the guest address space.

Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

authored by

Christian Borntraeger and committed by
Martin Schwidefsky
388186bc 499069e1

+82 -2
+1
arch/s390/include/asm/kvm_host.h
··· 143 143 u32 instruction_sigp_arch; 144 144 u32 instruction_sigp_prefix; 145 145 u32 instruction_sigp_restart; 146 + u32 diagnose_10; 146 147 u32 diagnose_44; 147 148 }; 148 149
+1
arch/s390/include/asm/pgtable.h
··· 698 698 int gmap_unmap_segment(struct gmap *gmap, unsigned long to, unsigned long len); 699 699 unsigned long __gmap_fault(unsigned long address, struct gmap *); 700 700 unsigned long gmap_fault(unsigned long address, struct gmap *); 701 + void gmap_discard(unsigned long from, unsigned long to, struct gmap *); 701 702 702 703 /* 703 704 * Certain architectures need to do special things when PTEs
+31 -1
arch/s390/kvm/diag.c
··· 1 1 /* 2 2 * diag.c - handling diagnose instructions 3 3 * 4 - * Copyright IBM Corp. 2008 4 + * Copyright IBM Corp. 2008,2011 5 5 * 6 6 * This program is free software; you can redistribute it and/or modify 7 7 * it under the terms of the GNU General Public License (version 2 only) ··· 14 14 #include <linux/kvm.h> 15 15 #include <linux/kvm_host.h> 16 16 #include "kvm-s390.h" 17 + 18 + static int diag_release_pages(struct kvm_vcpu *vcpu) 19 + { 20 + unsigned long start, end; 21 + unsigned long prefix = vcpu->arch.sie_block->prefix; 22 + 23 + start = vcpu->arch.guest_gprs[(vcpu->arch.sie_block->ipa & 0xf0) >> 4]; 24 + end = vcpu->arch.guest_gprs[vcpu->arch.sie_block->ipa & 0xf] + 4096; 25 + 26 + if (start & ~PAGE_MASK || end & ~PAGE_MASK || start > end 27 + || start < 2 * PAGE_SIZE) 28 + return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 29 + 30 + VCPU_EVENT(vcpu, 5, "diag release pages %lX %lX", start, end); 31 + vcpu->stat.diagnose_10++; 32 + 33 + /* we checked for start > end above */ 34 + if (end < prefix || start >= prefix + 2 * PAGE_SIZE) { 35 + gmap_discard(start, end, vcpu->arch.gmap); 36 + } else { 37 + if (start < prefix) 38 + gmap_discard(start, prefix, vcpu->arch.gmap); 39 + if (end >= prefix) 40 + gmap_discard(prefix + 2 * PAGE_SIZE, 41 + end, vcpu->arch.gmap); 42 + } 43 + return 0; 44 + } 17 45 18 46 static int __diag_time_slice_end(struct kvm_vcpu *vcpu) 19 47 { ··· 85 57 int code = (vcpu->arch.sie_block->ipb & 0xfff0000) >> 16; 86 58 87 59 switch (code) { 60 + case 0x10: 61 + return diag_release_pages(vcpu); 88 62 case 0x44: 89 63 return __diag_time_slice_end(vcpu); 90 64 case 0x308:
+1
arch/s390/kvm/kvm-s390.c
··· 69 69 { "instruction_sigp_set_arch", VCPU_STAT(instruction_sigp_arch) }, 70 70 { "instruction_sigp_set_prefix", VCPU_STAT(instruction_sigp_prefix) }, 71 71 { "instruction_sigp_restart", VCPU_STAT(instruction_sigp_restart) }, 72 + { "diagnose_10", VCPU_STAT(diagnose_10) }, 72 73 { "diagnose_44", VCPU_STAT(diagnose_44) }, 73 74 { NULL } 74 75 };
+48 -1
arch/s390/mm/pgtable.c
··· 1 1 /* 2 - * Copyright IBM Corp. 2007,2009 2 + * Copyright IBM Corp. 2007,2011 3 3 * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> 4 4 */ 5 5 ··· 477 477 return rc; 478 478 } 479 479 EXPORT_SYMBOL_GPL(gmap_fault); 480 + 481 + void gmap_discard(unsigned long from, unsigned long to, struct gmap *gmap) 482 + { 483 + 484 + unsigned long *table, address, size; 485 + struct vm_area_struct *vma; 486 + struct gmap_pgtable *mp; 487 + struct page *page; 488 + 489 + down_read(&gmap->mm->mmap_sem); 490 + address = from; 491 + while (address < to) { 492 + /* Walk the gmap address space page table */ 493 + table = gmap->table + ((address >> 53) & 0x7ff); 494 + if (unlikely(*table & _REGION_ENTRY_INV)) { 495 + address = (address + PMD_SIZE) & PMD_MASK; 496 + continue; 497 + } 498 + table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN); 499 + table = table + ((address >> 42) & 0x7ff); 500 + if (unlikely(*table & _REGION_ENTRY_INV)) { 501 + address = (address + PMD_SIZE) & PMD_MASK; 502 + continue; 503 + } 504 + table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN); 505 + table = table + ((address >> 31) & 0x7ff); 506 + if (unlikely(*table & _REGION_ENTRY_INV)) { 507 + address = (address + PMD_SIZE) & PMD_MASK; 508 + continue; 509 + } 510 + table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN); 511 + table = table + ((address >> 20) & 0x7ff); 512 + if (unlikely(*table & _SEGMENT_ENTRY_INV)) { 513 + address = (address + PMD_SIZE) & PMD_MASK; 514 + continue; 515 + } 516 + page = pfn_to_page(*table >> PAGE_SHIFT); 517 + mp = (struct gmap_pgtable *) page->index; 518 + vma = find_vma(gmap->mm, mp->vmaddr); 519 + size = min(to - address, PMD_SIZE - (address & ~PMD_MASK)); 520 + zap_page_range(vma, mp->vmaddr | (address & ~PMD_MASK), 521 + size, NULL); 522 + address = (address + PMD_SIZE) & PMD_MASK; 523 + } 524 + up_read(&gmap->mm->mmap_sem); 525 + } 526 + EXPORT_SYMBOL_GPL(gmap_discard); 480 527 481 528 void gmap_unmap_notifier(struct mm_struct *mm, unsigned long *table) 482 529 {