Skip to content
This repository was archived by the owner on Oct 24, 2022. It is now read-only.

Commit 19a5750

Browse files
committed
Inflight I/O: Implement missing traits
This commit implements the get and set inflight fd members of the VhostUserSlaveReqHandlerMut trait, which is used to pass inflight I/O queue tracking regions as memfds. Fixes #14. Signed-off-by: Harshavardhan Unnibhavi <[email protected]>
1 parent 70f668a commit 19a5750

File tree

2 files changed

+198
-12
lines changed

2 files changed

+198
-12
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ license = "Apache-2.0"
1111
epoll = ">=4.0.1"
1212
libc = ">=0.2.39"
1313
log = ">=0.4.6"
14-
vhost = { version = "0.1", features = ["vhost-user-slave"] }
14+
vhost = { git = "https://github.com/rust-vmm/vhost", features = ["vhost-user-slave"] }
1515
virtio-bindings = "0.1"
1616
virtio-queue = { git = "https://github.com/rust-vmm/vm-virtio", rev = "6013dd9" }
1717
vm-memory = {version = "0.6", features = ["backend-mmap", "backend-atomic"]}

src/handler.rs

Lines changed: 197 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@
66
use std::error;
77
use std::fs::File;
88
use std::io;
9-
use std::os::unix::io::AsRawFd;
9+
use std::os::unix::io::{AsRawFd, FromRawFd};
1010
use std::sync::Arc;
1111
use std::thread;
1212

1313
use vhost::vhost_user::message::{
14-
VhostUserConfigFlags, VhostUserMemoryRegion, VhostUserProtocolFeatures,
14+
DescStatePacked, DescStateSplit, QueueRegionPacked, QueueRegionSplit, VhostUserConfigFlags,
15+
VhostUserInflight, VhostUserMemoryRegion, VhostUserProtocolFeatures,
1516
VhostUserSingleMemoryRegion, VhostUserVirtioFeatures, VhostUserVringAddrFlags,
1617
VhostUserVringState,
1718
};
@@ -23,9 +24,15 @@ use virtio_bindings::bindings::virtio_ring::VIRTIO_RING_F_EVENT_IDX;
2324
use vm_memory::bitmap::Bitmap;
2425
use vm_memory::mmap::NewBitmap;
2526
use vm_memory::{
26-
FileOffset, GuestAddress, GuestAddressSpace, GuestMemoryMmap, GuestRegionMmap, MmapRegion,
27+
Address, FileOffset, GuestAddress, GuestAddressSpace, GuestMemoryMmap, GuestRegionMmap,
28+
MmapRegion,
2729
};
2830

31+
use libc::c_void;
32+
use std::mem;
33+
use std::os::unix::io::RawFd;
34+
use virtio_bindings::bindings::virtio_net::VIRTIO_F_RING_PACKED;
35+
2936
use super::backend::VhostUserBackend;
3037
use super::event_loop::VringEpollHandler;
3138
use super::event_loop::{VringEpollError, VringEpollResult};
@@ -89,6 +96,9 @@ where
8996
atomic_mem: GM<B>,
9097
vrings: Vec<V>,
9198
worker_threads: Vec<thread::JoinHandle<VringEpollResult<()>>>,
99+
inflight_file: Option<File>,
100+
inflight_mapping_addr: Option<GuestAddress>,
101+
inflight_mmap_size: usize,
92102
}
93103

94104
impl<S, V, B> VhostUserHandler<S, V, B>
@@ -146,6 +156,9 @@ where
146156
atomic_mem,
147157
vrings,
148158
worker_threads,
159+
inflight_file: None,
160+
inflight_mapping_addr: None,
161+
inflight_mmap_size: 0,
149162
})
150163
}
151164
}
@@ -535,20 +548,193 @@ where
535548

