Skip to content

Commit

Permalink
Use inotify to wait for the loop device being created
Browse files Browse the repository at this point in the history
  • Loading branch information
tiann committed Feb 14, 2023
1 parent 4baedb0 commit 1833044
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 9 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ direct_io = []
errno = "0.2.8"
libc = "0.2.105"

[target.'cfg(target_os = "android")'.dependencies]
inotify = "0.10"

[build-dependencies]
bindgen = { version = "0.60.1", default-features = false, features = ["runtime"] }

Expand Down
47 changes: 38 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ impl LoopControl {
})?;
let dev = format!("{}{}", LOOP_PREFIX, dev_num);
#[cfg(target_os = "android")]
wait_for_device(&dev);
let _ = wait_until_file_created(&dev);
LoopDevice::open(&dev)
}

Expand Down Expand Up @@ -520,17 +520,46 @@ fn ioctl_to_error(ret: i32) -> io::Result<i32> {
// created by userspace daemon ueventd. There could be a noticeable delay
// between LOOP_CTL_GET_FREE issued and loop device created, so we need to
// wait until it is created and then continue.
// The timeout (5s) and time quantum (20ms) is picked randomly, it bares no
// special meaning but they worked fine empirically.
#[cfg(target_os = "android")]
fn wait_for_device<P: AsRef<Path>>(device: P) {
fn wait_until_file_created<P: AsRef<Path>>(dev: P) -> io::Result<()> {
let path = dev.as_ref();
if path.exists() {
return Ok(());
}

use inotify::{Inotify, WatchMask};
let mut inotify = Inotify::init()?;
// We need to watch the parent directory because the file may not exist yet
// And we can be sure that the parent must exist
let parent_dir = path.parent().ok_or(io::Error::new(
io::ErrorKind::Other,
format!("Cannot get parent directory of {}", path.display()),
))?;
inotify.add_watch(parent_dir, WatchMask::CREATE)?;

// the file may have been created when we are adding the watch
if path.exists() {
return Ok(());
}
// 1024 is enough for most cases
let mut buffer = [0; 1024];
let start = std::time::Instant::now();
let timeout = std::time::Duration::from_secs(5);
let quantum = std::time::Duration::from_millis(20);
while !device.as_ref().exists() {
let timeout = std::time::Duration::from_secs(2);
loop {
if start.elapsed() > timeout {
break;
}
std::thread::sleep(quantum);
if let Ok(events) = inotify.read_events(&mut buffer) {
for event in events {
if let Some(ev_path) = path.file_name() {
return Ok(());
}
}
}
}
}

Err(io::Error::new(
io::ErrorKind::Other,
format!("Timeout waiting for file {} being created!", path.display()),
))
}

0 comments on commit 1833044

Please sign in to comment.