77#[ macro_use]
88extern crate log;
99
10- use std :: error ;
10+ use libc :: c_void ;
1111use std:: fs:: File ;
12- use std:: io;
1312use std:: os:: unix:: io:: { AsRawFd , FromRawFd , RawFd } ;
1413use std:: os:: unix:: prelude:: IntoRawFd ;
15- use std:: result;
1614use std:: sync:: { Arc , Mutex , RwLock } ;
1715use std:: thread;
16+ use std:: { error, mem} ;
17+ use std:: { io, usize} ;
18+ use std:: { result, u64} ;
1819use vhost:: vhost_user:: message:: {
19- VhostUserConfigFlags , VhostUserMemoryRegion , VhostUserProtocolFeatures ,
20+ DescStatePacked , DescStateSplit , QueueRegionPacked , QueueRegionSplit , VhostUserConfigFlags ,
21+ VhostUserInflight , VhostUserMemoryRegion , VhostUserProtocolFeatures ,
2022 VhostUserSingleMemoryRegion , VhostUserVirtioFeatures , VhostUserVringAddrFlags ,
2123 VhostUserVringState ,
2224} ;
2325use vhost:: vhost_user:: {
2426 Error as VhostUserError , Listener , Result as VhostUserResult , SlaveFsCacheReq , SlaveListener ,
2527 VhostUserSlaveReqHandlerMut ,
2628} ;
29+ use virtio_bindings:: bindings:: virtio_net:: VIRTIO_F_RING_PACKED ;
2730use virtio_bindings:: bindings:: virtio_ring:: VIRTIO_RING_F_EVENT_IDX ;
31+ use virtio_queue:: Queue ;
2832use vm_memory:: guest_memory:: FileOffset ;
2933use vm_memory:: {
30- GuestAddress , GuestAddressSpace , GuestMemoryAtomic , GuestMemoryMmap , GuestRegionMmap ,
34+ Address , GuestAddress , GuestAddressSpace , GuestMemoryAtomic , GuestMemoryMmap , GuestRegionMmap ,
3135 MmapRegion ,
3236} ;
33- use virtio_queue:: Queue ;
3437use vmm_sys_util:: eventfd:: EventFd ;
3538
3639const MAX_MEM_SLOTS : u64 = 32 ;
@@ -453,6 +456,9 @@ struct VhostUserHandler<S: VhostUserBackend> {
453456 atomic_mem : GuestMemoryAtomic < GuestMemoryMmap > ,
454457 vrings : Vec < Arc < RwLock < Vring > > > ,
455458 worker_threads : Vec < thread:: JoinHandle < VringWorkerResult < ( ) > > > ,
459+ inflight_file : Option < File > ,
460+ inflight_mapping_addr : Option < GuestAddress > ,
461+ inflight_mmap_size : usize ,
456462}
457463
458464impl < S : VhostUserBackend > VhostUserHandler < S > {
@@ -536,6 +542,9 @@ impl<S: VhostUserBackend> VhostUserHandler<S> {
536542 atomic_mem,
537543 vrings,
538544 worker_threads,
545+ inflight_file : None ,
546+ inflight_mapping_addr : None ,
547+ inflight_mmap_size : 0 ,
539548 } )
540549 }
541550
@@ -552,6 +561,104 @@ impl<S: VhostUserBackend> VhostUserHandler<S> {
552561
553562 Err ( VhostUserHandlerError :: MissingMemoryMapping )
554563 }
564+
565+ fn get_inflight_queue_size ( & mut self , queue_size : u16 ) -> usize {
566+ let queue_region_size;
567+ let descr_state_size;
568+ let virtio_features = self . get_features ( ) . unwrap ( ) ;
569+
570+ if virtio_features & ( 1 << VIRTIO_F_RING_PACKED ) == 0 {
571+ // Use descriptor and queue states for split virtqueues
572+ queue_region_size = mem:: size_of :: < QueueRegionSplit > ( ) ;
573+ descr_state_size = mem:: size_of :: < DescStateSplit > ( ) ;
574+ } else {
575+ // Use descriptor and queue states for packed virtqueues
576+ queue_region_size = mem:: size_of :: < QueueRegionPacked > ( ) ;
577+ descr_state_size = mem:: size_of :: < DescStatePacked > ( ) ;
578+ }
579+ queue_region_size + descr_state_size * queue_size as usize
580+ }
581+
582+ fn memfd_alloc ( & self , mmap_size : usize , inflight_queue_region : & mut i64 ) -> * mut c_void {
583+ let mut ret_val;
584+
585+ ret_val = unsafe {
586+ libc:: syscall (
587+ libc:: SYS_memfd_create ,
588+ & std:: ffi:: CString :: new ( "inflight-region" ) . unwrap ( ) ,
589+ libc:: MFD_ALLOW_SEALING ,
590+ )
591+ } ;
592+
593+ if ret_val == -1 {
594+ return ret_val as * mut c_void ;
595+ }
596+
597+ * inflight_queue_region = ret_val;
598+
599+ ret_val =
600+ unsafe { libc:: ftruncate ( * inflight_queue_region as RawFd , mmap_size as i64 ) } as i64 ;
601+
602+ if ret_val == -1 {
603+ return ret_val as * mut c_void ;
604+ }
605+
606+ ret_val = unsafe {
607+ libc:: fcntl (
608+ * inflight_queue_region as i32 ,
609+ libc:: F_ADD_SEALS ,
610+ libc:: F_SEAL_GROW | libc:: F_SEAL_SHRINK | libc:: F_SEAL_SEAL ,
611+ )
612+ } as i64 ;
613+
614+ if ret_val == -1 {
615+ return ret_val as * mut c_void ;
616+ }
617+
618+ unsafe {
619+ libc:: mmap (
620+ std:: ptr:: null_mut ( ) ,
621+ mmap_size,
622+ libc:: PROT_READ | libc:: PROT_WRITE ,
623+ libc:: MAP_SHARED ,
624+ * inflight_queue_region as i32 ,
625+ 0 ,
626+ )
627+ }
628+ }
629+
630+ fn set_desc_num_packed ( & mut self , inflight_region : u64 , num_queues : u16 , queue_size : u16 ) {
631+ let raw_ptr = inflight_region as * mut QueueRegionPacked ;
632+
633+ for i in 0 ..num_queues {
634+ unsafe {
635+ let queue_region = raw_ptr. offset ( i as isize ) . as_mut ( ) . unwrap ( ) ;
636+ queue_region. desc_num = queue_size;
637+ }
638+ }
639+ }
640+
641+ fn set_desc_num_split ( & mut self , inflight_region : u64 , num_queues : u16 , queue_size : u16 ) {
642+ let raw_ptr = inflight_region as * mut QueueRegionSplit ;
643+
644+ for i in 0 ..num_queues {
645+ unsafe {
646+ let queue_region = raw_ptr. offset ( i as isize ) . as_mut ( ) . unwrap ( ) ;
647+ queue_region. desc_num = queue_size;
648+ }
649+ }
650+ }
651+
652+ fn set_inflight_region_desc_num ( & mut self , num_queues : u16 , queue_size : u16 ) {
653+ let inflight_region = self . inflight_mapping_addr . unwrap ( ) . raw_value ( ) ;
654+
655+ let virtio_features = self . get_features ( ) . unwrap ( ) ;
656+
657+ match virtio_features & ( 1 << VIRTIO_F_RING_PACKED ) {
658+ 0 => self . set_desc_num_split ( inflight_region, num_queues, queue_size) ,
659+ _ => self . set_desc_num_packed ( inflight_region, num_queues, queue_size) ,
660+ } ;
661+ }
555662}
556663
557664impl < S : VhostUserBackend > VhostUserSlaveReqHandlerMut for VhostUserHandler < S > {
@@ -948,16 +1055,73 @@ impl<S: VhostUserBackend> VhostUserSlaveReqHandlerMut for VhostUserHandler<S> {
9481055
9491056 fn get_inflight_fd (
9501057 & mut self ,
951- _inflight : & vhost:: vhost_user:: message:: VhostUserInflight ,
952- ) -> VhostUserResult < ( vhost:: vhost_user:: message:: VhostUserInflight , File ) > {
953- // Assume the backend hasn't negotiated the inflight feature; it
954- // wouldn't be correct for the backend to do so, as we don't (yet)
955- // provide a way for it to handle such requests.
956- Err ( VhostUserError :: InvalidOperation )
1058+ inflight : & VhostUserInflight ,
1059+ ) -> VhostUserResult < ( VhostUserInflight , File ) > {
1060+ let ret_val = -1 ;
1061+ // Total size of the inflight queue region
1062+ let mut total_mmap_size =
1063+ self . get_inflight_queue_size ( inflight. queue_size ) * inflight. num_queues as usize ;
1064+
1065+ // Create a memfd region to hold the queues for inflight I/O tracking
1066+ let mut inflight_fd = -1 ;
1067+ let mmap_ptr = self . memfd_alloc ( total_mmap_size, & mut inflight_fd) ;
1068+
1069+ self . inflight_file = Some ( unsafe { File :: from_raw_fd ( inflight_fd as i32 ) } ) ;
1070+
1071+ if mmap_ptr == ret_val as * mut c_void {
1072+ self . inflight_mapping_addr = None ;
1073+ total_mmap_size = 0 ;
1074+ } else {
1075+ unsafe { libc:: memset ( mmap_ptr, 0 , total_mmap_size) } ;
1076+ self . inflight_mapping_addr = Some ( GuestAddress :: new ( mmap_ptr as u64 ) ) ;
1077+ }
1078+ self . inflight_mmap_size = total_mmap_size;
1079+
1080+ Ok ( (
1081+ VhostUserInflight {
1082+ mmap_size : total_mmap_size as u64 ,
1083+ mmap_offset : 0 ,
1084+ num_queues : inflight. num_queues ,
1085+ queue_size : inflight. queue_size ,
1086+ } ,
1087+ unsafe { File :: from_raw_fd ( inflight_fd as RawFd ) } ,
1088+ ) )
9571089 }
9581090
959- fn set_inflight_fd ( & mut self , _inflight : & vhost:: vhost_user:: message:: VhostUserInflight , _file : File ) -> VhostUserResult < ( ) > {
960- Err ( VhostUserError :: InvalidOperation )
1091+ fn set_inflight_fd ( & mut self , inflight : & VhostUserInflight , file : File ) -> VhostUserResult < ( ) > {
1092+ // Need to unmap any previously mmaped regions as closing the
1093+ // associated file doesn't unmap it automatically
1094+ // TODO: Handle error
1095+ unsafe {
1096+ libc:: munmap (
1097+ self . inflight_mapping_addr . unwrap ( ) . raw_value ( ) as * mut c_void ,
1098+ self . inflight_mmap_size ,
1099+ )
1100+ } ;
1101+
1102+ let inflight_fd = file. as_raw_fd ( ) ;
1103+
1104+ self . inflight_file = Some ( file) ;
1105+ let mmap_size = inflight. mmap_size ;
1106+ let mmap_offset = inflight. mmap_offset ;
1107+
1108+ let mmap_ptr = unsafe {
1109+ libc:: mmap (
1110+ std:: ptr:: null_mut :: < c_void > ( ) ,
1111+ mmap_size as usize ,
1112+ libc:: PROT_READ | libc:: PROT_WRITE ,
1113+ libc:: MAP_SHARED ,
1114+ inflight_fd,
1115+ mmap_offset as i64 ,
1116+ )
1117+ } ;
1118+
1119+ self . inflight_mapping_addr = Some ( GuestAddress :: new ( mmap_ptr as u64 ) ) ;
1120+ self . inflight_mmap_size = mmap_size as usize ;
1121+
1122+ self . set_inflight_region_desc_num ( inflight. num_queues , inflight. queue_size ) ;
1123+
1124+ Ok ( ( ) )
9611125 }
9621126}
9631127
0 commit comments