@@ -4786,11 +4786,104 @@ static void kvm_s390_assert_primary_as(struct kvm_vcpu *vcpu)
4786
4786
current -> thread .gmap_int_code , current -> thread .gmap_teid .val );
4787
4787
}
4788
4788
4789
+ /*
4790
+ * __kvm_s390_handle_dat_fault() - handle a dat fault for the gmap of a vcpu
4791
+ * @vcpu: the vCPU whose gmap is to be fixed up
4792
+ * @gfn: the guest frame number used for memslots (including fake memslots)
4793
+ * @gaddr: the gmap address, does not have to match @gfn for ucontrol gmaps
4794
+ * @flags: FOLL_* flags
4795
+ *
4796
+ * Return: 0 on success, < 0 in case of error.
4797
+ * Context: The mm lock must not be held before calling. May sleep.
4798
+ */
4799
+ int __kvm_s390_handle_dat_fault (struct kvm_vcpu * vcpu , gfn_t gfn , gpa_t gaddr , unsigned int flags )
4800
+ {
4801
+ struct kvm_memory_slot * slot ;
4802
+ unsigned int fault_flags ;
4803
+ bool writable , unlocked ;
4804
+ unsigned long vmaddr ;
4805
+ struct page * page ;
4806
+ kvm_pfn_t pfn ;
4807
+ int rc ;
4808
+
4809
+ slot = kvm_vcpu_gfn_to_memslot (vcpu , gfn );
4810
+ if (!slot || slot -> flags & KVM_MEMSLOT_INVALID )
4811
+ return vcpu_post_run_addressing_exception (vcpu );
4812
+
4813
+ fault_flags = flags & FOLL_WRITE ? FAULT_FLAG_WRITE : 0 ;
4814
+ if (vcpu -> arch .gmap -> pfault_enabled )
4815
+ flags |= FOLL_NOWAIT ;
4816
+ vmaddr = __gfn_to_hva_memslot (slot , gfn );
4817
+
4818
+ try_again :
4819
+ pfn = __kvm_faultin_pfn (slot , gfn , flags , & writable , & page );
4820
+
4821
+ /* Access outside memory, inject addressing exception */
4822
+ if (is_noslot_pfn (pfn ))
4823
+ return vcpu_post_run_addressing_exception (vcpu );
4824
+ /* Signal pending: try again */
4825
+ if (pfn == KVM_PFN_ERR_SIGPENDING )
4826
+ return - EAGAIN ;
4827
+
4828
+ /* Needs I/O, try to setup async pfault (only possible with FOLL_NOWAIT) */
4829
+ if (pfn == KVM_PFN_ERR_NEEDS_IO ) {
4830
+ trace_kvm_s390_major_guest_pfault (vcpu );
4831
+ if (kvm_arch_setup_async_pf (vcpu ))
4832
+ return 0 ;
4833
+ vcpu -> stat .pfault_sync ++ ;
4834
+ /* Could not setup async pfault, try again synchronously */
4835
+ flags &= ~FOLL_NOWAIT ;
4836
+ goto try_again ;
4837
+ }
4838
+ /* Any other error */
4839
+ if (is_error_pfn (pfn ))
4840
+ return - EFAULT ;
4841
+
4842
+ /* Success */
4843
+ mmap_read_lock (vcpu -> arch .gmap -> mm );
4844
+ /* Mark the userspace PTEs as young and/or dirty, to avoid page fault loops */
4845
+ rc = fixup_user_fault (vcpu -> arch .gmap -> mm , vmaddr , fault_flags , & unlocked );
4846
+ if (!rc )
4847
+ rc = __gmap_link (vcpu -> arch .gmap , gaddr , vmaddr );
4848
+ scoped_guard (spinlock , & vcpu -> kvm -> mmu_lock ) {
4849
+ kvm_release_faultin_page (vcpu -> kvm , page , false, writable );
4850
+ }
4851
+ mmap_read_unlock (vcpu -> arch .gmap -> mm );
4852
+ return rc ;
4853
+ }
4854
+
4855
+ static int vcpu_dat_fault_handler (struct kvm_vcpu * vcpu , unsigned long gaddr , unsigned int flags )
4856
+ {
4857
+ unsigned long gaddr_tmp ;
4858
+ gfn_t gfn ;
4859
+
4860
+ gfn = gpa_to_gfn (gaddr );
4861
+ if (kvm_is_ucontrol (vcpu -> kvm )) {
4862
+ /*
4863
+ * This translates the per-vCPU guest address into a
4864
+ * fake guest address, which can then be used with the
4865
+ * fake memslots that are identity mapping userspace.
4866
+ * This allows ucontrol VMs to use the normal fault
4867
+ * resolution path, like normal VMs.
4868
+ */
4869
+ mmap_read_lock (vcpu -> arch .gmap -> mm );
4870
+ gaddr_tmp = __gmap_translate (vcpu -> arch .gmap , gaddr );
4871
+ mmap_read_unlock (vcpu -> arch .gmap -> mm );
4872
+ if (gaddr_tmp == - EFAULT ) {
4873
+ vcpu -> run -> exit_reason = KVM_EXIT_S390_UCONTROL ;
4874
+ vcpu -> run -> s390_ucontrol .trans_exc_code = gaddr ;
4875
+ vcpu -> run -> s390_ucontrol .pgm_code = PGM_SEGMENT_TRANSLATION ;
4876
+ return - EREMOTE ;
4877
+ }
4878
+ gfn = gpa_to_gfn (gaddr_tmp );
4879
+ }
4880
+ return __kvm_s390_handle_dat_fault (vcpu , gfn , gaddr , flags );
4881
+ }
4882
+
4789
4883
static int vcpu_post_run_handle_fault (struct kvm_vcpu * vcpu )
4790
4884
{
4791
4885
unsigned int flags = 0 ;
4792
4886
unsigned long gaddr ;
4793
- int rc = 0 ;
4794
4887
4795
4888
gaddr = current -> thread .gmap_teid .addr * PAGE_SIZE ;
4796
4889
if (kvm_s390_cur_gmap_fault_is_write ())
@@ -4842,37 +4935,14 @@ static int vcpu_post_run_handle_fault(struct kvm_vcpu *vcpu)
4842
4935
case PGM_REGION_SECOND_TRANS :
4843
4936
case PGM_REGION_THIRD_TRANS :
4844
4937
kvm_s390_assert_primary_as (vcpu );
4845
- if (vcpu -> arch .gmap -> pfault_enabled ) {
4846
- rc = gmap_fault (vcpu -> arch .gmap , gaddr , flags | FAULT_FLAG_RETRY_NOWAIT );
4847
- if (rc == - EFAULT )
4848
- return vcpu_post_run_addressing_exception (vcpu );
4849
- if (rc == - EAGAIN ) {
4850
- trace_kvm_s390_major_guest_pfault (vcpu );
4851
- if (kvm_arch_setup_async_pf (vcpu ))
4852
- return 0 ;
4853
- vcpu -> stat .pfault_sync ++ ;
4854
- } else {
4855
- return rc ;
4856
- }
4857
- }
4858
- rc = gmap_fault (vcpu -> arch .gmap , gaddr , flags );
4859
- if (rc == - EFAULT ) {
4860
- if (kvm_is_ucontrol (vcpu -> kvm )) {
4861
- vcpu -> run -> exit_reason = KVM_EXIT_S390_UCONTROL ;
4862
- vcpu -> run -> s390_ucontrol .trans_exc_code = gaddr ;
4863
- vcpu -> run -> s390_ucontrol .pgm_code = 0x10 ;
4864
- return - EREMOTE ;
4865
- }
4866
- return vcpu_post_run_addressing_exception (vcpu );
4867
- }
4868
- break ;
4938
+ return vcpu_dat_fault_handler (vcpu , gaddr , flags );
4869
4939
default :
4870
4940
KVM_BUG (1 , vcpu -> kvm , "Unexpected program interrupt 0x%x, TEID 0x%016lx" ,
4871
4941
current -> thread .gmap_int_code , current -> thread .gmap_teid .val );
4872
4942
send_sig (SIGSEGV , current , 0 );
4873
4943
break ;
4874
4944
}
4875
- return rc ;
4945
+ return 0 ;
4876
4946
}
4877
4947
4878
4948
static int vcpu_post_run (struct kvm_vcpu * vcpu , int exit_reason )
@@ -5751,7 +5821,9 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
5751
5821
}
5752
5822
#endif
5753
5823
case KVM_S390_VCPU_FAULT : {
5754
- r = gmap_fault (vcpu -> arch .gmap , arg , 0 );
5824
+ idx = srcu_read_lock (& vcpu -> kvm -> srcu );
5825
+ r = vcpu_dat_fault_handler (vcpu , arg , 0 );
5826
+ srcu_read_unlock (& vcpu -> kvm -> srcu , idx );
5755
5827
break ;
5756
5828
}
5757
5829
case KVM_ENABLE_CAP :
0 commit comments