btrfs_cli/rescue/
zero_log.rs1use crate::{Format, Runnable, util::is_mounted};
2use anyhow::{Context, Result, bail};
3use btrfs_disk::{
4 raw,
5 superblock::{read_superblock_bytes, write_superblock_all_mirrors},
6};
7use clap::Parser;
8use std::{fs::OpenOptions, mem, path::PathBuf};
9
10#[derive(Parser, Debug)]
19pub struct RescueZeroLogCommand {
20 device: PathBuf,
22}
23
24impl Runnable for RescueZeroLogCommand {
25 fn run(&self, _format: Format, _dry_run: bool) -> Result<()> {
26 if is_mounted(&self.device) {
27 bail!("{} is currently mounted", self.device.display());
28 }
29
30 let mut file = OpenOptions::new()
31 .read(true)
32 .write(true)
33 .open(&self.device)
34 .with_context(|| {
35 format!("failed to open '{}'", self.device.display())
36 })?;
37
38 let mut buf = read_superblock_bytes(&mut file).with_context(|| {
39 format!(
40 "failed to read superblock from '{}'",
41 self.device.display()
42 )
43 })?;
44
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}