Merge "Add support for autoclear flag for loopdevice" into main
diff --git a/guest/apkdmverity/src/main.rs b/guest/apkdmverity/src/main.rs
index d2f88ae..2fc964b 100644
--- a/guest/apkdmverity/src/main.rs
+++ b/guest/apkdmverity/src/main.rs
@@ -27,6 +27,7 @@
use apkverify::{HashAlgorithm, V4Signature};
use clap::{arg, Arg, ArgAction, Command};
use dm::loopdevice;
+use dm::loopdevice::LoopConfigOptions;
use dm::util;
use dm::verity::{DmVerityHashAlgorithm, DmVerityTargetBuilder};
use itertools::Itertools;
@@ -109,9 +110,13 @@
}
(
loopdevice::attach(
- &apk, 0, apk_size, /* direct_io */ true, /* writable */ false,
+ &apk,
+ 0,
+ apk_size,
+ &LoopConfigOptions { direct_io: true, ..Default::default() },
)
- .context("Failed to attach APK to a loop device")?,
+ .context("Failed to attach APK to a loop device")?
+ .path,
apk_size,
)
};
@@ -125,10 +130,9 @@
// Due to unknown reason(b/191344832), we can't enable "direct IO" for the IDSIG file (backing
// the hash). For now we don't use "direct IO" but it seems OK since the IDSIG file is very
// small and the benefit of direct-IO would be negliable.
- let hash_device = loopdevice::attach(
- &idsig, offset, size, /* direct_io */ false, /* writable */ false,
- )
- .context("Failed to attach idsig to a loop device")?;
+ let hash_device = loopdevice::attach(&idsig, offset, size, &LoopConfigOptions::default())
+ .context("Failed to attach idsig to a loop device")?
+ .path;
// Build a dm-verity target spec from the information from the idsig file. The apk and the
// idsig files are used as the data device and the hash device, respectively.
@@ -347,18 +351,17 @@
// of the data device is done in the scopeguard for the return value of `enable_verity`
// below. Only the idsig_loop_device needs detatching.
let apk_loop_device = loopdevice::attach(
- &apk_path, 0, apk_size, /* direct_io */ true, /* writable */ false,
+ &apk_path,
+ 0,
+ apk_size,
+ &LoopConfigOptions { direct_io: true, ..Default::default() },
)
- .unwrap();
+ .unwrap()
+ .path;
let idsig_loop_device = scopeguard::guard(
- loopdevice::attach(
- &idsig_path,
- 0,
- idsig_size,
- /* direct_io */ false,
- /* writable */ false,
- )
- .unwrap(),
+ loopdevice::attach(&idsig_path, 0, idsig_size, &LoopConfigOptions::default())
+ .unwrap()
+ .path,
|dev| loopdevice::detach(dev).unwrap(),
);
diff --git a/libs/devicemapper/Android.bp b/libs/devicemapper/Android.bp
index 5332469..6b7f680 100644
--- a/libs/devicemapper/Android.bp
+++ b/libs/devicemapper/Android.bp
@@ -8,7 +8,6 @@
defaults: ["avf_build_flags_rust"],
srcs: ["src/lib.rs"],
edition: "2021",
- prefer_rlib: true,
rustlibs: [
"libanyhow",
"libbitflags",
@@ -18,16 +17,12 @@
"libuuid",
"libzerocopy",
],
- multilib: {
- lib32: {
- enabled: false,
- },
- },
}
rust_library {
name: "libdm_rust",
defaults: ["libdm_rust.defaults"],
+ host_supported: true,
}
rust_test {
diff --git a/libs/devicemapper/src/lib.rs b/libs/devicemapper/src/lib.rs
index a8f3049..a8c2833 100644
--- a/libs/devicemapper/src/lib.rs
+++ b/libs/devicemapper/src/lib.rs
@@ -235,6 +235,7 @@
#[cfg(test)]
mod tests {
use super::*;
+ use crate::loopdevice::LoopConfigOptions;
use crypt::{CipherType, DmCryptTargetBuilder};
use rdroidtest::{ignore_if, rdroidtest};
use rustutils::system_properties;
@@ -328,10 +329,10 @@
backing_file,
0,
sz,
- /* direct_io */ true,
- /* writable */ true,
+ &LoopConfigOptions { direct_io: true, writable: true, ..Default::default() },
)
- .unwrap();
+ .unwrap()
+ .path;
let device_diff = device.to_owned() + "_diff";
scopeguard::defer! {
@@ -372,10 +373,10 @@
backing_file,
0,
sz,
- /* direct_io */ true,
- /* writable */ true,
+ &LoopConfigOptions { direct_io: true, writable: true, ..Default::default() },
)
- .unwrap();
+ .unwrap()
+ .path;
let device_diff = device.to_owned() + "_diff";
scopeguard::defer! {
loopdevice::detach(&data_device).unwrap();
diff --git a/libs/devicemapper/src/loopdevice.rs b/libs/devicemapper/src/loopdevice.rs
index 130c1c4..b830eda 100644
--- a/libs/devicemapper/src/loopdevice.rs
+++ b/libs/devicemapper/src/loopdevice.rs
@@ -59,14 +59,31 @@
Ok(unsafe { _loop_clr_fd(device_file.as_raw_fd()) }?)
}
+/// LOOP_CONFIGURE ioctl operation flags.
+#[derive(Default)]
+pub struct LoopConfigOptions {
+ /// Whether to use direct I/O
+ pub direct_io: bool,
+ /// Whether the device is writable
+ pub writable: bool,
+ /// Whether to autodestruct the device on last close
+ pub autoclear: bool,
+}
+
+pub struct LoopDevice {
+ /// The loop device file
+ pub file: File,
+ /// Path to the loop device
+ pub path: PathBuf,
+}
+
/// Creates a loop device and attach the given file at `path` as the backing store.
pub fn attach<P: AsRef<Path>>(
path: P,
offset: u64,
size_limit: u64,
- direct_io: bool,
- writable: bool,
-) -> Result<PathBuf> {
+ options: &LoopConfigOptions,
+) -> Result<LoopDevice> {
// Attaching a file to a loop device can make a race condition; a loop device number obtained
// from LOOP_CTL_GET_FREE might have been used by another thread or process. In that case the
// subsequent LOOP_CONFIGURE ioctl returns with EBUSY. Try until it succeeds.
@@ -80,8 +97,8 @@
let begin = Instant::now();
loop {
- match try_attach(&path, offset, size_limit, direct_io, writable) {
- Ok(loop_dev) => return Ok(loop_dev),
+ match try_attach(&path, offset, size_limit, options) {
+ Ok(loop_device) => return Ok(loop_device),
Err(e) => {
if begin.elapsed() > TIMEOUT {
return Err(e);
@@ -102,9 +119,8 @@
path: P,
offset: u64,
size_limit: u64,
- direct_io: bool,
- writable: bool,
-) -> Result<PathBuf> {
+ options: &LoopConfigOptions,
+) -> Result<LoopDevice> {
// Get a free loop device
wait_for_path(LOOP_CONTROL)?;
let ctrl_file = OpenOptions::new()
@@ -117,8 +133,8 @@
// Construct the loop_info64 struct
let backing_file = OpenOptions::new()
.read(true)
- .write(writable)
- .custom_flags(if direct_io { O_DIRECT } else { 0 })
+ .write(options.writable)
+ .custom_flags(if options.direct_io { O_DIRECT } else { 0 })
.open(&path)
.context(format!("failed to open {:?}", path.as_ref()))?;
let mut config = loop_config::new_zeroed();
@@ -127,14 +143,18 @@
config.info.lo_offset = offset;
config.info.lo_sizelimit = size_limit;
- if !writable {
+ if !options.writable {
config.info.lo_flags = Flag::LO_FLAGS_READ_ONLY;
}
- if direct_io {
+ if options.direct_io {
config.info.lo_flags.insert(Flag::LO_FLAGS_DIRECT_IO);
}
+ if options.autoclear {
+ config.info.lo_flags.insert(Flag::LO_FLAGS_AUTOCLEAR);
+ }
+
// Configure the loop device to attach the backing file
let device_path = format!("{}{}", LOOP_DEV_PREFIX, num);
wait_for_path(&device_path)?;
@@ -146,7 +166,7 @@
loop_configure(&device_file, &config)
.context(format!("Failed to configure {:?}", &device_path))?;
- Ok(PathBuf::from(device_path))
+ Ok(LoopDevice { file: device_file, path: PathBuf::from(device_path) })
}
/// Detaches backing file from the loop device `path`.
@@ -185,7 +205,10 @@
let a_file = a_dir.path().join("test");
let a_size = 4096u64;
create_empty_file(&a_file, a_size);
- let dev = attach(a_file, 0, a_size, /* direct_io */ true, /* writable */ false).unwrap();
+ let dev =
+ attach(a_file, 0, a_size, &LoopConfigOptions { direct_io: true, ..Default::default() })
+ .unwrap()
+ .path;
scopeguard::defer! {
detach(&dev).unwrap();
}
@@ -198,7 +221,7 @@
let a_file = a_dir.path().join("test");
let a_size = 4096u64;
create_empty_file(&a_file, a_size);
- let dev = attach(a_file, 0, a_size, /* direct_io */ false, /* writable */ false).unwrap();
+ let dev = attach(a_file, 0, a_size, &LoopConfigOptions::default()).unwrap().path;
scopeguard::defer! {
detach(&dev).unwrap();
}
@@ -211,11 +234,34 @@
let a_file = a_dir.path().join("test");
let a_size = 4096u64;
create_empty_file(&a_file, a_size);
- let dev = attach(a_file, 0, a_size, /* direct_io */ true, /* writable */ true).unwrap();
+ let dev = attach(
+ a_file,
+ 0,
+ a_size,
+ &LoopConfigOptions { direct_io: true, writable: true, ..Default::default() },
+ )
+ .unwrap()
+ .path;
scopeguard::defer! {
detach(&dev).unwrap();
}
assert!(is_direct_io(&dev));
assert!(is_direct_io_writable(&dev));
}
+
+ #[rdroidtest]
+ fn attach_loop_device_autoclear() {
+ let a_dir = tempfile::TempDir::new().unwrap();
+ let a_file = a_dir.path().join("test");
+ let a_size = 4096u64;
+ create_empty_file(&a_file, a_size);
+ let dev =
+ attach(a_file, 0, a_size, &LoopConfigOptions { autoclear: true, ..Default::default() })
+ .unwrap();
+ drop(dev.file);
+
+ let dev_size_path =
+ Path::new("/sys/block").join(dev.path.file_name().unwrap()).join("size");
+ assert_eq!("0", fs::read_to_string(dev_size_path).unwrap().trim());
+ }
}