vhost_user_blk: implement support for direct (O_DIRECT) mode

Add support for opening the disk images with O_DIRECT. This allows
bypassing the host's file system cache, which is useful to avoid
polluting its cache and for better data integrity.

This mode of operation can be enabled by adding the "direct=<bool>"
parameter to the "backend" argument:

./target/debug/vhost_user_blk --backend image=test.raw,sock=/tmp/vhostblk,direct=true

The "direct" parameter defaults to "false", to preserve the original
behavior.

Signed-off-by: Sergio Lopez <slp@redhat.com>
This commit is contained in:
Sergio Lopez 2019-12-02 14:59:09 +01:00 committed by Rob Bradford
parent a14aee9213
commit c7e9056c1e

View File

@ -23,6 +23,7 @@ use std::fs::OpenOptions;
use std::io::Read;
use std::io::{Seek, SeekFrom, Write};
use std::mem;
use std::os::unix::fs::OpenOptionsExt;
use std::path::PathBuf;
use std::process;
use std::slice;
@ -58,6 +59,8 @@ pub enum Error {
GuestMemory(GuestMemoryError),
/// Can't open image file.
OpenImage,
/// Failed to parse direct parameter.
ParseDirectParam,
/// Failed to parse image parameter.
ParseImageParam,
/// Failed to parse sock parameter.
@ -77,13 +80,15 @@ struct VhostUserBlkBackend {
}
impl VhostUserBlkBackend {
pub fn new(image_path: String, rdonly: bool) -> Result<Self> {
let image: File = OpenOptions::new()
.read(true)
.write(!rdonly)
.open(&image_path)
.unwrap();
let mut raw_img = vm_virtio::RawFile::new(image, false);
pub fn new(image_path: String, rdonly: bool, direct: bool) -> Result<Self> {
let mut options = OpenOptions::new();
options.read(true);
options.write(!rdonly);
if direct {
options.custom_flags(libc::O_DIRECT);
}
let image: File = options.open(&image_path).unwrap();
let mut raw_img: vm_virtio::RawFile = vm_virtio::RawFile::new(image, direct);
let image_id = build_disk_image_id(&PathBuf::from(&image_path));
let image_type = qcow::detect_image_type(&mut raw_img).unwrap();
@ -225,6 +230,7 @@ pub struct VhostUserBlkBackendConfig<'a> {
pub image: &'a str,
pub sock: &'a str,
pub readonly: bool,
pub direct: bool,
}
impl<'a> VhostUserBlkBackendConfig<'a> {
@ -234,6 +240,7 @@ impl<'a> VhostUserBlkBackendConfig<'a> {
let mut image: &str = "";
let mut sock: &str = "";
let mut readonly: bool = false;
let mut direct: bool = false;
for param in params_list.iter() {
if param.starts_with("image=") {
@ -245,6 +252,11 @@ impl<'a> VhostUserBlkBackendConfig<'a> {
Ok(b) => b,
Err(_) => return Err(Error::ParseReadOnlyParam),
}
} else if param.starts_with("direct=") {
direct = match param[7..].parse::<bool>() {
Ok(b) => b,
Err(_) => return Err(Error::ParseDirectParam),
}
}
}
@ -259,6 +271,7 @@ impl<'a> VhostUserBlkBackendConfig<'a> {
image,
sock,
readonly,
direct,
})
}
}
@ -273,7 +286,8 @@ fn main() {
.long("backend")
.help(
"Backend parameters \"image=<image_path>,\
sock=<socket_path>,readonly=true|false\"",
sock=<socket_path>,readonly=true|false,\
direct=true|false\"",
)
.takes_value(true)
.min_values(1),
@ -291,8 +305,12 @@ fn main() {
};
let blk_backend = Arc::new(RwLock::new(
VhostUserBlkBackend::new(backend_config.image.to_string(), backend_config.readonly)
.unwrap(),
VhostUserBlkBackend::new(
backend_config.image.to_string(),
backend_config.readonly,
backend_config.direct,
)
.unwrap(),
));
debug!("blk_backend is created!\n");