Skip to content

Commit

Permalink
vhost-user: fix reconnecting for vhost user device
Browse files Browse the repository at this point in the history
1. It should set protocol_features when reconnecting which will be used
   in spdk for inflight IO.
2. Set used index as the last avail index for spdk/ovs.

Signed-off-by: Yan Wang <[email protected]>
  • Loading branch information
wangyan0507 authored and Fei Xu committed Nov 9, 2023
1 parent 2c709a4 commit ab019ad
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 27 deletions.
3 changes: 1 addition & 2 deletions machine/src/standard_vm/aarch64/syscall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ const KVM_RUN: u32 = 0xae80;
/// # Notes
/// This allowlist limit syscall with:
/// * aarch64-unknown-gnu: 98 syscalls
/// * aarch64-unknown-musl: 60 syscalls
/// * aarch64-unknown-musl: 61 syscalls
/// To reduce performance losses, the syscall rules is ordered by frequency.
pub fn syscall_whitelist() -> Vec<BpfRule> {
vec![
Expand All @@ -76,7 +76,6 @@ pub fn syscall_whitelist() -> Vec<BpfRule> {
BpfRule::new(libc::SYS_close),
BpfRule::new(libc::SYS_eventfd2),
BpfRule::new(libc::SYS_epoll_ctl),
#[cfg(target_env = "gnu")]
BpfRule::new(libc::SYS_ppoll),
BpfRule::new(libc::SYS_fdatasync),
BpfRule::new(libc::SYS_recvmsg),
Expand Down
3 changes: 1 addition & 2 deletions machine/src/standard_vm/x86_64/syscall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ const KVM_RUN: u32 = 0xae80;
/// # Notes
/// This allowlist limit syscall with:
/// * x86_64-unknown-gnu: 96 syscalls
/// * x86_64-unknown-musl: 63 syscalls
/// * x86_64-unknown-musl: 64 syscalls
/// To reduce performance losses, the syscall rules is ordered by frequency.
pub fn syscall_whitelist() -> Vec<BpfRule> {
vec![
Expand All @@ -78,7 +78,6 @@ pub fn syscall_whitelist() -> Vec<BpfRule> {
BpfRule::new(libc::SYS_close),
BpfRule::new(libc::SYS_eventfd2),
BpfRule::new(libc::SYS_epoll_ctl),
#[cfg(target_env = "gnu")]
BpfRule::new(libc::SYS_ppoll),
BpfRule::new(libc::SYS_fdatasync),
BpfRule::new(libc::SYS_recvmsg),
Expand Down
3 changes: 3 additions & 0 deletions virtio/src/queue/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,9 @@ pub trait VringOps {
/// Get the avail index of the vring.
fn get_avail_idx(&self, sys_mem: &Arc<AddressSpace>) -> Result<u16>;

/// Get the used index of the vring.
fn get_used_idx(&self, sys_mem: &Arc<AddressSpace>) -> Result<u16>;

/// Get the region cache information of the SplitVring.
fn get_cache(&self) -> &Option<RegionCache>;
}
Expand Down
4 changes: 4 additions & 0 deletions virtio/src/queue/split.rs
Original file line number Diff line number Diff line change
Expand Up @@ -903,6 +903,10 @@ impl VringOps for SplitVring {
SplitVring::get_avail_idx(self, sys_mem)
}

fn get_used_idx(&self, sys_mem: &Arc<AddressSpace>) -> Result<u16> {
SplitVring::get_used_idx(self, sys_mem)
}

fn get_cache(&self) -> &Option<RegionCache> {
&self.cache
}
Expand Down
15 changes: 11 additions & 4 deletions virtio/src/vhost/user/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ use vmm_sys_util::eventfd::EventFd;
use super::client::VhostUserClient;
use crate::vhost::VhostOps;
use crate::VhostUser::client::{
VhostBackendType, VHOST_USER_PROTOCOL_F_CONFIG, VHOST_USER_PROTOCOL_F_MQ,
VhostBackendType, VHOST_USER_PROTOCOL_F_CONFIG, VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD,
VHOST_USER_PROTOCOL_F_MQ,
};
use crate::VhostUser::listen_guest_notifier;
use crate::VhostUser::message::VHOST_USER_F_PROTOCOL_FEATURES;
Expand All @@ -45,6 +46,8 @@ pub struct Block {
client: Option<Arc<Mutex<VhostUserClient>>>,
/// Whether irqfd can be used.
pub enable_irqfd: bool,
/// Vhost user protocol features.
protocol_features: u64,
}

impl Block {
Expand All @@ -59,6 +62,7 @@ impl Block {
mem_space: mem_space.clone(),
client: None,
enable_irqfd: false,
protocol_features: 0_u64,
}
}

Expand Down Expand Up @@ -111,10 +115,12 @@ impl VirtioDevice for Block {
let protocol_features = locked_client
.get_protocol_features()
.with_context(|| "Failed to get protocol features for vhost-user blk")?;
let supported_protocol_features =
1 << VHOST_USER_PROTOCOL_F_MQ | 1 << VHOST_USER_PROTOCOL_F_CONFIG;
let supported_protocol_features = 1 << VHOST_USER_PROTOCOL_F_MQ
| 1 << VHOST_USER_PROTOCOL_F_CONFIG
| 1 << VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD;
self.protocol_features = supported_protocol_features & protocol_features;
locked_client
.set_protocol_features(supported_protocol_features & protocol_features)
.set_protocol_features(self.protocol_features)
.with_context(|| "Failed to set protocol features for vhost-user blk")?;

if virtio_has_feature(protocol_features, VHOST_USER_PROTOCOL_F_CONFIG as u32) {
Expand Down Expand Up @@ -207,6 +213,7 @@ impl VirtioDevice for Block {
None => return Err(anyhow!("Failed to get client for vhost-user blk")),
};
client.features = self.base.driver_features;
client.protocol_features = self.protocol_features;
client.set_queues(&self.base.queues);
client.set_queue_evts(&queue_evts);

Expand Down
70 changes: 51 additions & 19 deletions virtio/src/vhost/user/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ pub const VHOST_USER_PROTOCOL_F_MQ: u8 = 0;
/// Vhost supports `VHOST_USER_SET_CONFIG` and `VHOST_USER_GET_CONFIG` msg.
pub const VHOST_USER_PROTOCOL_F_CONFIG: u8 = 9;
/// Vhost supports `VHOST_USER_SET_INFLIGHT_FD` and `VHOST_USER_GET_INFLIGHT_FD` msg.
const VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD: u8 = 12;
pub const VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD: u8 = 12;

struct ClientInternal {
// Used to send requests to the vhost user backend in userspace.
Expand Down Expand Up @@ -100,7 +100,8 @@ fn vhost_user_reconnect(client: &Arc<Mutex<VhostUserClient>>) {
vhost_user_reconnect(&cloned_client);
});

info!("Try to reconnect vhost-user net.");
let dev_type = client.lock().unwrap().backend_type.to_string();
info!("Try to reconnect vhost-user {}.", dev_type);
if let Err(_e) = client
.lock()
.unwrap()
Expand All @@ -121,9 +122,22 @@ fn vhost_user_reconnect(client: &Arc<Mutex<VhostUserClient>>) {
client.lock().unwrap().reconnecting = false;
if let Err(e) = VhostUserClient::add_event(client) {
error!("Failed to update event for client sock, {:?}", e);
return;
}

let mut locked_client = client.lock().unwrap();
let protocol_features = locked_client.protocol_features;
if protocol_features != 0 {
if let Err(e) = locked_client.set_protocol_features(protocol_features) {
error!(
"Failed to set protocol features for vhost-user {}, {:?}",
dev_type, e
);
return;
}
}

if let Err(e) = client.lock().unwrap().activate_vhost_user() {
if let Err(e) = locked_client.activate_vhost_user() {
error!("Failed to reactivate vhost-user net, {:?}", e);
} else {
info!("Reconnecting vhost-user net succeed.");
Expand Down Expand Up @@ -350,6 +364,16 @@ pub enum VhostBackendType {
TypeFs,
}

impl ToString for VhostBackendType {
fn to_string(&self) -> String {
match self {
VhostBackendType::TypeNet => String::from("net"),
VhostBackendType::TypeBlock => String::from("block"),
VhostBackendType::TypeFs => String::from("fs"),
}
}
}

/// Struct for communication with the vhost user backend in userspace
pub struct VhostUserClient {
client: Arc<Mutex<ClientInternal>>,
Expand All @@ -363,6 +387,7 @@ pub struct VhostUserClient {
reconnecting: bool,
inflight: Option<VhostInflight>,
backend_type: VhostBackendType,
pub protocol_features: u64,
}

impl VhostUserClient {
Expand Down Expand Up @@ -398,6 +423,7 @@ impl VhostUserClient {
reconnecting: false,
inflight: None,
backend_type,
protocol_features: 0_u64,
})
}

Expand Down Expand Up @@ -501,20 +527,22 @@ impl VhostUserClient {

for (queue_index, queue_mutex) in self.queues.iter().enumerate() {
let queue = queue_mutex.lock().unwrap();
let queue_config = queue.vring.get_queue_config();
if !queue.vring.is_enabled() {
warn!("Queue {} is not enabled, skip it", queue_index);
continue;
}

let queue_config = queue.vring.get_queue_config();
self.set_vring_addr(&queue_config, queue_index, 0)
.with_context(|| {
format!(
"Failed to set vring addr for vhost-user, index: {}",
queue_index,
)
})?;
let last_avail_idx = if queue.vring.is_enabled() {
queue.vring.get_avail_idx(&self.mem_space)?
} else {
0
};
// When spdk/ovs has been killed, stratovirt can not get the last avail
// index in spdk/ovs, it can only use used index as last avail index.
let last_avail_idx = queue.vring.get_used_idx(&self.mem_space)?;
self.set_vring_base(queue_index, last_avail_idx)
.with_context(|| {
format!(
Expand Down Expand Up @@ -542,23 +570,27 @@ impl VhostUserClient {
// If VHOST_USER_F_PROTOCOL_FEATURES has been negotiated, it should call
// set_vring_enable to enable vring. Otherwise, the ring is enabled by default.
// Currently, only vhost-user-blk device support negotiate VHOST_USER_F_PROTOCOL_FEATURES.
for (queue_index, queue) in self.queues.iter().enumerate() {
let enabled = queue.lock().unwrap().is_enabled();
self.set_vring_enable(queue_index, enabled)
.with_context(|| {
format!(
"Failed to set vring enable for vhost-user, index: {}",
queue_index,
)
})?;
for (queue_index, queue_mutex) in self.queues.iter().enumerate() {
if !queue_mutex.lock().unwrap().is_enabled() {
continue;
}
self.set_vring_enable(queue_index, true).with_context(|| {
format!(
"Failed to set vring enable for vhost-user, index: {}",
queue_index,
)
})?;
}
}

Ok(())
}

pub fn reset_vhost_user(&mut self) -> Result<()> {
for (queue_index, _) in self.queues.iter().enumerate() {
for (queue_index, queue_mutex) in self.queues.iter().enumerate() {
if !queue_mutex.lock().unwrap().vring.is_enabled() {
continue;
}
self.set_vring_enable(queue_index, false)
.with_context(|| format!("Failed to set vring disable, index: {}", queue_index))?;
self.get_vring_base(queue_index)
Expand Down

0 comments on commit ab019ad

Please sign in to comment.