536549
fn get_inflight_fd(
537550
&mut self,
538-
_inflight: &vhost::vhost_user::message::VhostUserInflight,
551+
inflight: &vhost::vhost_user::message::VhostUserInflight,
539552
) -> VhostUserResult<(vhost::vhost_user::message::VhostUserInflight, File)> {
540-
// Assume the backend hasn't negotiated the inflight feature; it
541-
// wouldn't be correct for the backend to do so, as we don't (yet)
542-
// provide a way for it to handle such requests.
543-
Err(VhostUserError::InvalidOperation)
553+
let ret_val = -1;
554+
// Total size of the inflight queue region
555+
let mut total_mmap_size =
556+
self.get_inflight_queue_size(inflight.queue_size) * inflight.num_queues as usize;
557+
558+
// Create a memfd region to hold the queues for inflight I/O tracking
559+
let mut inflight_fd = -1;
560+
let mmap_ptr = self.memfd_alloc(total_mmap_size, &mut inflight_fd)?;
561+
562+
self.inflight_file = Some(unsafe { File::from_raw_fd(inflight_fd as i32) });
563+
564+
if mmap_ptr == ret_val as *mut c_void {
565+
total_mmap_size = 0;
566+
self.inflight_mapping_addr = None;
567+
} else {
568+
unsafe { libc::memset(mmap_ptr, 0, total_mmap_size) };
569+
self.inflight_mapping_addr = Some(GuestAddress::new(mmap_ptr as u64));
570+
}
571+
self.inflight_mmap_size = total_mmap_size;
572+
573+
Ok((
574+
VhostUserInflight {
575+
mmap_size: total_mmap_size as u64,
576+
mmap_offset: 0,
577+
num_queues: inflight.num_queues,
578+
queue_size: inflight.queue_size,
579+
},
580+
unsafe { File::from_raw_fd(inflight_fd as RawFd) },
581+
))
544582
}
545583

