From 1833044f760dd9471ebdb5fbe6c42d2b17f9e557 Mon Sep 17 00:00:00 2001 From: tiann Date: Tue, 14 Feb 2023 10:40:57 +0800 Subject: [PATCH] Use inotify to wait for the loop device being created --- Cargo.toml | 3 +++ src/lib.rs | 47 ++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 41 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 64307fa..14182e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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"] } diff --git a/src/lib.rs b/src/lib.rs index b13644f..6d84db6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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) } @@ -520,17 +520,46 @@ fn ioctl_to_error(ret: i32) -> io::Result { // 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>(device: P) { +fn wait_until_file_created>(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(()); + } + } + } } -} \ No newline at end of file + + Err(io::Error::new( + io::ErrorKind::Other, + format!("Timeout waiting for file {} being created!", path.display()), + )) +}