[libdm_rust] Enable writable loopdevice
Add option in loopdevice module to create a block device in writable
mode as well. This is required for unit-testing dm-crypt device.
Also, add test: attach_loop_device_with_dio_writable
Test: atest libdm_rust.test
Test: atest apkdmverity.test
Bug: 250880499
Change-Id: I793ca247ec3cb3258d16a6d9bb25aae31c127ede
diff --git a/libs/devicemapper/src/loopdevice.rs b/libs/devicemapper/src/loopdevice.rs
index bdbc0f6..5533e17 100644
--- a/libs/devicemapper/src/loopdevice.rs
+++ b/libs/devicemapper/src/loopdevice.rs
@@ -66,6 +66,7 @@
offset: u64,
size_limit: u64,
direct_io: bool,
+ writable: bool,
) -> Result<PathBuf> {
// 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
@@ -80,7 +81,7 @@
let begin = Instant::now();
loop {
- match try_attach(&path, offset, size_limit, direct_io) {
+ match try_attach(&path, offset, size_limit, direct_io, writable) {
Ok(loop_dev) => return Ok(loop_dev),
Err(e) => {
if begin.elapsed() > TIMEOUT {
@@ -103,6 +104,7 @@
offset: u64,
size_limit: u64,
direct_io: bool,
+ writable: bool,
) -> Result<PathBuf> {
// Get a free loop device
wait_for_path(LOOP_CONTROL)?;
@@ -116,6 +118,7 @@
// Construct the loop_info64 struct
let backing_file = OpenOptions::new()
.read(true)
+ .write(writable)
.custom_flags(if direct_io { O_DIRECT } else { 0 })
.open(&path)
.context(format!("failed to open {:?}", path.as_ref()))?;
@@ -126,7 +129,11 @@
config.block_size = 4096;
config.info.lo_offset = offset;
config.info.lo_sizelimit = size_limit;
- config.info.lo_flags = Flag::LO_FLAGS_READ_ONLY;
+
+ if !writable {
+ config.info.lo_flags = Flag::LO_FLAGS_READ_ONLY;
+ }
+
if direct_io {
config.info.lo_flags.insert(Flag::LO_FLAGS_DIRECT_IO);
}
@@ -168,13 +175,19 @@
"1" == fs::read_to_string(&dio).unwrap().trim()
}
+ // kernel exposes /sys/block/loop*/ro which gives the read-only value
+ fn is_direct_io_writable(dev: &Path) -> bool {
+ let ro = Path::new("/sys/block").join(dev.file_name().unwrap()).join("ro");
+ "0" == fs::read_to_string(&ro).unwrap().trim()
+ }
+
#[test]
fn attach_loop_device_with_dio() {
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, /*direct_io*/ true).unwrap();
+ let dev = attach(a_file, 0, a_size, /*direct_io*/ true, /*writable*/ false).unwrap();
scopeguard::defer! {
detach(&dev).unwrap();
}
@@ -187,10 +200,24 @@
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).unwrap();
+ let dev = attach(a_file, 0, a_size, /*direct_io*/ false, /*writable*/ false).unwrap();
scopeguard::defer! {
detach(&dev).unwrap();
}
assert!(!is_direct_io(&dev));
}
+
+ #[test]
+ fn attach_loop_device_with_dio_writable() {
+ 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, /*direct_io*/ true, /*writable*/ true).unwrap();
+ scopeguard::defer! {
+ detach(&dev).unwrap();
+ }
+ assert!(is_direct_io(&dev));
+ assert!(is_direct_io_writable(&dev));
+ }
}