Skip to content

Commit

Permalink
example/ramdisk: always dump device in current context
Browse files Browse the repository at this point in the history
Use eventfd to communicate device id between parent and child,
and dump device in current(parent) context, and this way follows
rublk, and it is more friendly for test code.

Meantime simplify test_ublk_ramdisk_recovery() a bit.

Signed-off-by: Ming Lei <tom.leiming@gmail.com>
  • Loading branch information
ming1 committed Nov 17, 2024
1 parent 69335e7 commit e90cdac
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 37 deletions.
43 changes: 35 additions & 8 deletions examples/ramdisk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use libublk::helpers::IoBuf;
use libublk::io::{UblkDev, UblkQueue};
use libublk::uring_async::ublk_run_ctrl_task;
use libublk::{UblkError, UblkFlags};
use std::io::{Error, ErrorKind};
use std::rc::Rc;
use std::sync::Arc;

Expand Down Expand Up @@ -84,9 +85,29 @@ fn start_dev_fn(
smol::block_on(task)
}

fn write_dev_id(ctrl: &UblkCtrl, efd: i32) -> Result<i32, Error> {
// Can't write 0 to eventfd file, otherwise the read() side may
// not be waken up
let dev_id = ctrl.dev_info().dev_id as u64 + 1;
let bytes = dev_id.to_le_bytes();

nix::unistd::write(efd, &bytes)?;
Ok(0)
}

fn read_dev_id(efd: i32) -> Result<i32, Error> {
let mut buffer = [0; 8];

let bytes_read = nix::unistd::read(efd, &mut buffer)?;
if bytes_read == 0 {
return Err(Error::new(ErrorKind::InvalidInput, "invalid device id"));
}
return Ok((i64::from_le_bytes(buffer) - 1) as i32);
}

