use std::path::Path;
use nix::mount::{mount, MsFlags};
use crate::error::BlktraceError;
const DEBUGFS: &str = "/sys/kernel/debug";
pub(crate) fn ensure_debugfs() -> Result<(), BlktraceError> {
let debugfs = Path::new(DEBUGFS);
if !debugfs.exists() {
return Err(BlktraceError::DebugfsUnsupported);
}
let mounted = mnt::MountIter::new_from_proc()
.map(|mut iter| iter.any(|item| item.map(|item| item.file == debugfs).unwrap_or(false)))
.unwrap_or(false);
if mounted {
return Ok(());
}
tracing::debug!("debugfs not mounted, mounting it now");
std::fs::create_dir_all(debugfs)?;
mount(
Some("debugfs"),
debugfs,
Some("debugfs"),
MsFlags::empty(),
Option::<&str>::None,
)
.map_err(BlktraceError::MountDebugfs)?;
Ok(())
}
pub fn drop_page_cache() -> std::io::Result<()> {
use std::io::Write;
let mut file = std::fs::OpenOptions::new()
.write(true)
.open("/proc/sys/vm/drop_caches")?;
file.write_all(b"1")
}
#[cfg(test)]
mod tests {
use super::*;
fn is_root() -> bool {
use std::os::unix::fs::MetadataExt;
std::fs::metadata("/proc/self")
.map(|meta| meta.uid() == 0)
.unwrap_or(false)
}
#[test]
fn ensure_debugfs_succeeds_for_root() {
if !is_root() {
return;
}
ensure_debugfs().expect("debugfs is available on a root test machine");
}
#[test]
fn drop_page_cache_writes_when_root() {
if !is_root() {
return;
}
drop_page_cache().expect("root can write to /proc/sys/vm/drop_caches");
}
}