]> git.proxmox.com Git - proxmox-backup.git/blob - src/tools/disks/zfs.rs
tree-wide: fix needless borrows
[proxmox-backup.git] / src / tools / disks / zfs.rs
1 use std::path::PathBuf;
2 use std::collections::HashSet;
3 use std::os::unix::fs::MetadataExt;
4
5 use anyhow::{bail, Error};
6 use lazy_static::lazy_static;
7
8 use super::*;
9
10 lazy_static!{
11 static ref ZFS_UUIDS: HashSet<&'static str> = {
12 let mut set = HashSet::new();
13 set.insert("6a898cc3-1dd2-11b2-99a6-080020736631"); // apple
14 set.insert("516e7cba-6ecf-11d6-8ff8-00022d09712b"); // bsd
15 set
16 };
17 }
18
19 /// returns pool from dataset path of the form 'rpool/ROOT/pbs-1'
20 pub fn get_pool_from_dataset(dataset: &OsStr) -> Option<&OsStr> {
21 if let Some(dataset) = dataset.to_str() {
22 if let Some(idx) = dataset.find('/') {
23 return Some(dataset[0..idx].as_ref());
24 }
25 }
26
27 None
28 }
29
30 /// Returns kernel IO-stats for zfs pools
31 pub fn zfs_pool_stats(pool: &OsStr) -> Result<Option<BlockDevStat>, Error> {
32
33 let mut path = PathBuf::from("/proc/spl/kstat/zfs");
34 path.push(pool);
35 path.push("io");
36
37 let text = match proxmox_sys::fs::file_read_optional_string(&path)? {
38 Some(text) => text,
39 None => { return Ok(None); }
40 };
41
42 let lines: Vec<&str> = text.lines().collect();
43
44 if lines.len() < 3 {
45 bail!("unable to parse {:?} - got less than 3 lines", path);
46 }
47
48 // https://github.com/openzfs/zfs/blob/master/lib/libspl/include/sys/kstat.h#L578
49 // nread nwritten reads writes wtime wlentime wupdate rtime rlentime rupdate wcnt rcnt
50 // Note: w -> wait (wtime -> wait time)
51 // Note: r -> run (rtime -> run time)
52 // All times are nanoseconds
53 let stat: Vec<u64> = lines[2].split_ascii_whitespace().map(|s| {
54 u64::from_str_radix(s, 10).unwrap_or(0)
55 }).collect();
56
57 let ticks = (stat[4] + stat[7])/1_000_000; // convert to milisec
58
59 let stat = BlockDevStat {
60 read_sectors: stat[0]>>9,
61 write_sectors: stat[1]>>9,
62 read_ios: stat[2],
63 write_ios: stat[3],
64 io_ticks: ticks,
65 };
66
67 Ok(Some(stat))
68 }
69
70 /// Get set of devices used by zfs (or a specific zfs pool)
71 ///
72 /// The set is indexed by using the unix raw device number (dev_t is u64)
73 pub fn zfs_devices(
74 lsblk_info: &[LsblkInfo],
75 pool: Option<String>,
76 ) -> Result<HashSet<u64>, Error> {
77
78 let list = zpool_list(pool, true)?;
79
80 let mut device_set = HashSet::new();
81 for entry in list {
82 for device in entry.devices {
83 let meta = std::fs::metadata(device)?;
84 device_set.insert(meta.rdev());
85 }
86 }
87
88 for info in lsblk_info.iter() {
89 if let Some(partition_type) = &info.partition_type {
90 if ZFS_UUIDS.contains(partition_type.as_str()) {
91 let meta = std::fs::metadata(&info.path)?;
92 device_set.insert(meta.rdev());
93 }
94 }
95 }
96
97 Ok(device_set)
98 }
99