use crate::common::single_mount;
use btrfs_uapi::features::{
CompatRoFlags, FeatureFlags, IncompatFlags, get_features,
get_supported_features, set_features,
};
#[test]
#[ignore = "requires elevated privileges"]
fn features_get() {
let (_td, mnt) = single_mount();
let flags = get_features(mnt.fd()).expect("get_features failed");
assert!(
flags.incompat.contains(IncompatFlags::NO_HOLES)
|| flags.incompat.contains(IncompatFlags::EXTENDED_IREF)
|| !flags.incompat.is_empty(),
"expected at least some incompat flags on a new filesystem, got {:?}",
flags.incompat,
);
}
#[test]
#[ignore = "requires elevated privileges"]
fn features_get_supported() {
let (_td, mnt) = single_mount();
let active = get_features(mnt.fd()).expect("get_features failed");
let supported = get_supported_features(mnt.fd())
.expect("get_supported_features failed");
assert!(
supported.incompat_supported.contains(active.incompat),
"active incompat {:?} should be subset of supported {:?}",
active.incompat,
supported.incompat_supported,
);
assert!(
supported.compat_ro_supported.contains(active.compat_ro),
"active compat_ro {:?} should be subset of supported {:?}",
active.compat_ro,
supported.compat_ro_supported,
);
}
#[test]
#[ignore = "requires elevated privileges"]
fn features_set_and_get_roundtrip() {
let (_td, mnt) = single_mount();
let supported = get_supported_features(mnt.fd())
.expect("get_supported_features failed");
let before = get_features(mnt.fd()).expect("get_features failed");
let settable = supported.compat_ro_safe_set & !before.compat_ro;
if settable.is_empty() {
let clearable = supported.compat_ro_safe_clear & before.compat_ro;
if clearable.is_empty() {
eprintln!("no toggleable compat_ro flags available, skipping");
return;
}
let flag = CompatRoFlags::from_bits_truncate(
clearable.bits() & clearable.bits().wrapping_neg(),
);
let desired = FeatureFlags {
compat_ro: before.compat_ro & !flag,
incompat: before.incompat,
};
let mask = FeatureFlags {
compat_ro: flag,
incompat: IncompatFlags::empty(),
};
set_features(mnt.fd(), &desired, &mask)
.expect("set_features (clear) failed");
let after = get_features(mnt.fd()).expect("get_features failed");
assert!(
!after.compat_ro.contains(flag),
"flag {flag:?} should have been cleared, got {:?}",
after.compat_ro,
);
} else {
let flag = CompatRoFlags::from_bits_truncate(
settable.bits() & settable.bits().wrapping_neg(),
);
let desired = FeatureFlags {
compat_ro: before.compat_ro | flag,
incompat: before.incompat,
};
let mask = FeatureFlags {
compat_ro: flag,
incompat: IncompatFlags::empty(),
};
set_features(mnt.fd(), &desired, &mask)
.expect("set_features (set) failed");
let after = get_features(mnt.fd()).expect("get_features failed");
assert!(
after.compat_ro.contains(flag),
"flag {flag:?} should have been set, got {:?}",
after.compat_ro,
);
}
}