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

Commit ad0aeca

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 1a45bc2 commit ad0aeca

File tree

1 file changed

+178
-14
lines changed

1 file changed

+178
-14
lines changed

src/lib.rs

Lines changed: 178 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,30 +7,33 @@
77
#[macro_use]
88
extern crate log;
99

10-
use std::error;
10+
use libc::c_void;
1111
use std::fs::File;
12-
use std::io;
1312
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
1413
use std::os::unix::prelude::IntoRawFd;
15-
use std::result;
1614
use std::sync::{Arc, Mutex, RwLock};
1715
use std::thread;
16+
use std::{error, mem};
17+
use std::{io, usize};
18+
use std::{result, u64};
1819
use 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
};
2325
use 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;
2730
use virtio_bindings::bindings::virtio_ring::VIRTIO_RING_F_EVENT_IDX;
31+
use virtio_queue::Queue;
2832
use vm_memory::guest_memory::FileOffset;
2933
use vm_memory::{
30-
GuestAddress, GuestAddressSpace, GuestMemoryAtomic, GuestMemoryMmap, GuestRegionMmap,
34+
Address, GuestAddress, GuestAddressSpace, GuestMemoryAtomic, GuestMemoryMmap, GuestRegionMmap,
3135
MmapRegion,
3236
};
33-
use virtio_queue::Queue;
3437
use vmm_sys_util::eventfd::EventFd;
3538

3639
const 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

458464
impl<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

557664
impl<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

Comments
 (0)