@@ -47,6 +47,7 @@ struct vhost_vdpa {
4747 int minor ;
4848 struct eventfd_ctx * config_ctx ;
4949 int in_batch ;
50+ struct vdpa_iova_range range ;
5051};
5152
5253static DEFINE_IDA (vhost_vdpa_ida );
@@ -103,6 +104,9 @@ static void vhost_vdpa_setup_vq_irq(struct vhost_vdpa *v, u16 qid)
103104 vq -> call_ctx .producer .token = vq -> call_ctx .ctx ;
104105 vq -> call_ctx .producer .irq = irq ;
105106 ret = irq_bypass_register_producer (& vq -> call_ctx .producer );
107+ if (unlikely (ret ))
108+ dev_info (& v -> dev , "vq %u, irq bypass producer (token %p) registration fails, ret = %d\n" ,
109+ qid , vq -> call_ctx .producer .token , ret );
106110}
107111
108112static void vhost_vdpa_unsetup_vq_irq (struct vhost_vdpa * v , u16 qid )
@@ -337,6 +341,16 @@ static long vhost_vdpa_set_config_call(struct vhost_vdpa *v, u32 __user *argp)
337341 return 0 ;
338342}
339343
344+ static long vhost_vdpa_get_iova_range (struct vhost_vdpa * v , u32 __user * argp )
345+ {
346+ struct vhost_vdpa_iova_range range = {
347+ .first = v -> range .first ,
348+ .last = v -> range .last ,
349+ };
350+
351+ return copy_to_user (argp , & range , sizeof (range ));
352+ }
353+
340354static long vhost_vdpa_vring_ioctl (struct vhost_vdpa * v , unsigned int cmd ,
341355 void __user * argp )
342356{
@@ -421,12 +435,11 @@ static long vhost_vdpa_unlocked_ioctl(struct file *filep,
421435 void __user * argp = (void __user * )arg ;
422436 u64 __user * featurep = argp ;
423437 u64 features ;
424- long r ;
438+ long r = 0 ;
425439
426440 if (cmd == VHOST_SET_BACKEND_FEATURES ) {
427- r = copy_from_user (& features , featurep , sizeof (features ));
428- if (r )
429- return r ;
441+ if (copy_from_user (& features , featurep , sizeof (features )))
442+ return - EFAULT ;
430443 if (features & ~VHOST_VDPA_BACKEND_FEATURES )
431444 return - EOPNOTSUPP ;
432445 vhost_set_backend_features (& v -> vdev , features );
@@ -469,7 +482,11 @@ static long vhost_vdpa_unlocked_ioctl(struct file *filep,
469482 break ;
470483 case VHOST_GET_BACKEND_FEATURES :
471484 features = VHOST_VDPA_BACKEND_FEATURES ;
472- r = copy_to_user (featurep , & features , sizeof (features ));
485+ if (copy_to_user (featurep , & features , sizeof (features )))
486+ r = - EFAULT ;
487+ break ;
488+ case VHOST_VDPA_GET_IOVA_RANGE :
489+ r = vhost_vdpa_get_iova_range (v , argp );
473490 break ;
474491 default :
475492 r = vhost_dev_ioctl (& v -> vdev , cmd , argp );
@@ -588,106 +605,87 @@ static int vhost_vdpa_process_iotlb_update(struct vhost_vdpa *v,
588605 struct vhost_dev * dev = & v -> vdev ;
589606 struct vhost_iotlb * iotlb = dev -> iotlb ;
590607 struct page * * page_list ;
591- struct vm_area_struct * * vmas ;
608+ unsigned long list_size = PAGE_SIZE / sizeof ( struct page * ) ;
592609 unsigned int gup_flags = FOLL_LONGTERM ;
593- unsigned long map_pfn , last_pfn = 0 ;
594- unsigned long npages , lock_limit ;
595- unsigned long i , nmap = 0 ;
610+ unsigned long npages , cur_base , map_pfn , last_pfn = 0 ;
611+ unsigned long locked , lock_limit , pinned , i ;
596612 u64 iova = msg -> iova ;
597- long pinned ;
598613 int ret = 0 ;
599614
615+ if (msg -> iova < v -> range .first ||
616+ msg -> iova + msg -> size - 1 > v -> range .last )
617+ return - EINVAL ;
618+
600619 if (vhost_iotlb_itree_first (iotlb , msg -> iova ,
601620 msg -> iova + msg -> size - 1 ))
602621 return - EEXIST ;
603622
623+ page_list = (struct page * * ) __get_free_page (GFP_KERNEL );
624+ if (!page_list )
625+ return - ENOMEM ;
626+
604627 if (msg -> perm & VHOST_ACCESS_WO )
605628 gup_flags |= FOLL_WRITE ;
606629
607630 npages = PAGE_ALIGN (msg -> size + (iova & ~PAGE_MASK )) >> PAGE_SHIFT ;
608631 if (!npages )
609632 return - EINVAL ;
610633
611- page_list = kvmalloc_array (npages , sizeof (struct page * ), GFP_KERNEL );
612- vmas = kvmalloc_array (npages , sizeof (struct vm_area_struct * ),
613- GFP_KERNEL );
614- if (!page_list || !vmas ) {
615- ret = - ENOMEM ;
616- goto free ;
617- }
618-
619634 mmap_read_lock (dev -> mm );
620635
636+ locked = atomic64_add_return (npages , & dev -> mm -> pinned_vm );
621637 lock_limit = rlimit (RLIMIT_MEMLOCK ) >> PAGE_SHIFT ;
622- if (npages + atomic64_read (& dev -> mm -> pinned_vm ) > lock_limit ) {
623- ret = - ENOMEM ;
624- goto unlock ;
625- }
626638
627- pinned = pin_user_pages (msg -> uaddr & PAGE_MASK , npages , gup_flags ,
628- page_list , vmas );
629- if (npages != pinned ) {
630- if (pinned < 0 ) {
631- ret = pinned ;
632- } else {
633- unpin_user_pages (page_list , pinned );
634- ret = - ENOMEM ;
635- }
636- goto unlock ;
639+ if (locked > lock_limit ) {
640+ ret = - ENOMEM ;
641+ goto out ;
637642 }
638643
644+ cur_base = msg -> uaddr & PAGE_MASK ;
639645 iova &= PAGE_MASK ;
640- map_pfn = page_to_pfn (page_list [0 ]);
641-
642- /* One more iteration to avoid extra vdpa_map() call out of loop. */
643- for (i = 0 ; i <= npages ; i ++ ) {
644- unsigned long this_pfn ;
645- u64 csize ;
646-
647- /* The last chunk may have no valid PFN next to it */
648- this_pfn = i < npages ? page_to_pfn (page_list [i ]) : -1UL ;
649-
650- if (last_pfn && (this_pfn == -1UL ||
651- this_pfn != last_pfn + 1 )) {
652- /* Pin a contiguous chunk of memory */
653- csize = last_pfn - map_pfn + 1 ;
654- ret = vhost_vdpa_map (v , iova , csize << PAGE_SHIFT ,
655- map_pfn << PAGE_SHIFT ,
656- msg -> perm );
657- if (ret ) {
658- /*
659- * Unpin the rest chunks of memory on the
660- * flight with no corresponding vdpa_map()
661- * calls having been made yet. On the other
662- * hand, vdpa_unmap() in the failure path
663- * is in charge of accounting the number of
664- * pinned pages for its own.
665- * This asymmetrical pattern of accounting
666- * is for efficiency to pin all pages at
667- * once, while there is no other callsite
668- * of vdpa_map() than here above.
669- */
670- unpin_user_pages (& page_list [nmap ],
671- npages - nmap );
672- goto out ;
646+
647+ while (npages ) {
648+ pinned = min_t (unsigned long , npages , list_size );
649+ ret = pin_user_pages (cur_base , pinned ,
650+ gup_flags , page_list , NULL );
651+ if (ret != pinned )
652+ goto out ;
653+
654+ if (!last_pfn )
655+ map_pfn = page_to_pfn (page_list [0 ]);
656+
657+ for (i = 0 ; i < ret ; i ++ ) {
658+ unsigned long this_pfn = page_to_pfn (page_list [i ]);
659+ u64 csize ;
660+
661+ if (last_pfn && (this_pfn != last_pfn + 1 )) {
662+ /* Pin a contiguous chunk of memory */
663+ csize = (last_pfn - map_pfn + 1 ) << PAGE_SHIFT ;
664+ if (vhost_vdpa_map (v , iova , csize ,
665+ map_pfn << PAGE_SHIFT ,
666+ msg -> perm ))
667+ goto out ;
668+ map_pfn = this_pfn ;
669+ iova += csize ;
673670 }
674- atomic64_add (csize , & dev -> mm -> pinned_vm );
675- nmap += csize ;
676- iova += csize << PAGE_SHIFT ;
677- map_pfn = this_pfn ;
671+
672+ last_pfn = this_pfn ;
678673 }
679- last_pfn = this_pfn ;
674+
675+ cur_base += ret << PAGE_SHIFT ;
676+ npages -= ret ;
680677 }
681678
682- WARN_ON (nmap != npages );
679+ /* Pin the rest chunk */
680+ ret = vhost_vdpa_map (v , iova , (last_pfn - map_pfn + 1 ) << PAGE_SHIFT ,
681+ map_pfn << PAGE_SHIFT , msg -> perm );
683682out :
684- if (ret )
683+ if (ret ) {
685684 vhost_vdpa_unmap (v , msg -> iova , msg -> size );
686- unlock :
685+ atomic64_sub (npages , & dev -> mm -> pinned_vm );
686+ }
687687 mmap_read_unlock (dev -> mm );
688- free :
689- kvfree (vmas );
690- kvfree (page_list );
688+ free_page ((unsigned long )page_list );
691689 return ret ;
692690}
693691
@@ -783,6 +781,27 @@ static void vhost_vdpa_free_domain(struct vhost_vdpa *v)
783781 v -> domain = NULL ;
784782}
785783
784+ static void vhost_vdpa_set_iova_range (struct vhost_vdpa * v )
785+ {
786+ struct vdpa_iova_range * range = & v -> range ;
787+ struct iommu_domain_geometry geo ;
788+ struct vdpa_device * vdpa = v -> vdpa ;
789+ const struct vdpa_config_ops * ops = vdpa -> config ;
790+
791+ if (ops -> get_iova_range ) {
792+ * range = ops -> get_iova_range (vdpa );
793+ } else if (v -> domain &&
794+ !iommu_domain_get_attr (v -> domain ,
795+ DOMAIN_ATTR_GEOMETRY , & geo ) &&
796+ geo .force_aperture ) {
797+ range -> first = geo .aperture_start ;
798+ range -> last = geo .aperture_end ;
799+ } else {
800+ range -> first = 0 ;
801+ range -> last = ULLONG_MAX ;
802+ }
803+ }
804+
786805static int vhost_vdpa_open (struct inode * inode , struct file * filep )
787806{
788807 struct vhost_vdpa * v ;
@@ -823,6 +842,8 @@ static int vhost_vdpa_open(struct inode *inode, struct file *filep)
823842 if (r )
824843 goto err_init_iotlb ;
825844
845+ vhost_vdpa_set_iova_range (v );
846+
826847 filep -> private_data = v ;
827848
828849 return 0 ;
0 commit comments