use crate::{
bindings::{
btrfs_ioctl_dev_info_args, btrfs_ioctl_get_dev_stats, btrfs_ioctl_vol_args,
btrfs_ioctl_vol_args_v2, vol_args_v2_volume, BTRFS_DEVICE_SPEC_BY_ID,
BTRFS_DEV_STAT_CORRUPTION_ERRS, BTRFS_DEV_STAT_FLUSH_ERRS, BTRFS_DEV_STAT_GENERATION_ERRS,
BTRFS_DEV_STAT_READ_ERRS, BTRFS_DEV_STAT_VALUES_MAX, BTRFS_DEV_STAT_WRITE_ERRS,
BTRFS_IOC_ADD_DEV, BTRFS_IOC_DEV_INFO, BTRFS_IOC_GET_DEV_STATS, BTRFS_IOC_RM_DEV,
BTRFS_IOC_RM_DEV_V2,
},
util::{btrfs_ioctl, vol_args_name_from_bytes, vol_args_v2_name_from_bytes, OptionFd},
};
use std::{fs::File, io, os::unix::io::AsRawFd, path::Path};
mod dev_info;
pub use dev_info::{info, info_iter, DevInfo, InfoIter};
mod dev_item;
pub use dev_item::{item_iter, DevItem, ItemIter};
pub struct DevStats(btrfs_ioctl_get_dev_stats);
impl DevStats {
pub fn write_errors(&self) -> u64 {
self.0.values[BTRFS_DEV_STAT_WRITE_ERRS as usize]
}
pub fn read_errors(&self) -> u64 {
self.0.values[BTRFS_DEV_STAT_READ_ERRS as usize]
}
pub fn flush_errors(&self) -> u64 {
self.0.values[BTRFS_DEV_STAT_FLUSH_ERRS as usize]
}
pub fn corruptions_errors(&self) -> u64 {
self.0.values[BTRFS_DEV_STAT_CORRUPTION_ERRS as usize]
}
pub fn generation_errors(&self) -> u64 {
self.0.values[BTRFS_DEV_STAT_GENERATION_ERRS as usize]
}
pub fn has_errors(&self) -> bool {
self.0.values.iter().any(|&f| f != 0)
}
}
pub fn get_stats<P: AsRef<Path>>(devid: u64, fs: P) -> io::Result<DevStats> {
let fd = File::open(fs)?;
fd::get_stats(devid, fd.as_raw_fd())
}
pub fn add<P: AsRef<Path>>(device: &str, fs: P) -> io::Result<()> {
let fd = File::open(fs)?;
fd::add(device, fd.as_raw_fd())
}
pub fn rm<P: AsRef<Path>>(device: &str, fs: P) -> io::Result<()> {
let fd = File::open(fs)?;
fd::rm(device, fd.as_raw_fd())
}
pub fn rm_by_id<P: AsRef<Path>>(devid: u64, fs: P) -> io::Result<()> {
let fd = File::open(fs)?;
fd::rm_by_id(devid, fd.as_raw_fd())
}
pub mod fd {
use super::*;
use std::os::unix::io::RawFd;
pub use dev_info::fd::{info, info_iter};
pub use dev_item::fd::item_iter;
pub fn get_stats(devid: u64, fd: RawFd) -> io::Result<DevStats> {
let mut stats = btrfs_ioctl_get_dev_stats {
devid,
nr_items: BTRFS_DEV_STAT_VALUES_MAX as u64,
..Default::default()
};
btrfs_ioctl(fd, BTRFS_IOC_GET_DEV_STATS, &mut stats)?;
Ok(DevStats(stats))
}
pub fn add(device: &str, fd: RawFd) -> io::Result<()> {
let mut args = btrfs_ioctl_vol_args {
name: vol_args_name_from_bytes(device.as_bytes()),
..Default::default()
};
btrfs_ioctl(fd, BTRFS_IOC_ADD_DEV, &mut args)
}
pub fn rm(device: &str, fd: RawFd) -> io::Result<()> {
fn rm_dev_v1(fd: i32, device: &str) -> io::Result<()> {
let mut vol_args = btrfs_ioctl_vol_args {
name: vol_args_name_from_bytes(device.as_bytes()),
..Default::default()
};
btrfs_ioctl(fd, BTRFS_IOC_RM_DEV, &mut vol_args)
}
let mut vol_args = btrfs_ioctl_vol_args_v2 {
inner2: vol_args_v2_volume {
name: vol_args_v2_name_from_bytes(device.as_bytes()),
},
..Default::default()
};
match btrfs_ioctl(fd, BTRFS_IOC_RM_DEV_V2, &mut vol_args) {
Err(e) => match e.raw_os_error() {
Some(libc::ENOTTY) | Some(libc::ENOTSUP) => rm_dev_v1(fd, device),
_ => Err(e),
},
_ => Ok(()),
}
}
pub fn rm_by_id(devid: u64, fd: RawFd) -> io::Result<()> {
let mut args = btrfs_ioctl_vol_args_v2 {
flags: BTRFS_DEVICE_SPEC_BY_ID,
inner2: vol_args_v2_volume { devid },
..Default::default()
};
btrfs_ioctl(fd, BTRFS_IOC_RM_DEV_V2, &mut args)
}
}