metaovl: Use xcp to copy image faster.
This commit is contained in:
@@ -10,6 +10,7 @@ license = "GPL-3.0"
|
|||||||
anyhow = "1"
|
anyhow = "1"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
env_logger = { version = "0.11", default-features = false }
|
env_logger = { version = "0.11", default-features = false }
|
||||||
|
hole-punch = { git = "https://github.com/tiann/hole-punch" }
|
||||||
|
|
||||||
[target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies]
|
[target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies]
|
||||||
rustix = { git = "https://github.com/Kernel-SU/rustix.git", rev = "4a53fbc7cb7a07cabe87125cc21dbc27db316259", features = ["all-apis"] }
|
rustix = { git = "https://github.com/Kernel-SU/rustix.git", rev = "4a53fbc7cb7a07cabe87125cc21dbc27db316259", features = ["all-apis"] }
|
||||||
|
|||||||
@@ -43,13 +43,12 @@ ui_print "- Architecture-specific binary installed successfully"
|
|||||||
|
|
||||||
# Create ext4 image for module content storage
|
# Create ext4 image for module content storage
|
||||||
IMG_FILE="$MODPATH/modules.img"
|
IMG_FILE="$MODPATH/modules.img"
|
||||||
MNT_DIR="$MODPATH/mnt"
|
|
||||||
IMG_SIZE_MB=2048
|
IMG_SIZE_MB=2048
|
||||||
EXISTING_IMG="/data/adb/modules/$MODID/modules.img"
|
EXISTING_IMG="/data/adb/modules/$MODID/modules.img"
|
||||||
|
|
||||||
if [ -f "$EXISTING_IMG" ]; then
|
if [ -f "$EXISTING_IMG" ]; then
|
||||||
ui_print "- Reusing modules image from previous install"
|
ui_print "- Reusing modules image from previous install"
|
||||||
cp "$EXISTING_IMG" "$IMG_FILE" || \
|
"$MODPATH/meta-overlayfs" xcp "$EXISTING_IMG" "$IMG_FILE" || \
|
||||||
abort "! Failed to copy existing modules image"
|
abort "! Failed to copy existing modules image"
|
||||||
else
|
else
|
||||||
ui_print "- Creating 2GB ext4 image for module storage"
|
ui_print "- Creating 2GB ext4 image for module storage"
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ module_requires_overlay_move() {
|
|||||||
post_install_to_image() {
|
post_install_to_image() {
|
||||||
ui_print "- Copying module content to image"
|
ui_print "- Copying module content to image"
|
||||||
|
|
||||||
set_perm_recursive $MNT_DIR 0 0 0755 0644
|
set_perm_recursive "$MNT_DIR" 0 0 0755 0644
|
||||||
|
|
||||||
MOD_IMG_DIR="$MNT_DIR/$MODID"
|
MOD_IMG_DIR="$MNT_DIR/$MODID"
|
||||||
mkdir -p "$MOD_IMG_DIR"
|
mkdir -p "$MOD_IMG_DIR"
|
||||||
@@ -58,11 +58,11 @@ post_install_to_image() {
|
|||||||
done
|
done
|
||||||
|
|
||||||
# Set permissions
|
# Set permissions
|
||||||
set_perm_recursive $MOD_IMG_DIR 0 0 0755 0644
|
set_perm_recursive "$MOD_IMG_DIR" 0 0 0755 0644
|
||||||
set_perm_recursive $MOD_IMG_DIR/system/bin 0 2000 0755 0755
|
set_perm_recursive "$MOD_IMG_DIR/system/bin" 0 2000 0755 0755
|
||||||
set_perm_recursive $MOD_IMG_DIR/system/xbin 0 2000 0755 0755
|
set_perm_recursive "$MOD_IMG_DIR/system/xbin" 0 2000 0755 0755
|
||||||
set_perm_recursive $MOD_IMG_DIR/system/system_ext/bin 0 2000 0755 0755
|
set_perm_recursive "$MOD_IMG_DIR/system/system_ext/bin" 0 2000 0755 0755
|
||||||
set_perm_recursive $MOD_IMG_DIR/system/vendor 0 2000 0755 0755 u:object_r:vendor_file:s0
|
set_perm_recursive "$MOD_IMG_DIR/system/vendor" 0 2000 0755 0755 u:object_r:vendor_file:s0
|
||||||
|
|
||||||
ui_print "- Module content copied"
|
ui_print "- Module content copied"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,14 @@ use log::info;
|
|||||||
|
|
||||||
mod defs;
|
mod defs;
|
||||||
mod mount;
|
mod mount;
|
||||||
|
mod xcp;
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
|
let args: Vec<String> = std::env::args().collect();
|
||||||
|
if matches!(args.get(1), Some(cmd) if cmd == "xcp") {
|
||||||
|
return xcp::run(&args[2..]);
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize logger
|
// Initialize logger
|
||||||
env_logger::builder()
|
env_logger::builder()
|
||||||
.filter_level(log::LevelFilter::Info)
|
.filter_level(log::LevelFilter::Info)
|
||||||
|
|||||||
90
userspace/meta-overlayfs/src/xcp.rs
Normal file
90
userspace/meta-overlayfs/src/xcp.rs
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
use anyhow::{bail, Context, Result};
|
||||||
|
use hole_punch::*;
|
||||||
|
use std::{
|
||||||
|
fs::{File, OpenOptions},
|
||||||
|
io::{Read, Seek, SeekFrom, Write},
|
||||||
|
path::Path,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Handle the `xcp` command: copy sparse file with optional hole punching.
|
||||||
|
pub fn run(args: &[String]) -> Result<()> {
|
||||||
|
let mut positional: Vec<&str> = Vec::with_capacity(2);
|
||||||
|
let mut punch_hole = false;
|
||||||
|
|
||||||
|
for arg in args {
|
||||||
|
match arg.as_str() {
|
||||||
|
"--punch-hole" => punch_hole = true,
|
||||||
|
"-h" | "--help" => {
|
||||||
|
print_usage();
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
_ => positional.push(arg),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if positional.len() < 2 {
|
||||||
|
print_usage();
|
||||||
|
bail!("xcp requires source and destination paths");
|
||||||
|
}
|
||||||
|
if positional.len() > 2 {
|
||||||
|
bail!("unexpected argument: {}", positional[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
copy_sparse_file(positional[0], positional[1], punch_hole)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_usage() {
|
||||||
|
eprintln!("Usage: meta-overlayfs xcp <src> <dst> [--punch-hole]");
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: use libxcp to improve the speed if cross's MSRV is 1.70
|
||||||
|
pub fn copy_sparse_file<P: AsRef<Path>, Q: AsRef<Path>>(
|
||||||
|
src: P,
|
||||||
|
dst: Q,
|
||||||
|
punch_hole: bool,
|
||||||
|
) -> Result<()> {
|
||||||
|
let mut src_file = File::open(src.as_ref())
|
||||||
|
.with_context(|| format!("failed to open {}", src.as_ref().display()))?;
|
||||||
|
let mut dst_file = OpenOptions::new()
|
||||||
|
.write(true)
|
||||||
|
.create(true)
|
||||||
|
.truncate(true)
|
||||||
|
.open(dst.as_ref())
|
||||||
|
.with_context(|| format!("failed to open {}", dst.as_ref().display()))?;
|
||||||
|
|
||||||
|
dst_file.set_len(src_file.metadata()?.len())?;
|
||||||
|
|
||||||
|
let segments = src_file.scan_chunks()?;
|
||||||
|
for segment in segments {
|
||||||
|
if let SegmentType::Data = segment.segment_type {
|
||||||
|
let start = segment.start;
|
||||||
|
let end = segment.end + 1;
|
||||||
|
|
||||||
|
src_file.seek(SeekFrom::Start(start))?;
|
||||||
|
dst_file.seek(SeekFrom::Start(start))?;
|
||||||
|
|
||||||
|
let mut buffer = [0; 4096];
|
||||||
|
let mut total_bytes_copied = 0;
|
||||||
|
|
||||||
|
while total_bytes_copied < end - start {
|
||||||
|
let bytes_to_read =
|
||||||
|
std::cmp::min(buffer.len() as u64, end - start - total_bytes_copied);
|
||||||
|
let bytes_read = src_file.read(&mut buffer[..bytes_to_read as usize])?;
|
||||||
|
|
||||||
|
if bytes_read == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if punch_hole && buffer[..bytes_read].iter().all(|&x| x == 0) {
|
||||||
|
dst_file.seek(SeekFrom::Current(bytes_read as i64))?;
|
||||||
|
total_bytes_copied += bytes_read as u64;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
dst_file.write_all(&buffer[..bytes_read])?;
|
||||||
|
total_bytes_copied += bytes_read as u64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user