]>
git.proxmox.com Git - proxmox-backup.git/blob - src/tools/disks/zfs.rs
1 use std
::path
::PathBuf
;
2 use std
::collections
::HashSet
;
3 use std
::os
::unix
::fs
::MetadataExt
;
5 use anyhow
::{bail, Error}
;
6 use lazy_static
::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
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());
30 /// Returns kernel IO-stats for zfs pools
31 pub fn zfs_pool_stats(pool
: &OsStr
) -> Result
<Option
<BlockDevStat
>, Error
> {
33 let mut path
= PathBuf
::from("/proc/spl/kstat/zfs");
37 let text
= match proxmox_sys
::fs
::file_read_optional_string(&path
)?
{
39 None
=> { return Ok(None); }
42 let lines
: Vec
<&str> = text
.lines().collect();
45 bail
!("unable to parse {:?} - got less than 3 lines", path
);
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)
57 let ticks
= (stat
[4] + stat
[7])/1_000_000; // convert to milisec
59 let stat
= BlockDevStat
{
60 read_sectors
: stat
[0]>>9,
61 write_sectors
: stat
[1]>>9,
70 /// Get set of devices used by zfs (or a specific zfs pool)
72 /// The set is indexed by using the unix raw device number (dev_t is u64)
74 lsblk_info
: &[LsblkInfo
],
76 ) -> Result
<HashSet
<u64>, Error
> {
78 let list
= zpool_list(pool
, true)?
;
80 let mut device_set
= HashSet
::new();
82 for device
in entry
.devices
{
83 let meta
= std
::fs
::metadata(device
)?
;
84 device_set
.insert(meta
.rdev());
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());