use crate::common::{
BackingFile, LoopbackDevice, Mount, single_mount, write_test_data,
};
use btrfs_uapi::{
balance::{BalanceArgs, BalanceFlags, balance},
chunk::{chunk_list, device_chunk_allocations},
device::device_add,
filesystem::sync,
space::BlockGroupFlags,
};
use std::ffi::CString;
#[test]
#[ignore = "requires elevated privileges"]
fn chunk_list_basic() {
let (_td, mnt) = single_mount();
let initial = chunk_list(mnt.fd()).expect("chunk_list failed");
assert!(!initial.is_empty(), "fresh filesystem should have chunks");
for entry in &initial {
assert!(
entry.length > 0,
"chunk length should be non-zero: {entry:?}"
);
let has_type = entry.flags.contains(BlockGroupFlags::DATA)
|| entry.flags.contains(BlockGroupFlags::METADATA)
|| entry.flags.contains(BlockGroupFlags::SYSTEM);
assert!(has_type, "chunk should have a type flag: {entry:?}");
}
write_test_data(mnt.path(), "data.bin", 50_000_000);
sync(mnt.fd()).unwrap();
let after = chunk_list(mnt.fd()).expect("chunk_list after write failed");
let initial_data_chunks = initial
.iter()
.filter(|e| e.flags.contains(BlockGroupFlags::DATA))
.count();
let after_data_chunks = after
.iter()
.filter(|e| e.flags.contains(BlockGroupFlags::DATA))
.count();
assert!(
after_data_chunks >= initial_data_chunks,
"data chunk count should not decrease after writing: before={initial_data_chunks}, after={after_data_chunks}",
);
}
#[test]
#[ignore = "requires elevated privileges"]
fn chunk_allocations_two_devices() {
let td = tempfile::tempdir().unwrap();
let f1 = BackingFile::new(td.path(), "d1.img", 300_000_000);
f1.mkfs();
let lo1 = LoopbackDevice::new(f1);
let mnt = Mount::new(lo1, td.path());
let f2 = BackingFile::new(td.path(), "d2.img", 300_000_000);
let lo2 = LoopbackDevice::new(f2);
let dev2_cpath = CString::new(lo2.path().to_str().unwrap()).unwrap();
device_add(mnt.fd(), &dev2_cpath).expect("device_add failed");
write_test_data(mnt.path(), "data.bin", 50_000_000);
sync(mnt.fd()).unwrap();
let convert_args =
BalanceArgs::new().convert(BlockGroupFlags::RAID1.bits());
let flags =
BalanceFlags::DATA | BalanceFlags::METADATA | BalanceFlags::SYSTEM;
balance(
mnt.fd(),
flags,
Some(convert_args.clone()),
Some(convert_args.clone()),
Some(convert_args),
)
.expect("balance failed");
let allocs = device_chunk_allocations(mnt.fd())
.expect("device_chunk_allocations failed");
let dev1_bytes: u64 = allocs
.iter()
.filter(|a| a.devid == 1)
.map(|a| a.bytes)
.sum();
let dev2_bytes: u64 = allocs
.iter()
.filter(|a| a.devid == 2)
.map(|a| a.bytes)
.sum();
assert!(dev1_bytes > 0, "device 1 should have allocations");
assert!(dev2_bytes > 0, "device 2 should have allocations");
}