Skip to content

Commit

Permalink
Use zfs compression (and 100G quota) on U.2 debug volume (oxidecomput…
Browse files Browse the repository at this point in the history
…er#3700)

This also makes ensure_filesystem (re-)apply any explicit quotas to
existing filesystems that were created with different ones.
  • Loading branch information
lifning authored Jul 18, 2023
1 parent d92d0f5 commit 1604e18
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 8 deletions.
43 changes: 40 additions & 3 deletions illumos-utils/src/zfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,12 @@ pub struct EncryptionDetails {
pub epoch: u64,
}

#[derive(Debug, Default)]
pub struct SizeDetails {
pub quota: Option<usize>,
pub compression: Option<&'static str>,
}

#[cfg_attr(any(test, feature = "testing"), mockall::automock, allow(dead_code))]
impl Zfs {
/// Lists all datasets within a pool or existing dataset.
Expand Down Expand Up @@ -192,10 +198,16 @@ impl Zfs {
zoned: bool,
do_format: bool,
encryption_details: Option<EncryptionDetails>,
quota: Option<usize>,
size_details: Option<SizeDetails>,
) -> Result<(), EnsureFilesystemError> {
let (exists, mounted) = Self::dataset_exists(name, &mountpoint)?;
if exists {
if let Some(SizeDetails { quota, compression }) = size_details {
// apply quota and compression mode (in case they've changed across
// sled-agent versions since creation)
Self::apply_properties(name, &mountpoint, quota, compression)?;
}

if encryption_details.is_none() {
// If the dataset exists, we're done. Unencrypted datasets are
// automatically mounted.
Expand Down Expand Up @@ -238,21 +250,46 @@ impl Zfs {
&epoch,
]);
}

cmd.args(&["-o", &format!("mountpoint={}", mountpoint), name]);
execute(cmd).map_err(|err| EnsureFilesystemError {
name: name.to_string(),
mountpoint: mountpoint.clone(),
err: err.into(),
})?;

// Apply any quota.
if let Some(SizeDetails { quota, compression }) = size_details {
// Apply any quota and compression mode.
Self::apply_properties(name, &mountpoint, quota, compression)?;
}

Ok(())
}

fn apply_properties(
name: &str,
mountpoint: &Mountpoint,
quota: Option<usize>,
compression: Option<&'static str>,
) -> Result<(), EnsureFilesystemError> {
if let Some(quota) = quota {
if let Err(err) =
Self::set_value(name, "quota", &format!("{quota}"))
{
return Err(EnsureFilesystemError {
name: name.to_string(),
mountpoint,
mountpoint: mountpoint.clone(),
// Take the execution error from the SetValueError
err: err.err.into(),
});
}
}
if let Some(compression) = compression {
if let Err(err) = Self::set_value(name, "compression", compression)
{
return Err(EnsureFilesystemError {
name: name.to_string(),
mountpoint: mountpoint.clone(),
// Take the execution error from the SetValueError
err: err.err.into(),
});
Expand Down
4 changes: 2 additions & 2 deletions sled-agent/src/storage_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -368,14 +368,14 @@ impl StorageWorker {
let fs_name = &dataset_name.full();
let do_format = true;
let encryption_details = None;
let quota = None;
let size_details = None;
Zfs::ensure_filesystem(
&dataset_name.full(),
Mountpoint::Path(Utf8PathBuf::from("/data")),
zoned,
do_format,
encryption_details,
quota,
size_details,
)?;
// Ensure the dataset has a usable UUID.
if let Ok(id_str) = Zfs::get_oxide_value(&fs_name, "uuid") {
Expand Down
24 changes: 21 additions & 3 deletions sled-hardware/src/disk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use illumos_utils::zfs::DestroyDatasetErrorVariant;
use illumos_utils::zfs::EncryptionDetails;
use illumos_utils::zfs::Keypath;
use illumos_utils::zfs::Mountpoint;
use illumos_utils::zfs::SizeDetails;
use illumos_utils::zfs::Zfs;
use illumos_utils::zpool::Zpool;
use illumos_utils::zpool::ZpoolKind;
Expand Down Expand Up @@ -225,11 +226,13 @@ struct ExpectedDataset {
quota: Option<usize>,
// Identifies if the dataset should be deleted on boot
wipe: bool,
// Optional compression mode
compression: Option<&'static str>,
}

impl ExpectedDataset {
const fn new(name: &'static str) -> Self {
ExpectedDataset { name, quota: None, wipe: false }
ExpectedDataset { name, quota: None, wipe: false, compression: None }
}

const fn quota(mut self, quota: usize) -> Self {
Expand All @@ -241,6 +244,11 @@ impl ExpectedDataset {
self.wipe = true;
self
}

const fn compression(mut self, compression: &'static str) -> Self {
self.compression = Some(compression);
self
}
}

pub const INSTALL_DATASET: &'static str = "install";
Expand All @@ -251,6 +259,10 @@ pub const DEBUG_DATASET: &'static str = "debug";
// TODO-correctness: This value of 100GiB is a pretty wild guess, and should be
// tuned as needed.
pub const DEBUG_DATASET_QUOTA: usize = 100 * (1 << 30);
// ditto.
pub const DUMP_DATASET_QUOTA: usize = 100 * (1 << 30);
// passed to zfs create -o compression=
pub const DUMP_DATASET_COMPRESSION: &'static str = "gzip-9";

// U.2 datasets live under the encrypted dataset and inherit encryption
pub const ZONE_DATASET: &'static str = "crypt/zone";
Expand All @@ -264,7 +276,9 @@ static U2_EXPECTED_DATASETS: [ExpectedDataset; U2_EXPECTED_DATASET_COUNT] = [
// Stores filesystems for zones
ExpectedDataset::new(ZONE_DATASET).wipe(),
// For storing full kernel RAM dumps
ExpectedDataset::new(DUMP_DATASET),
ExpectedDataset::new(DUMP_DATASET)
.quota(DUMP_DATASET_QUOTA)
.compression(DUMP_DATASET_COMPRESSION),
];

const M2_EXPECTED_DATASET_COUNT: usize = 5;
Expand Down Expand Up @@ -562,13 +576,17 @@ impl Disk {
}

let encryption_details = None;
let size_details = Some(SizeDetails {
quota: dataset.quota,
compression: dataset.compression,
});
Zfs::ensure_filesystem(
name,
Mountpoint::Path(mountpoint),
zoned,
do_format,
encryption_details,
dataset.quota,
size_details,
)?;

if dataset.wipe {
Expand Down

0 comments on commit 1604e18

Please sign in to comment.