vhost-device-console: Being able to specify max queue size

Some hypervisors, e.g. UML, negotiate a queue size larger than `QUEUE_SIZE`
(128), which results in failures. This patch allows users to specify it
using `--max-queue-size <size>`.

Signed-off-by: Xuewei Niu <niuxuewei.nxw@antgroup.com>
This commit is contained in:
Xuewei Niu 2025-02-11 18:13:46 +08:00 committed by Manos Pitsidianakis
parent bc07d3ef7a
commit 04c30f700a
5 changed files with 77 additions and 32 deletions

View File

@ -3,6 +3,8 @@
### Added
- [#811](https://github.com/rust-vmm/vhost-device/pull/811) Being able to specify max queue size
### Changed
### Fixed

View File

@ -47,6 +47,11 @@ vhost-device-console --socket-path=<SOCKET_PATH>
Note: The nested backend is selected by default and can be used only when
socket_count equals 1.
.. option:: -q, --max-queue-size=SIZE
The maximum size of virtqueues. It is optional, and the default value is
128. The size must be greater than 0 and a power of 2.
## Limitations
This device is still work-in-progress (WIP). The current version has been tested

View File

@ -50,6 +50,7 @@ pub struct VuConsoleConfig {
pub backend: BackendType,
pub tcp_port: String,
pub socket_count: u32,
pub max_queue_size: usize,
}
impl VuConsoleConfig {
@ -86,12 +87,18 @@ impl VuConsoleConfig {
/// This is the public API through which an external program starts the
/// vhost-device-console backend server.
pub fn start_backend_server(socket: PathBuf, tcp_addr: String, backend: BackendType) -> Result<()> {
pub fn start_backend_server(
socket: PathBuf,
tcp_addr: String,
backend: BackendType,
max_queue_size: usize,
) -> Result<()> {
loop {
let controller = ConsoleController::new(backend);
let arc_controller = Arc::new(RwLock::new(controller));
let vu_console_backend = Arc::new(RwLock::new(
VhostUserConsoleBackend::new(arc_controller).map_err(Error::CouldNotCreateBackend)?,
VhostUserConsoleBackend::new(max_queue_size, arc_controller)
.map_err(Error::CouldNotCreateBackend)?,
));
vu_console_backend
@ -127,6 +134,7 @@ pub fn start_backend(config: VuConsoleConfig) -> Result<()> {
let (senders, receiver) = std::sync::mpsc::channel();
let tcp_addrs = config.generate_tcp_addrs();
let backend = config.backend;
let max_queue_size = config.max_queue_size;
for (thread_id, (socket, tcp_addr)) in config
.generate_socket_paths()
@ -143,7 +151,7 @@ pub fn start_backend(config: VuConsoleConfig) -> Result<()> {
.name(name.clone())
.spawn(move || {
let result = std::panic::catch_unwind(move || {
start_backend_server(socket, tcp_addr.to_string(), backend)
start_backend_server(socket, tcp_addr.to_string(), backend, max_queue_size)
});
// Notify the main thread that we are done.
@ -173,7 +181,7 @@ mod tests {
use assert_matches::assert_matches;
use super::*;
use crate::ConsoleArgs;
use crate::{ConsoleArgs, DEFAULT_QUEUE_SIZE};
#[test]
fn test_console_valid_configuration_nested() {
@ -182,6 +190,7 @@ mod tests {
backend: BackendType::Nested,
tcp_port: String::from("12345"),
socket_count: 1,
max_queue_size: DEFAULT_QUEUE_SIZE,
};
VuConsoleConfig::try_from(args).unwrap();
@ -194,6 +203,7 @@ mod tests {
backend: BackendType::Nested,
tcp_port: String::from("12345"),
socket_count: 0,
max_queue_size: DEFAULT_QUEUE_SIZE,
};
assert_matches!(
@ -209,6 +219,7 @@ mod tests {
backend: BackendType::Nested,
tcp_port: String::from("12345"),
socket_count: 2,
max_queue_size: DEFAULT_QUEUE_SIZE,
};
assert_matches!(
@ -224,6 +235,7 @@ mod tests {
backend: BackendType::Network,
tcp_port: String::from("12345"),
socket_count: 1,
max_queue_size: DEFAULT_QUEUE_SIZE,
};
VuConsoleConfig::try_from(args).unwrap();
@ -236,6 +248,7 @@ mod tests {
backend: BackendType::Network,
tcp_port: String::from("12345"),
socket_count: 2,
max_queue_size: DEFAULT_QUEUE_SIZE,
};
VuConsoleConfig::try_from(args).unwrap();
@ -246,13 +259,14 @@ mod tests {
let tcp_addrs = config.generate_tcp_addrs();
let backend = config.backend;
let max_queue_size = config.max_queue_size;
for (socket, tcp_addr) in config
.generate_socket_paths()
.into_iter()
.zip(tcp_addrs.iter())
{
start_backend_server(socket, tcp_addr.to_string(), backend)?;
start_backend_server(socket, tcp_addr.to_string(), backend, max_queue_size)?;
}
Ok(())
}
@ -264,6 +278,7 @@ mod tests {
backend: BackendType::Network,
tcp_port: String::from("12345"),
socket_count: 1,
max_queue_size: DEFAULT_QUEUE_SIZE,
};
assert!(test_backend_start_and_stop(args).is_err());
@ -276,6 +291,7 @@ mod tests {
backend: BackendType::Network,
tcp_port: String::from("12346"),
socket_count: 1,
max_queue_size: DEFAULT_QUEUE_SIZE,
};
assert!(start_backend(config).is_err());

View File

@ -44,6 +44,8 @@ use crate::console::BackendType;
pub type Result<T> = std::result::Result<T, Error>;
use crate::backend::{start_backend, Error, VuConsoleConfig};
const DEFAULT_QUEUE_SIZE: usize = 128;
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
struct ConsoleArgs {
@ -65,6 +67,10 @@ struct ConsoleArgs {
/// `tcp_port + 1`, ... , `tcp_port + (N - 1)`.
#[clap(short = 'p', long, value_name = "PORT", default_value = "12345")]
tcp_port: String,
/// Specify the maximum size of virtqueue, the default is 128.
#[clap(short = 'q', long, default_value_t = DEFAULT_QUEUE_SIZE)]
max_queue_size: usize,
}
impl TryFrom<ConsoleArgs> for VuConsoleConfig {
@ -84,6 +90,7 @@ impl TryFrom<ConsoleArgs> for VuConsoleConfig {
backend,
tcp_port,
socket_count,
max_queue_size,
} = args;
Ok(Self {
@ -91,6 +98,7 @@ impl TryFrom<ConsoleArgs> for VuConsoleConfig {
backend,
tcp_port,
socket_count,
max_queue_size,
})
}
}

View File

@ -124,6 +124,7 @@ impl<T: Read + Write> ReadWrite for T {}
unsafe impl ByteValued for VirtioConsoleControl {}
pub struct VhostUserConsoleBackend {
max_queue_size: usize,
controller: Arc<RwLock<ConsoleController>>,
acked_features: u64,
event_idx: bool,
@ -147,11 +148,11 @@ type ConsoleDescriptorChain = DescriptorChain<GuestMemoryLoadGuard<GuestMemoryMm
impl VhostUserConsoleBackend {
// Virtio configuration
pub const QUEUE_SIZE: usize = 128;
pub const NUM_QUEUES: u16 = 4;
pub fn new(controller: Arc<RwLock<ConsoleController>>) -> Result<Self> {
pub fn new(max_queue_size: usize, controller: Arc<RwLock<ConsoleController>>) -> Result<Self> {
Ok(Self {
max_queue_size,
controller,
event_idx: false,
rx_ctrl_fifo: Queue::new(),
@ -698,7 +699,7 @@ impl VhostUserBackendMut for VhostUserConsoleBackend {
}
fn max_queue_size(&self) -> usize {
Self::QUEUE_SIZE
self.max_queue_size
}
fn features(&self) -> u64 {
@ -863,12 +864,14 @@ mod tests {
use vm_memory::{Bytes, GuestAddress, GuestMemoryAtomic, GuestMemoryMmap};
use super::*;
use crate::DEFAULT_QUEUE_SIZE;
#[test]
fn test_vhost_user_console_backend_creation() {
let console_controller = Arc::new(RwLock::new(ConsoleController::new(BackendType::Nested)));
let vhost_user_console_backend = VhostUserConsoleBackend::new(console_controller)
.expect("Failed create vhuconsole backend");
let vhost_user_console_backend =
VhostUserConsoleBackend::new(DEFAULT_QUEUE_SIZE, console_controller)
.expect("Failed create vhuconsole backend");
assert_eq!(vhost_user_console_backend.acked_features, 0);
assert!(!vhost_user_console_backend.event_idx);
@ -879,8 +882,9 @@ mod tests {
#[test]
fn test_virtio_console_empty_handle_request() {
let console_controller = Arc::new(RwLock::new(ConsoleController::new(BackendType::Nested)));
let mut vu_console_backend = VhostUserConsoleBackend::new(console_controller)
.expect("Failed create vhuconsole backend");
let mut vu_console_backend =
VhostUserConsoleBackend::new(DEFAULT_QUEUE_SIZE, console_controller)
.expect("Failed create vhuconsole backend");
let mem = GuestMemoryAtomic::new(
GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x1000)]).unwrap(),
@ -926,8 +930,9 @@ mod tests {
#[test]
fn test_virtio_console_empty_requests() {
let console_controller = Arc::new(RwLock::new(ConsoleController::new(BackendType::Nested)));
let mut vu_console_backend = VhostUserConsoleBackend::new(console_controller)
.expect("Failed create vhuconsole backend");
let mut vu_console_backend =
VhostUserConsoleBackend::new(DEFAULT_QUEUE_SIZE, console_controller)
.expect("Failed create vhuconsole backend");
let mem = GuestMemoryAtomic::new(
GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x1000)]).unwrap(),
@ -985,8 +990,9 @@ mod tests {
#[test]
fn test_virtio_console_ctrl_rx_request() {
let console_controller = Arc::new(RwLock::new(ConsoleController::new(BackendType::Nested)));
let mut vu_console_backend = VhostUserConsoleBackend::new(console_controller)
.expect("Failed create vhuconsole backend");
let mut vu_console_backend =
VhostUserConsoleBackend::new(DEFAULT_QUEUE_SIZE, console_controller)
.expect("Failed create vhuconsole backend");
let mem = GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x1000)]).unwrap();
@ -1059,8 +1065,9 @@ mod tests {
#[test]
fn test_virtio_console_ctrl_tx_request() {
let console_controller = Arc::new(RwLock::new(ConsoleController::new(BackendType::Nested)));
let mut vu_console_backend = VhostUserConsoleBackend::new(console_controller)
.expect("Failed create vhuconsole backend");
let mut vu_console_backend =
VhostUserConsoleBackend::new(DEFAULT_QUEUE_SIZE, console_controller)
.expect("Failed create vhuconsole backend");
let mem = GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x1000)]).unwrap();
@ -1109,8 +1116,9 @@ mod tests {
#[test]
fn test_virtio_console_handle_control_msg() {
let console_controller = Arc::new(RwLock::new(ConsoleController::new(BackendType::Nested)));
let mut vu_console_backend = VhostUserConsoleBackend::new(console_controller)
.expect("Failed create vhuconsole backend");
let mut vu_console_backend =
VhostUserConsoleBackend::new(DEFAULT_QUEUE_SIZE, console_controller)
.expect("Failed create vhuconsole backend");
let mem = GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x1000)]).unwrap();
let mem_1 = GuestMemoryAtomic::new(mem.clone());
@ -1162,8 +1170,9 @@ mod tests {
#[test]
fn test_virtio_console_tx_request() {
let console_controller = Arc::new(RwLock::new(ConsoleController::new(BackendType::Nested)));
let mut vu_console_backend = VhostUserConsoleBackend::new(console_controller)
.expect("Failed create vhuconsole backend");
let mut vu_console_backend =
VhostUserConsoleBackend::new(DEFAULT_QUEUE_SIZE, console_controller)
.expect("Failed create vhuconsole backend");
let mem = GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x1000)]).unwrap();
@ -1217,8 +1226,9 @@ mod tests {
fn test_virtio_console_tx_request_network() {
let console_controller =
Arc::new(RwLock::new(ConsoleController::new(BackendType::Network)));
let mut vu_console_backend = VhostUserConsoleBackend::new(console_controller)
.expect("Failed create vhuconsole backend");
let mut vu_console_backend =
VhostUserConsoleBackend::new(DEFAULT_QUEUE_SIZE, console_controller)
.expect("Failed create vhuconsole backend");
let mem = GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x1000)]).unwrap();
let desc_chain = build_desc_chain(&mem, 1, vec![0], 0x200);
@ -1258,8 +1268,9 @@ mod tests {
#[test]
fn test_virtio_console_rx_request() {
let console_controller = Arc::new(RwLock::new(ConsoleController::new(BackendType::Nested)));
let mut vu_console_backend = VhostUserConsoleBackend::new(console_controller)
.expect("Failed create vhuconsole backend");
let mut vu_console_backend =
VhostUserConsoleBackend::new(DEFAULT_QUEUE_SIZE, console_controller)
.expect("Failed create vhuconsole backend");
let mem = GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x1000)]).unwrap();
@ -1331,8 +1342,9 @@ mod tests {
#[test]
fn test_virtio_console_start_nested_console_thread() {
let console_controller = Arc::new(RwLock::new(ConsoleController::new(BackendType::Nested)));
let mut vu_console_backend = VhostUserConsoleBackend::new(console_controller)
.expect("Failed create vhuconsole backend");
let mut vu_console_backend =
VhostUserConsoleBackend::new(DEFAULT_QUEUE_SIZE, console_controller)
.expect("Failed create vhuconsole backend");
let mem = GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x1000)]).unwrap();
let mem = GuestMemoryAtomic::new(mem);
@ -1360,8 +1372,9 @@ mod tests {
fn test_virtio_console_tcp_console_read_func() {
let console_controller =
Arc::new(RwLock::new(ConsoleController::new(BackendType::Network)));
let mut vu_console_backend = VhostUserConsoleBackend::new(console_controller)
.expect("Failed create vhuconsole backend");
let mut vu_console_backend =
VhostUserConsoleBackend::new(DEFAULT_QUEUE_SIZE, console_controller)
.expect("Failed create vhuconsole backend");
let mem = GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x1000)]).unwrap();
let mem = GuestMemoryAtomic::new(mem);
@ -1389,8 +1402,9 @@ mod tests {
fn test_virtio_console_tcp_console_write_func() {
let console_controller =
Arc::new(RwLock::new(ConsoleController::new(BackendType::Network)));
let mut vu_console_backend = VhostUserConsoleBackend::new(console_controller)
.expect("Failed create vhuconsole backend");
let mut vu_console_backend =
VhostUserConsoleBackend::new(DEFAULT_QUEUE_SIZE, console_controller)
.expect("Failed create vhuconsole backend");
let mem = GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x1000)]).unwrap();
let mem = GuestMemoryAtomic::new(mem);