///run this ramdisk ublk daemon completely in single context with
///async control command, no need Rust async any more
fn rd_add_dev(dev_id: i32, buf_addr: *mut u8, size: u64, for_add: bool) {
fn rd_add_dev(dev_id: i32, buf_addr: *mut u8, size: u64, for_add: bool, efd: i32) {
let dev_flags = if for_add {
UblkFlags::UBLK_DEV_F_ADD_DEV
} else {
Expand Down Expand Up @@ -127,7 +148,8 @@ fn rd_add_dev(dev_id: i32, buf_addr: *mut u8, size: u64, for_add: bool) {
let res = start_dev_fn(&exec, &ctrl, &dev_arc, &q_rc);
match res {
Ok(_) => {
ctrl.dump();
write_dev_id(&ctrl, efd).expect("Failed to write dev_id");

libublk::uring_async::ublk_wait_and_handle_ios(&exec, &q_rc);
}
_ => eprintln!("device can't be started"),
Expand All @@ -151,12 +173,13 @@ fn test_add(recover: usize) {
.unwrap();
let s = std::env::args().nth(3).unwrap_or_else(|| "32".to_string());
let mb = s.parse::<u64>().unwrap();
let efd = nix::sys::eventfd::eventfd(0, nix::sys::eventfd::EfdFlags::empty()).unwrap();

let daemonize = daemonize::Daemonize::new()
.stdout(daemonize::Stdio::keep())
.stderr(daemonize::Stdio::keep());
match daemonize.start() {
Ok(_) => {
.stdout(daemonize::Stdio::devnull())
.stderr(daemonize::Stdio::devnull());
match daemonize.execute() {
daemonize::Outcome::Child(Ok(_)) => {
let mut size = (mb << 20) as u64;

if recover > 0 {
Expand All @@ -168,9 +191,13 @@ fn test_add(recover: usize) {
}

let buf = libublk::helpers::IoBuf::<u8>::new(size as usize);
rd_add_dev(dev_id, buf.as_mut_ptr(), size, recover == 0);
rd_add_dev(dev_id, buf.as_mut_ptr(), size, recover == 0, efd);
}
Err(_) => panic!(),
daemonize::Outcome::Parent(Ok(_)) => match read_dev_id(efd) {
Ok(id) => UblkCtrl::new_simple(id).unwrap().dump(),
_ => eprintln!("Failed to add ublk device"),
},
_ => panic!(),
}
}

Expand Down
50 changes: 21 additions & 29 deletions tests/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ mod integration {
use libublk::uring_async::ublk_wait_and_handle_ios;
use libublk::{ctrl::UblkCtrl, ctrl::UblkCtrlBuilder, sys, UblkError, UblkFlags, UblkIORes};
use std::env;
use std::io::{BufRead, BufReader};
use std::path::Path;
use std::process::{Command, Stdio};
use std::rc::Rc;
Expand Down Expand Up @@ -410,40 +411,34 @@ mod integration {
}

let tgt_dir = get_curr_bin_dir().unwrap();
let tmpfile = tempfile::NamedTempFile::new().unwrap();
let file = std::fs::File::create(tmpfile.path()).unwrap();

//println!("top dir: path {:?} {:?}", &tgt_dir, &file);
let rd_path = tgt_dir.display().to_string() + &"/examples/ramdisk".to_string();
let mut cmd = Command::new(&rd_path)
.args(["add", "-1", "32"])
.stdout(Stdio::from(file))
.stdout(Stdio::piped())
.spawn()
.expect("fail to add ublk ramdisk");
cmd.wait().unwrap();

let buf = loop {
std::thread::sleep(std::time::Duration::from_millis(200));
let _buf = std::fs::read_to_string(tmpfile.path()).unwrap();

if _buf.len() >= 200 {
break _buf;
}
};

let id_regx = regex::Regex::new(r"dev id (\d+)").unwrap();
let tid_regx = regex::Regex::new(r"queue 0 tid: (\d+)").unwrap();
let stdout = cmd.stdout.take().expect("Failed to capture stdout");
let _ = cmd.wait().expect("Failed to wait on child");

let mut id = -1_i32;
if let Some(c) = id_regx.captures(&buf.as_str()) {
id = c.get(1).unwrap().as_str().parse().unwrap();
}

let mut tid = 0;
if let Some(c) = tid_regx.captures(&buf.as_str()) {
tid = c.get(1).unwrap().as_str().parse().unwrap();
let id_regx = regex::Regex::new(r"dev id (\d+)").unwrap();
let tid_regx = regex::Regex::new(r"queue 0 tid: (\d+)").unwrap();
for line in BufReader::new(stdout).lines() {
match line {
Ok(content) => {
if let Some(c) = id_regx.captures(&content.as_str()) {
id = c.get(1).unwrap().as_str().parse().unwrap();
}
if let Some(c) = tid_regx.captures(&content.as_str()) {
tid = c.get(1).unwrap().as_str().parse().unwrap();
}
}
Err(e) => eprintln!("Error reading line: {}", e), // Handle error
}
}
assert!(tid != 0);
assert!(tid != 0 && id >= 0);

let ctrl = UblkCtrl::new_simple(id).unwrap();
ublk_state_wait_until(&ctrl, sys::UBLK_S_DEV_LIVE as u16, 2000);
Expand All @@ -460,16 +455,13 @@ mod integration {
//wait device becomes quiesced
ublk_state_wait_until(&ctrl, sys::UBLK_S_DEV_QUIESCED as u16, 6000);

let file = std::fs::File::create(tmpfile.path()).unwrap();
//recover device
let mut cmd = Command::new(&rd_path)
.args(["recover", &id.to_string().as_str()])
.stdout(Stdio::from(file))
.stdout(Stdio::piped())
.spawn()
.expect("fail to recover ramdisk");
cmd.wait().unwrap();
//let buf = std::fs::read_to_string(tmpfile.path()).unwrap();
//println!("{}", buf);
cmd.wait().expect("Failed to wait on child");
ublk_state_wait_until(&ctrl, sys::UBLK_S_DEV_LIVE as u16, 20000);
ctrl.del_dev().unwrap();
}
Expand Down

0 comments on commit e90cdac

Please sign in to comment.