On 24.10.19 13:40, Janosch Frank wrote: > From: Claudio Imbrenda <imbrenda@xxxxxxxxxxxxx> > > Pin the guest pages when they are first accessed, instead of all at > the same time when starting the guest. > > Signed-off-by: Claudio Imbrenda <imbrenda@xxxxxxxxxxxxx> [...] > diff --git a/arch/s390/kvm/pv.c b/arch/s390/kvm/pv.c > index 80aecd5bea9e..383e660e2221 100644 > --- a/arch/s390/kvm/pv.c > +++ b/arch/s390/kvm/pv.c > @@ -15,8 +15,35 @@ > #include <asm/mman.h> > #include "kvm-s390.h" > > +static void unpin_destroy(struct page **pages, int nr) > +{ > + int i; > + struct page *page; > + u8 *val; > + > + for (i = 0; i < nr; i++) { > + page = pages[i]; > + if (!page) /* page was never used */ > + continue; > + val = (void *)page_to_phys(page); Why dont we call the convert from secure directly here to avoid the fault overhead? > + READ_ONCE(*val); > + put_page(page); as we also do the export here (via implicit reading that page) this can take a while. I think we must add a cond_resched here. > + } > +} > + [...] > - > mutex_unlock(&kvm->slots_lock); > + > + kvm->arch.gmap->pinned_pages = vzalloc(npages * sizeof(struct page *)); > + if (!kvm->arch.gmap->pinned_pages) > + goto out_err; > kvm->arch.pv.guest_len = npages * PAGE_SIZE; > > /* Allocate variable storage */ > vlen = ALIGN(virt * ((npages * PAGE_SIZE) / HPAGE_SIZE), PAGE_SIZE); > vlen += uv_info.guest_virt_base_stor_len; > kvm->arch.pv.stor_var = vzalloc(vlen); > - if (!kvm->arch.pv.stor_var) { > - kvm_s390_pv_dealloc_vm(kvm); > - return -ENOMEM; > - } > + if (!kvm->arch.pv.stor_var) > + goto out_err; > return 0; > + > +out_err: > + kvm_s390_pv_dealloc_vm(kvm); > + return -ENOMEM; > } > > int kvm_s390_pv_destroy_vm(struct kvm *kvm) > @@ -216,6 +246,11 @@ int kvm_s390_pv_unpack(struct kvm *kvm, unsigned long addr, unsigned long size, > for (i = 0; i < size / PAGE_SIZE; i++) { > uvcb.gaddr = addr + i * PAGE_SIZE; > uvcb.tweak[1] = i * PAGE_SIZE; > + down_read(&kvm->mm->mmap_sem); > + rc = kvm_s390_pv_pin_page(kvm->arch.gmap, uvcb.gaddr); > + up_read(&kvm->mm->mmap_sem); Here we should also have a cond_resched(); > + if (rc && (rc != -EEXIST)) > + break; > retry: > rc = uv_call(0, (u64)&uvcb); > if (!rc) >