1use crate::raw::{
11 BTRFS_SCRUB_READONLY, btrfs_ioc_scrub, btrfs_ioc_scrub_cancel,
12 btrfs_ioc_scrub_progress, btrfs_ioctl_scrub_args,
13};
14use std::{
15 mem,
16 os::{fd::AsRawFd, unix::io::BorrowedFd},
17};
18
19#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
22pub struct ScrubProgress {
23 pub data_extents_scrubbed: u64,
25 pub tree_extents_scrubbed: u64,
27 pub data_bytes_scrubbed: u64,
29 pub tree_bytes_scrubbed: u64,
31 pub read_errors: u64,
33 pub csum_errors: u64,
35 pub verify_errors: u64,
37 pub no_csum: u64,
39 pub csum_discards: u64,
41 pub super_errors: u64,
43 pub malloc_errors: u64,
45 pub uncorrectable_errors: u64,
47 pub corrected_errors: u64,
49 pub last_physical: u64,
51 pub unverified_errors: u64,
53}
54
55impl ScrubProgress {
56 #[must_use]
58 pub fn error_count(&self) -> u64 {
59 self.read_errors
60 + self.super_errors
61 + self.verify_errors
62 + self.csum_errors
63 }
64
65 #[must_use]
67 pub fn bytes_scrubbed(&self) -> u64 {
68 self.data_bytes_scrubbed + self.tree_bytes_scrubbed
69 }
70
71 #[must_use]
73 pub fn is_clean(&self) -> bool {
74 self.error_count() == 0
75 && self.corrected_errors == 0
76 && self.uncorrectable_errors == 0
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83
84 #[test]
85 fn scrub_progress_default_is_clean() {
86 let p = ScrubProgress::default();
87 assert!(p.is_clean());
88 assert_eq!(p.error_count(), 0);
89 assert_eq!(p.bytes_scrubbed(), 0);
90 }
91
92 #[test]
93 fn scrub_progress_error_count() {
94 let p = ScrubProgress {
95 read_errors: 1,
96 super_errors: 2,
97 verify_errors: 3,
98 csum_errors: 4,
99 ..ScrubProgress::default()
100 };
101 assert_eq!(p.error_count(), 10);
102 assert!(!p.is_clean());
103 }
104
105 #[test]
106 fn scrub_progress_bytes_scrubbed() {
107 let p = ScrubProgress {
108 data_bytes_scrubbed: 1000,
109 tree_bytes_scrubbed: 500,
110 ..ScrubProgress::default()
111 };
112 assert_eq!(p.bytes_scrubbed(), 1500);
113 }
114
115 #[test]
116 fn scrub_progress_corrected_errors_not_clean() {
117 let p = ScrubProgress {
118 corrected_errors: 1,
119 ..ScrubProgress::default()
120 };
121 assert!(!p.is_clean());
122 assert_eq!(p.error_count(), 0); }
124
125 #[test]
126 fn scrub_progress_uncorrectable_errors_not_clean() {
127 let p = ScrubProgress {
128 uncorrectable_errors: 1,
129 ..ScrubProgress::default()
130 };
131 assert!(!p.is_clean());
132 }
133}
134
135fn from_raw(raw: &btrfs_ioctl_scrub_args) -> ScrubProgress {
136 let p = &raw.progress;
137 ScrubProgress {
138 data_extents_scrubbed: p.data_extents_scrubbed,
139 tree_extents_scrubbed: p.tree_extents_scrubbed,
140 data_bytes_scrubbed: p.data_bytes_scrubbed,
141 tree_bytes_scrubbed: p.tree_bytes_scrubbed,
142 read_errors: p.read_errors,
143 csum_errors: p.csum_errors,
144 verify_errors: p.verify_errors,
145 no_csum: p.no_csum,
146 csum_discards: p.csum_discards,
147 super_errors: p.super_errors,
148 malloc_errors: p.malloc_errors,
149 uncorrectable_errors: p.uncorrectable_errors,
150 corrected_errors: p.corrected_errors,
151 last_physical: p.last_physical,
152 unverified_errors: p.unverified_errors,
153 }
154}
155
156pub fn scrub_start(
164 fd: BorrowedFd,
165 devid: u64,
166 readonly: bool,
167) -> nix::Result<ScrubProgress> {
168 let mut args: btrfs_ioctl_scrub_args = unsafe { mem::zeroed() };
169 args.devid = devid;
170 args.start = 0;
171 args.end = u64::MAX;
172 if readonly {
173 args.flags = u64::from(BTRFS_SCRUB_READONLY);
174 }
175 unsafe { btrfs_ioc_scrub(fd.as_raw_fd(), &raw mut args) }?;
176 Ok(from_raw(&args))
177}
178
179pub fn scrub_cancel(fd: BorrowedFd) -> nix::Result<()> {
181 unsafe { btrfs_ioc_scrub_cancel(fd.as_raw_fd()) }?;
182 Ok(())
183}
184
185pub fn scrub_progress(
190 fd: BorrowedFd,
191 devid: u64,
192) -> nix::Result<Option<ScrubProgress>> {
193 let mut args: btrfs_ioctl_scrub_args = unsafe { mem::zeroed() };
194 args.devid = devid;
195 args.start = 0;
196 args.end = u64::MAX;
197
198 match unsafe { btrfs_ioc_scrub_progress(fd.as_raw_fd(), &raw mut args) } {
199 Err(nix::errno::Errno::ENOTCONN) => Ok(None),
200 Err(e) => Err(e),
201 Ok(_) => Ok(Some(from_raw(&args))),
202 }
203}