btrfs_cli/rescue/
zero_log.rs1use crate::{Format, Runnable, util::is_mounted};
2use anyhow::{Context, Result, bail};
3use btrfs_disk::superblock::{
4 read_superblock_bytes, write_superblock_all_mirrors,
5};
6use clap::Parser;
7use std::{fs::OpenOptions, mem, path::PathBuf};
8
9#[derive(Parser, Debug)]
18pub struct RescueZeroLogCommand {
19 device: PathBuf,
21}
22
23impl Runnable for RescueZeroLogCommand {
24 fn run(&self, _format: Format, _dry_run: bool) -> Result<()> {
25 if is_mounted(&self.device) {
26 bail!("{} is currently mounted", self.device.display());
27 }
28
29 let mut file = OpenOptions::new()
30 .read(true)
31 .write(true)
32 .open(&self.device)
33 .with_context(|| {
34 format!("failed to open '{}'", self.device.display())
35 })?;
36
37 let mut buf = read_superblock_bytes(&mut file).with_context(|| {
38 format!(
39 "failed to read superblock from '{}'",
40 self.device.display()
41 )
42 })?;
43
44 use btrfs_disk::raw;
45 let log_root_off = mem::offset_of!(raw::btrfs_super_block, log_root);
46 let log_root_level_off =
47 mem::offset_of!(raw::btrfs_super_block, log_root_level);
48
49 let log_root = u64::from_le_bytes(
50 buf[log_root_off..log_root_off + 8].try_into().unwrap(),
51 );
52 let log_root_level = buf[log_root_level_off];
53
54 println!(
55 "Clearing log on {}, previous log_root {log_root}, level {log_root_level}",
56 self.device.display()
57 );
58
59 buf[log_root_off..log_root_off + 8].fill(0);
60 buf[log_root_level_off] = 0;
61
62 write_superblock_all_mirrors(&mut file, &buf).with_context(|| {
63 format!("failed to write superblock to '{}'", self.device.display())
64 })?;
65
66 Ok(())
67 }
68}