#![forbid(unsafe_code)]
use std::path::PathBuf;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::Duration;
use crate::fuse::mount::{MountParams, mount as do_mount};
use crate::store::{Store, StoreConfig};
#[derive(Debug, Clone, clap::Args)]
pub struct MountArgs {
#[arg(value_name = "STORE")]
pub store: PathBuf,
#[arg(value_name = "MOUNTPOINT")]
pub mountpoint: PathBuf,
#[arg(long)]
pub read_only: bool,
#[arg(long)]
pub allow_other: bool,
#[arg(long, default_value_t = 1)]
pub threads: usize,
#[arg(long, default_value = "entropyfs")]
pub fs_name: String,
#[arg(long)]
pub no_background_optimize: bool,
#[arg(long, value_name = "PATH")]
pub stats_file: Option<PathBuf>,
#[arg(long, value_name = "MODE", default_value = "full")]
pub foreground: String,
#[arg(long, value_name = "BACKEND", default_value = "sync")]
pub io_backend: String,
#[arg(long, default_value_t = 256)]
pub io_uring_entries: u32,
#[arg(long, value_name = "N")]
pub worker_pool: Option<usize>,
#[arg(long)]
pub no_worker_pool: bool,
}
pub fn run(args: &MountArgs) -> Result<(), String> {
let config = StoreConfig {
foreground: match args.foreground.as_str() {
"full" => crate::optimizer::foreground::ForegroundPolicy::full(),
"cheap" => crate::optimizer::foreground::ForegroundPolicy::cheap(),
"focused" => crate::optimizer::foreground::ForegroundPolicy::focused(),
"pressure" => crate::optimizer::foreground::ForegroundPolicy {
pressure_enter: 0.80,
pressure_leave: 0.60,
pressure_defer_configurational: true,
pressure_max_deferred_bytes: 1024 * 1024 * 1024,
..crate::optimizer::foreground::ForegroundPolicy::focused()
},
"raw" => crate::optimizer::foreground::ForegroundPolicy::raw_only(),
other => {
return Err(format!(
"unknown --foreground mode {other:?} (expected full | cheap | focused | pressure | raw)"
));
}
},
io_backend: crate::store::io::IoBackendKind::parse(&args.io_backend)?,
io_uring_entries: args.io_uring_entries,
..StoreConfig::default()
};
let store =
Store::open(&args.store, &config).map_err(|e| crate::cli::errors::open(&args.store, &e))?;
let pool_threads = if args.no_worker_pool {
None
} else {
Some(args.worker_pool.unwrap_or_else(|| {
std::thread::available_parallelism()
.map(|p| p.get())
.unwrap_or(4)
}))
};
let params = MountParams {
store_dir: args.store.clone(),
mountpoint: args.mountpoint.clone(),
read_only: args.read_only,
allow_other: args.allow_other,
threads: args.threads,
fs_name: args.fs_name.clone(),
background_optimize: !args.no_background_optimize,
stats_file: args.stats_file.clone(),
worker_pool_threads: pool_threads,
};
let session = do_mount(¶ms, store)
.map_err(|e| crate::cli::errors::fuse_mount(&args.mountpoint, &e.to_string()))?;
println!(
"entropyfs mounted: {} -> {} (pid {})",
params.store_dir.display(),
params.mountpoint.display(),
std::process::id()
);
let stop = Arc::new(AtomicBool::new(false));
let stop_handler = Arc::clone(&stop);
ctrlc::set_handler(move || {
stop_handler.store(true, Ordering::SeqCst);
})
.map_err(|e| format!("signal handler: {e}"))?;
while !session.guard.is_finished() && !stop.load(Ordering::SeqCst) {
std::thread::sleep(Duration::from_millis(100));
}
session
.umount_and_join()
.map_err(|e| format!("unmount/join: {e}"))?;
crate::store::workers::POOL.disable();
Ok(())
}