546584
fn set_inflight_fd(
547585
&mut self,
548-
_inflight: &vhost::vhost_user::message::VhostUserInflight,
549-
_file: File,
586+
inflight: &vhost::vhost_user::message::VhostUserInflight,
587+
file: File,
550588
) -> VhostUserResult<()> {
551-
Err(VhostUserError::InvalidOperation)
589+
let ret_val = -1;
590+
591+
// Need to unmap any previously mmaped regions as closing the
592+
// associated file doesn't unmap it automatically
593+
if let Some(inflight_addr) = self.inflight_mapping_addr {
594+
unsafe {
595+
libc::munmap(
596+
inflight_addr.raw_value() as *mut c_void,
597+
self.inflight_mmap_size,
598+
)
599+
};
600+
}
601+
602+
let inflight_fd = file.as_raw_fd();
603+
604+
self.inflight_file = Some(file);
605+
let mmap_size = inflight.mmap_size;
606+
let mmap_offset = inflight.mmap_offset;
607+
608+
let mmap_ptr = unsafe {
609+
libc::mmap(
610+
std::ptr::null_mut::<c_void>(),
611+
mmap_size as usize,
612+
libc::PROT_READ | libc::PROT_WRITE,
613+
libc::MAP_SHARED,
614+
inflight_fd,
615+
mmap_offset as i64,
616+
)
617+
};
618+
619+
if mmap_ptr == ret_val as *mut c_void {
620+
self.inflight_mapping_addr = None;
621+
self.inflight_mmap_size = 0;
622+
} else {
623+
self.inflight_mapping_addr = Some(GuestAddress::new(mmap_ptr as u64));
624+
self.inflight_mmap_size = mmap_size as usize;
625+
}
626+
627+
self.set_inflight_region_desc_num(inflight.num_queues, inflight.queue_size);
628+
629+
Ok(())
630+
}
631+
}
632+
633+
impl<S, V, B> VhostUserHandler<S, V, B>
634+
where
635+
S: VhostUserBackend<V, B>,
636+
V: VringT<GM<B>>,
637+
B: NewBitmap + Clone,
638+
{
639+
fn get_inflight_queue_size(&mut self, queue_size: u16) -> usize {
640+
let queue_region_size;
641+
let descr_state_size;
642+
let virtio_features = self.get_features().unwrap();
643+
644+
if virtio_features & (1 << VIRTIO_F_RING_PACKED) == 0 {
645+
// Use descriptor and queue states for split virtqueues
646+
queue_region_size = mem::size_of::<QueueRegionSplit>();
647+
descr_state_size = mem::size_of::<DescStateSplit>();
648+
} else {
649+
// Use descriptor and queue states for packed virtqueues
650+
queue_region_size = mem::size_of::<QueueRegionPacked>();
651+
descr_state_size = mem::size_of::<DescStatePacked>();
652+
}
653+
queue_region_size + descr_state_size * queue_size as usize
654+
}
655+
656+
fn memfd_alloc(
657+
&self,
658+
mmap_size: usize,
659+
inflight_file: &mut i64,
660+
) -> VhostUserResult<*mut c_void> {
661+
let mut ret_val;
662+
663+
ret_val = unsafe {
664+
libc::syscall(
665+
libc::SYS_memfd_create,
666+
&std::ffi::CString::new("inflight-region").unwrap(),
667+
libc::MFD_ALLOW_SEALING,
668+
)
669+
};
670+
671+
if ret_val == -1 {
672+
return Err(vhost::vhost_user::Error::MemFdCreateError);
673+
}
674+
675+
*inflight_file = ret_val;
676+
677+
ret_val = unsafe { libc::ftruncate(*inflight_file as RawFd, mmap_size as i64) } as i64;
678+
679+
if ret_val == -1 {
680+
return Err(vhost::vhost_user::Error::FileTrucateError);
681+
}
682+
683+
ret_val = unsafe {
684+
libc::fcntl(
685+
*inflight_file as i32,
686+
libc::F_ADD_SEALS,
687+
libc::F_SEAL_GROW | libc::F_SEAL_SHRINK | libc::F_SEAL_SEAL,
688+
)
689+
} as i64;
690+
691+
if ret_val == -1 {
692+
return Err(vhost::vhost_user::Error::MemFdSealError);
693+
}
694+
695+
Ok(unsafe {
696+
libc::mmap(
697+
std::ptr::null_mut(),
698+
mmap_size,
699+
libc::PROT_READ | libc::PROT_WRITE,
700+
libc::MAP_SHARED,
701+
*inflight_file as i32,
702+
0,
703+
)
704+
})
705+
}
706+
707+
fn set_desc_num_packed(&mut self, inflight_region: u64, num_queues: u16, queue_size: u16) {
708+
let raw_ptr = inflight_region as *mut QueueRegionPacked;
709+
710+
for i in 0..num_queues {
711+
unsafe {
712+
let queue_region = raw_ptr.offset(i as isize).as_mut().unwrap();
713+
queue_region.desc_num = queue_size;
714+
}
715+
}
716+
}
717+
718+
fn set_desc_num_split(&mut self, inflight_region: u64, num_queues: u16, queue_size: u16) {
719+
let raw_ptr = inflight_region as *mut QueueRegionSplit;
720+
721+
for i in 0..num_queues {
722+
unsafe {
723+
let queue_region = raw_ptr.offset(i as isize).as_mut().unwrap();
724+
queue_region.desc_num = queue_size;
725+
}
726+
}
727+
}
728+
729+
fn set_inflight_region_desc_num(&mut self, num_queues: u16, queue_size: u16) {
730+
let inflight_region = self.inflight_mapping_addr.unwrap().raw_value();
731+
732+
let virtio_features = self.get_features().unwrap();
733+
734+
match virtio_features & (1 << VIRTIO_F_RING_PACKED) {
735+
0 => self.set_desc_num_split(inflight_region, num_queues, queue_size),
736+
_ => self.set_desc_num_packed(inflight_region, num_queues, queue_size),
737+
};
552738
}
553739
}
554740

0 commit comments

Comments
 (0)