diff options
author | Christian Borntraeger <borntraeger@de.ibm.com> | 2011-10-30 10:17:03 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2011-10-30 10:16:45 -0400 |
commit | 388186bc920d9200202e4d25de66fa95b1b8fc68 (patch) | |
tree | c7e1bc3231a50a91d298a8da59e8fefe2935d6da /arch/s390/mm | |
parent | 499069e1a421e2a85e76846c3237f00f1a5cb435 (diff) |
[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>
Diffstat (limited to 'arch/s390/mm')
-rw-r--r-- | arch/s390/mm/pgtable.c | 49 |
1 files changed, 48 insertions, 1 deletions
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index 441d34445d0e..301c84d3b542 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright IBM Corp. 2007,2009 | 2 | * Copyright IBM Corp. 2007,2011 |
3 | * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> | 3 | * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> |
4 | */ | 4 | */ |
5 | 5 | ||
@@ -478,6 +478,53 @@ unsigned long gmap_fault(unsigned long address, struct gmap *gmap) | |||
478 | } | 478 | } |
479 | EXPORT_SYMBOL_GPL(gmap_fault); | 479 | EXPORT_SYMBOL_GPL(gmap_fault); |
480 | 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); | ||
527 | |||
481 | void gmap_unmap_notifier(struct mm_struct *mm, unsigned long *table) | 528 | void gmap_unmap_notifier(struct mm_struct *mm, unsigned long *table) |
482 | { | 529 | { |
483 | struct gmap_rmap *rmap, *next; | 530 | struct gmap_rmap *rmap, *next; |