diff --git a/Cargo.lock b/Cargo.lock index e76aed1376c..f49e0a1e914 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -759,7 +759,7 @@ dependencies = [ "bitflags 2.9.4", "cexpr", "clang-sys", - "itertools 0.10.5", + "itertools 0.12.1", "lazy_static", "lazycell", "log", @@ -782,7 +782,7 @@ dependencies = [ "bitflags 2.9.4", "cexpr", "clang-sys", - "itertools 0.10.5", + "itertools 0.13.0", "log", "prettyplease", "proc-macro2", @@ -1745,7 +1745,7 @@ version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -2122,7 +2122,7 @@ dependencies = [ "futures-core", "mio", "parking_lot 0.12.3", - "rustix 1.0.7", + "rustix 1.1.2", "signal-hook", "signal-hook-mio", "winapi", @@ -5165,6 +5165,7 @@ dependencies = [ "oxlog", "oxnet", "regress", + "rustix 1.1.2", "schemars 0.8.22", "serde", "serde_json", @@ -6096,9 +6097,9 @@ checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "linux-raw-sys" -version = "0.9.4" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "litemap" @@ -9063,6 +9064,8 @@ dependencies = [ "ipnet", "ipnetwork", "itertools 0.10.5", + "itertools 0.12.1", + "itertools 0.13.0", "lalrpop-util", "lazy_static", "libc", @@ -9105,7 +9108,7 @@ dependencies = [ "rsa", "rustc-hash 2.1.1", "rustix 0.38.37", - "rustix 1.0.7", + "rustix 1.1.2", "rustls 0.23.19", "rustls-webpki 0.102.8", "schemars 0.8.22", @@ -12030,15 +12033,15 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.7" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ "bitflags 2.9.4", "errno", "libc", - "linux-raw-sys 0.9.4", - "windows-sys 0.59.0", + "linux-raw-sys 0.11.0", + "windows-sys 0.61.1", ] [[package]] @@ -13538,7 +13541,7 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03c3c6b7927ffe7ecaa769ee0e3994da3b8cafc8f444578982c83ecb161af917" dependencies = [ - "heck 0.4.1", + "heck 0.5.0", "proc-macro2", "quote", "syn 2.0.111", @@ -14182,7 +14185,7 @@ dependencies = [ "fastrand", "getrandom 0.3.4", "once_cell", - "rustix 1.0.7", + "rustix 1.1.2", "windows-sys 0.59.0", ] diff --git a/Cargo.toml b/Cargo.toml index 72dc0a7c2ab..ff125f9dc33 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -713,6 +713,7 @@ rustfmt-wrapper = "0.2" rustls = "0.22.2" rustls-pemfile = "2.2.0" rustyline = "14.0.0" +rustix = "1.1.2" samael = { version = "0.0.19", features = ["xmlsec"] } schemars = "0.8.22" scopeguard = "1.2.0" diff --git a/illumos-utils/Cargo.toml b/illumos-utils/Cargo.toml index 165aa2db031..2c1908d761a 100644 --- a/illumos-utils/Cargo.toml +++ b/illumos-utils/Cargo.toml @@ -45,6 +45,7 @@ uuid.workspace = true whoami.workspace = true zone.workspace = true tofino.workspace = true +rustix.workspace = true omicron-workspace-hack.workspace = true diff --git a/illumos-utils/src/zfs.rs b/illumos-utils/src/zfs.rs index de7519d8349..dd17f4d9bfa 100644 --- a/illumos-utils/src/zfs.rs +++ b/illumos-utils/src/zfs.rs @@ -16,6 +16,7 @@ use omicron_common::disk::CompressionAlgorithm; use omicron_common::disk::DiskIdentity; use omicron_common::disk::SharedDatasetConfig; use omicron_uuid_kinds::DatasetUuid; +use rustix::fd::AsRawFd; use std::collections::BTreeMap; use std::fmt; @@ -233,6 +234,12 @@ pub enum EnsureDatasetVolumeErrorInner { #[error("expected {value_name} to be {expected}, but saw {actual}")] ValueMismatch { value_name: String, expected: u64, actual: u64 }, + + #[error(transparent)] + RustixErrno(#[from] rustix::io::Errno), + + #[error("created but not ready yet: {reason}")] + NotReady { reason: String }, } /// Error returned by [`Zfs::ensure_dataset_volume`]. @@ -245,6 +252,10 @@ pub struct EnsureDatasetVolumeError { } impl EnsureDatasetVolumeError { + pub fn is_not_ready(&self) -> bool { + matches!(&self.err, EnsureDatasetVolumeErrorInner::NotReady { .. }) + } + pub fn execution(name: String, err: crate::ExecutionError) -> Self { EnsureDatasetVolumeError { name, @@ -288,6 +299,98 @@ impl EnsureDatasetVolumeError { }, } } + + pub fn from_raw_zvol_open(name: String, e: rustix::io::Errno) -> Self { + EnsureDatasetVolumeError { + name, + err: EnsureDatasetVolumeErrorInner::RustixErrno(e), + } + } + + pub fn from_raw_zvol_read(name: String, e: rustix::io::Errno) -> Self { + if e == rustix::io::Errno::INPROGRESS { + EnsureDatasetVolumeError { + name, + err: EnsureDatasetVolumeErrorInner::NotReady { + reason: String::from("raw volume not done initializing"), + }, + } + } else { + EnsureDatasetVolumeError { + name, + err: EnsureDatasetVolumeErrorInner::RustixErrno(e), + } + } + } +} + +#[derive(thiserror::Error, Debug)] +pub enum DeleteDatasetVolumeErrorInner { + #[error(transparent)] + Execution(#[from] crate::ExecutionError), + + #[error(transparent)] + RustixErrno(#[from] rustix::io::Errno), + + #[error("created but not ready yet: {reason}")] + NotReady { reason: String }, + + #[error("cannot cancel raw volume initialization, ioctl returned {err}")] + CancellingInitialization { err: i32 }, +} + +/// Error returned by [`Zfs::delete_dataset_volume`]. +#[derive(thiserror::Error, Debug)] +#[error("Failed to delete volume '{name}': {err}")] +pub struct DeleteDatasetVolumeError { + name: String, + #[source] + err: DeleteDatasetVolumeErrorInner, +} + +impl DeleteDatasetVolumeError { + pub fn is_not_ready(&self) -> bool { + matches!(&self.err, DeleteDatasetVolumeErrorInner::NotReady { .. }) + } + + pub fn execution(name: String, err: crate::ExecutionError) -> Self { + DeleteDatasetVolumeError { + name, + err: DeleteDatasetVolumeErrorInner::Execution(err), + } + } + + pub fn from_raw_zvol_open(name: String, e: rustix::io::Errno) -> Self { + DeleteDatasetVolumeError { + name, + err: DeleteDatasetVolumeErrorInner::RustixErrno(e), + } + } + + pub fn from_raw_zvol_read(name: String, e: rustix::io::Errno) -> Self { + if e == rustix::io::Errno::INPROGRESS { + DeleteDatasetVolumeError { + name, + err: DeleteDatasetVolumeErrorInner::NotReady { + reason: String::from("raw volume not done initializing"), + }, + } + } else { + DeleteDatasetVolumeError { + name, + err: DeleteDatasetVolumeErrorInner::RustixErrno(e), + } + } + } + + pub fn cancelling_initialization(name: String, err: i32) -> Self { + DeleteDatasetVolumeError { + name, + err: DeleteDatasetVolumeErrorInner::CancellingInitialization { + err, + }, + } + } } /// Wraps commands for interacting with ZFS. @@ -342,9 +445,20 @@ impl Keypath { } #[derive(Debug)] -pub struct EncryptionDetails { - pub keypath: Keypath, - pub epoch: u64, +pub enum EncryptionDetails { + /// Inherit the parent's encryption settings + Inherit, + + /// Explicitly set encryption to off + Off, + + /// Use a file based `keylocation` and configure `aes-256-gcm` + Aes256Gcm { + keypath: Keypath, + + /// Used to set the `oxide:epoch` option for the dataset. + epoch: u64, + }, } #[derive(Debug, Default)] @@ -623,7 +737,7 @@ pub struct DatasetEnsureArgs<'a> { /// root are implicitly encrypted. For existing filesystems, ensures that /// they are mounted (and that keys are loaded), but does not verify the /// input details. - pub encryption_details: Option, + pub encryption_details: EncryptionDetails, /// Optional properties that can be set for the dataset regarding /// space usage. @@ -899,6 +1013,29 @@ impl DatasetMountInfo { } } +/// Arguments to [Zfs::ensure_dataset_volume] +pub struct DatasetVolumeEnsureArgs<'a> { + /// The full path of the volume + pub name: &'a str, + + pub size: ByteCount, + + /// Create a raw zvol instead of a regular one + pub raw: bool, + + /// Optionally set the volblocksize + pub volblocksize: Option, +} + +/// Arguments to [Zfs::delete_dataset_volume] +pub struct DatasetVolumeDeleteArgs<'a> { + /// The full path of the volume + pub name: &'a str, + + /// Additional actions are required when deleting a raw zvol. + pub raw: bool, +} + impl Zfs { /// Lists all datasets within a pool or existing dataset. /// @@ -1122,19 +1259,27 @@ impl Zfs { if zoned { cmd.args(&["-o", "zoned=on"]); } - if let Some(details) = encryption_details { - let keyloc = format!("keylocation=file://{}", details.keypath); - let epoch = format!("oxide:epoch={}", details.epoch); - cmd.args(&[ - "-o", - "encryption=aes-256-gcm", - "-o", - "keyformat=raw", - "-o", - &keyloc, - "-o", - &epoch, - ]); + match encryption_details { + EncryptionDetails::Inherit => {} + + EncryptionDetails::Off => { + cmd.args(&["-o", "encryption=off"]); + } + + EncryptionDetails::Aes256Gcm { keypath, epoch } => { + let keyloc = format!("keylocation=file://{keypath}"); + let epoch = format!("oxide:epoch={epoch}"); + cmd.args(&[ + "-o", + "encryption=aes-256-gcm", + "-o", + "keyformat=raw", + "-o", + &keyloc, + "-o", + &epoch, + ]); + } } match can_mount { @@ -1411,27 +1556,36 @@ impl Zfs { } pub async fn ensure_dataset_volume( - name: String, - size: ByteCount, - block_size: u32, + params: DatasetVolumeEnsureArgs<'_>, ) -> Result<(), EnsureDatasetVolumeError> { let mut command = Command::new(PFEXEC); let cmd = command.args(&[ZFS, "create"]); - cmd.args(&[ - "-V", - &size.to_bytes().to_string(), - "-o", - &format!("volblocksize={}", block_size), - &name, - ]); + let mut args: Vec = + vec!["-V".to_string(), params.size.to_bytes().to_string()]; + + if params.raw { + args.push("-o".to_string()); + args.push("rawvol=on".to_string()); + } + + if let Some(volblocksize) = ¶ms.volblocksize { + args.push("-o".to_string()); + args.push(format!("volblocksize={}", volblocksize)); + } + + args.push(params.name.to_string()); + + cmd.args(&args); // The command to create a dataset is not idempotent and will fail with // "dataset already exists" if the volume is created already. Eat this // and return Ok instead. match execute_async(cmd).await { - Ok(_) => Ok(()), + Ok(_) => { + // Nothing to do + } Err(crate::ExecutionError::CommandFailure(info)) if info.stderr.contains("dataset already exists") => @@ -1440,55 +1594,162 @@ impl Zfs { // being requested: these cannot be changed once the volume is // created. - let [actual_size, actual_block_size] = - Self::get_values(&name, &["volsize", "volblocksize"], None) - .await - .map_err(|err| { - EnsureDatasetVolumeError::get_value( - name.clone(), - err, - ) - })?; + let [actual_size, actual_volblocksize] = Self::get_values( + params.name, + &["volsize", "volblocksize"], + None, + ) + .await + .map_err(|err| { + EnsureDatasetVolumeError::get_value( + params.name.to_string(), + err, + ) + })?; let actual_size: u64 = actual_size.parse().map_err(|_| { EnsureDatasetVolumeError::value_parse( - name.clone(), + params.name.to_string(), String::from("volsize"), actual_size, ) })?; - let actual_block_size: u32 = - actual_block_size.parse().map_err(|_| { + let actual_volblocksize: u32 = + actual_volblocksize.parse().map_err(|_| { EnsureDatasetVolumeError::value_parse( - name.clone(), + params.name.to_string(), String::from("volblocksize"), - actual_block_size, + actual_volblocksize, ) })?; - if actual_size != size.to_bytes() { + if actual_size != params.size.to_bytes() { return Err(EnsureDatasetVolumeError::value_mismatch( - name.clone(), + params.name.to_string(), String::from("volsize"), - size.to_bytes(), + params.size.to_bytes(), actual_size, )); } - if actual_block_size != block_size { - return Err(EnsureDatasetVolumeError::value_mismatch( - name.clone(), - String::from("volblocksize"), - u64::from(block_size), - u64::from(actual_block_size), - )); + if let Some(volblocksize) = ¶ms.volblocksize { + if actual_volblocksize != *volblocksize { + return Err(EnsureDatasetVolumeError::value_mismatch( + params.name.to_string(), + String::from("volblocksize"), + u64::from(*volblocksize), + u64::from(actual_volblocksize), + )); + } } + } + Err(err) => { + return Err(EnsureDatasetVolumeError::execution( + params.name.to_string(), + err, + )); + } + } + + if params.raw { + // Open the raw zvol and read from it. If EINPROGRESS is seen from + // the read, then it's not done initializing yet. We can't use it + // until it's fully done, so return the `NotReady` variant to signal + // upstack that it should poll. + let path = format!("/dev/zvol/rdsk/{}", params.name); + + let fd = rustix::fs::open( + path, + rustix::fs::OFlags::RDONLY, + rustix::fs::Mode::empty(), + ) + .map_err(|e| { + EnsureDatasetVolumeError::from_raw_zvol_open( + params.name.to_string(), + e, + ) + })?; + + let mut buf = [0u8; 64]; + rustix::io::read(fd, &mut buf).map_err(|e| { + EnsureDatasetVolumeError::from_raw_zvol_read( + params.name.to_string(), + e, + ) + })?; + } + + Ok(()) + } + + pub async fn delete_dataset_volume( + params: DatasetVolumeDeleteArgs<'_>, + ) -> Result<(), DeleteDatasetVolumeError> { + if params.raw { + // Open the raw zvol and check if it is still initializing. We can't + // delete it if it is, so stop the initialization before deleting. + let path = format!("/dev/zvol/rdsk/{}", params.name); + + let fd = rustix::fs::open( + path, + rustix::fs::OFlags::WRONLY, + rustix::fs::Mode::empty(), + ) + .map_err(|e| { + DeleteDatasetVolumeError::from_raw_zvol_open( + params.name.to_string(), + e, + ) + })?; + + #[cfg(target_os = "illumos")] + const DKIOCRAWVOLSTOP: libc::c_int = (0x04 << 8) | 0x1f; + #[cfg(not(target_os = "illumos"))] + const DKIOCRAWVOLSTOP: libc::c_ulong = (0x04 << 8) | 0x1f; + + // DKIOCRAWVOLSTOP will stop the initialization and block waiting + // for the initialization thread to exit. If this returns 0, the + // initialization thread has stopped and exited ok, proceed with + // deletion. + if unsafe { libc::ioctl(fd.as_raw_fd(), DKIOCRAWVOLSTOP) } == -1 { + let err = std::io::Error::last_os_error(); + match err.raw_os_error().unwrap() { + libc::ENOENT => { + // The raw volume was not initializing, proceed with + // deletion. + } + + e => { + // Unexpected error, return up the stack + return Err( + DeleteDatasetVolumeError::cancelling_initialization( + params.name.to_string(), + e, + ), + ); + } + } + } + } + + let mut command = Command::new(PFEXEC); + let cmd = command.args(&[ZFS, "destroy", params.name]); + + match execute_async(cmd).await { + Ok(_) => Ok(()), + + Err(crate::ExecutionError::CommandFailure(info)) + if info.stderr.contains("dataset does not exist") => + { Ok(()) } - Err(err) => Err(EnsureDatasetVolumeError::execution(name, err)), + Err(err) => Err(DeleteDatasetVolumeError::execution( + params.name.to_string(), + err, + )), } } } diff --git a/nexus/db-model/src/disk_type_local_storage.rs b/nexus/db-model/src/disk_type_local_storage.rs index c5917084f05..1cedec33b84 100644 --- a/nexus/db-model/src/disk_type_local_storage.rs +++ b/nexus/db-model/src/disk_type_local_storage.rs @@ -46,6 +46,8 @@ impl DiskTypeLocalStorage { let overhead: u64 = external::ByteCount::from_mebibytes_u32(70).to_bytes() * gbs; + // XXX revisit, tracked by oxidecomputer/omicron#9591 + // Don't unwrap this - the size of this disk is a parameter set by an // API call, and we don't want to panic on out of range input. let required_dataset_overhead = diff --git a/nexus/src/app/sagas/instance_start.rs b/nexus/src/app/sagas/instance_start.rs index a7df97649c1..a5e22af0c06 100644 --- a/nexus/src/app/sagas/instance_start.rs +++ b/nexus/src/app/sagas/instance_start.rs @@ -173,8 +173,14 @@ impl NexusSaga for SagaInstanceStart { // Changing MAX_DISKS_PER_INSTANCE requires changing this saga static_assertions::const_assert!(MAX_DISKS_PER_INSTANCE == 12); + + // In parallel, ensure all local storage related to this instance. seq!(N in 0..12 { - builder.append(paste!([]())); + builder.append_parallel(vec![ + #( + paste!([]()), + )* + ]); }); builder.append(dpd_ensure_action()); diff --git a/sled-agent/config-reconciler/src/dataset_serialization_task.rs b/sled-agent/config-reconciler/src/dataset_serialization_task.rs index 9abad836c09..cf6b55fa559 100644 --- a/sled-agent/config-reconciler/src/dataset_serialization_task.rs +++ b/sled-agent/config-reconciler/src/dataset_serialization_task.rs @@ -23,6 +23,7 @@ use illumos_utils::zfs::CanMount; use illumos_utils::zfs::DatasetEnsureArgs; use illumos_utils::zfs::DatasetProperties; use illumos_utils::zfs::DestroyDatasetError; +use illumos_utils::zfs::EncryptionDetails; use illumos_utils::zfs::Mountpoint; use illumos_utils::zfs::WhichDatasets; use illumos_utils::zfs::Zfs; @@ -951,7 +952,7 @@ impl DatasetTask { // `crypt` dataset. Ensuring that dataset would require non-`None` // encryption details, but that's currently handled by `Disk::new()` // when we start managing external disks. - let encryption_details = None; + let encryption_details = EncryptionDetails::Inherit; let size_details = Some(illumos_utils::zfs::SizeDetails { quota: size_details.quota, diff --git a/sled-agent/src/backing_fs.rs b/sled-agent/src/backing_fs.rs index ac6e625512a..85482ec39a1 100644 --- a/sled-agent/src/backing_fs.rs +++ b/sled-agent/src/backing_fs.rs @@ -23,8 +23,8 @@ use camino::Utf8PathBuf; use illumos_utils::zfs::{ - CanMount, DatasetEnsureArgs, EnsureDatasetError, GetValueError, Mountpoint, - SizeDetails, Zfs, + CanMount, DatasetEnsureArgs, EncryptionDetails, EnsureDatasetError, + GetValueError, Mountpoint, SizeDetails, Zfs, }; use omicron_common::api::external::ByteCount; use omicron_common::disk::CompressionAlgorithm; @@ -149,7 +149,7 @@ pub(crate) async fn ensure_backing_fs( mountpoint: mountpoint.clone(), can_mount: CanMount::NoAuto, zoned: false, - encryption_details: None, + encryption_details: EncryptionDetails::Inherit, size_details, id: None, additional_options: None, diff --git a/sled-agent/src/bootstrap/pre_server.rs b/sled-agent/src/bootstrap/pre_server.rs index bd689156f88..3359e698371 100644 --- a/sled-agent/src/bootstrap/pre_server.rs +++ b/sled-agent/src/bootstrap/pre_server.rs @@ -29,6 +29,7 @@ use illumos_utils::addrobj::AddrObject; use illumos_utils::dladm; use illumos_utils::dladm::Dladm; use illumos_utils::zfs; +use illumos_utils::zfs::EncryptionDetails; use illumos_utils::zfs::Zfs; use illumos_utils::zone; use illumos_utils::zone::Api; @@ -281,7 +282,7 @@ async fn ensure_zfs_ramdisk_dataset() -> Result<(), StartError> { )), can_mount: zfs::CanMount::On, zoned: false, - encryption_details: None, + encryption_details: EncryptionDetails::Inherit, size_details: None, id: None, additional_options: None, diff --git a/sled-agent/src/sled_agent.rs b/sled-agent/src/sled_agent.rs index 45de65083c2..89e743c6356 100644 --- a/sled-agent/src/sled_agent.rs +++ b/sled-agent/src/sled_agent.rs @@ -34,6 +34,9 @@ use illumos_utils::opte::PortManager; use illumos_utils::running_zone::RunningZone; use illumos_utils::zfs::CanMount; use illumos_utils::zfs::DatasetEnsureArgs; +use illumos_utils::zfs::DatasetVolumeDeleteArgs; +use illumos_utils::zfs::DatasetVolumeEnsureArgs; +use illumos_utils::zfs::EncryptionDetails; use illumos_utils::zfs::Mountpoint; use illumos_utils::zfs::SizeDetails; use illumos_utils::zfs::Zfs; @@ -1283,10 +1286,11 @@ impl SledAgent { ), can_mount: CanMount::Off, zoned: false, - // encryption details not required, will inherit from parent - // "oxp_UUID/crypt/local_storage", which inherits from - // "oxp_UUID/crypt" - encryption_details: None, + // Ordinarily, we would want to inherit encryption details from the + // parent "oxp_UUID/crypt/local_storage" dataset, which inherits + // from "oxp_UUID/crypt". We're making raw zvols though, so set + // encryption explicitly off. + encryption_details: EncryptionDetails::Off, size_details: Some(SizeDetails { quota: Some(dataset_size), reservation: Some(dataset_size), @@ -1298,13 +1302,20 @@ impl SledAgent { .await .map_err(|e| HttpError::for_internal_error(e.to_string()))?; - Zfs::ensure_dataset_volume( - delegated_zvol.volume_name(), - volume_size, - delegated_zvol.volblocksize(), - ) + Zfs::ensure_dataset_volume(DatasetVolumeEnsureArgs { + name: &delegated_zvol.volume_name(), + size: volume_size, + raw: true, + volblocksize: None, + }) .await - .map_err(|e| HttpError::for_internal_error(e.to_string()))?; + .map_err(|e| { + if e.is_not_ready() { + HttpError::for_unavail(None, e.to_string()) + } else { + HttpError::for_internal_error(e.to_string()) + } + })?; Ok(()) } @@ -1339,6 +1350,19 @@ impl SledAgent { let delegated_zvol = DelegatedZvol::LocalStorage { zpool_id, dataset_id }; + Zfs::delete_dataset_volume(DatasetVolumeDeleteArgs { + name: &delegated_zvol.volume_name(), + raw: true, + }) + .await + .map_err(|e| { + if e.is_not_ready() { + HttpError::for_unavail(None, e.to_string()) + } else { + HttpError::for_internal_error(e.to_string()) + } + })?; + Zfs::destroy_dataset(&delegated_zvol.parent_dataset_name()) .await .map_err(|e| HttpError::for_internal_error(e.to_string()))?; diff --git a/sled-storage/src/dataset.rs b/sled-storage/src/dataset.rs index 1fcb7bb76a4..89cb1a0b628 100644 --- a/sled-storage/src/dataset.rs +++ b/sled-storage/src/dataset.rs @@ -247,7 +247,8 @@ pub(crate) async fn ensure_zpool_has_datasets( error, })?; - let encryption_details = EncryptionDetails { keypath, epoch }; + let encryption_details = + EncryptionDetails::Aes256Gcm { keypath, epoch }; info!( log, @@ -259,7 +260,7 @@ pub(crate) async fn ensure_zpool_has_datasets( mountpoint: Mountpoint(mountpoint), can_mount: zfs::CanMount::On, zoned, - encryption_details: Some(encryption_details), + encryption_details, size_details: None, id: None, additional_options: None, @@ -286,7 +287,6 @@ pub(crate) async fn ensure_zpool_has_datasets( zpool_name.dataset_mountpoint(&mount_config.root, dataset.name); let name = &format!("{}/{}", zpool_name, dataset.name); - let encryption_details = None; let size_details = Some(SizeDetails { quota: dataset.quota, reservation: None, @@ -297,7 +297,7 @@ pub(crate) async fn ensure_zpool_has_datasets( mountpoint: Mountpoint(mountpoint), can_mount: zfs::CanMount::On, zoned, - encryption_details, + encryption_details: EncryptionDetails::Inherit, size_details, id: None, additional_options: None, diff --git a/sled-storage/zfs-test-harness/src/lib.rs b/sled-storage/zfs-test-harness/src/lib.rs index 6ff3cceec04..e4f20a089ed 100644 --- a/sled-storage/zfs-test-harness/src/lib.rs +++ b/sled-storage/zfs-test-harness/src/lib.rs @@ -13,6 +13,7 @@ use illumos_utils::ExecutionError; use illumos_utils::PFEXEC; use illumos_utils::zfs::CanMount; use illumos_utils::zfs::DatasetEnsureArgs; +use illumos_utils::zfs::EncryptionDetails; use illumos_utils::zfs::Mountpoint; use illumos_utils::zfs::Zfs; use key_manager::KeyManager; @@ -308,7 +309,7 @@ impl Inner { let DatasetCreationDetails { zoned, mountpoint, full_name } = details; // The "crypt" dataset needs these details, but should already exist // by the time we're creating datasets inside. - let encryption_details = None; + let encryption_details = EncryptionDetails::Inherit; let size_details = Some(illumos_utils::zfs::SizeDetails { quota: config.quota, reservation: config.reservation, diff --git a/workspace-hack/Cargo.toml b/workspace-hack/Cargo.toml index 70b6ad8ec8d..28245d05c3e 100644 --- a/workspace-hack/Cargo.toml +++ b/workspace-hack/Cargo.toml @@ -26,7 +26,7 @@ base16ct = { version = "0.2.0", default-features = false, features = ["alloc"] } base64 = { version = "0.22.1" } base64ct = { version = "1.6.0", default-features = false, features = ["std"] } bitflags-dff4ba8e3ae991db = { package = "bitflags", version = "1.3.2" } -bitflags-f595c2ba2a3f28df = { package = "bitflags", version = "2.9.4", default-features = false, features = ["serde"] } +bitflags-f595c2ba2a3f28df = { package = "bitflags", version = "2.9.4", default-features = false, features = ["serde", "std"] } bstr = { version = "1.10.0" } buf-list = { version = "1.0.3", default-features = false, features = ["tokio1"] } byteorder = { version = "1.5.0" } @@ -77,6 +77,7 @@ indexmap = { version = "2.12.1", features = ["serde"] } inout = { version = "0.1.3", default-features = false, features = ["std"] } ipnet = { version = "2.11.0", features = ["serde"] } ipnetwork = { version = "0.21.1", features = ["schemars", "serde"] } +itertools-594e8ee84c453af0 = { package = "itertools", version = "0.13.0" } lalrpop-util = { version = "0.19.12" } lazy_static = { version = "1.5.0", default-features = false, features = ["spin_no_std"] } libc = { version = "0.2.174", features = ["extra_traits"] } @@ -166,7 +167,7 @@ base16ct = { version = "0.2.0", default-features = false, features = ["alloc"] } base64 = { version = "0.22.1" } base64ct = { version = "1.6.0", default-features = false, features = ["std"] } bitflags-dff4ba8e3ae991db = { package = "bitflags", version = "1.3.2" } -bitflags-f595c2ba2a3f28df = { package = "bitflags", version = "2.9.4", default-features = false, features = ["serde"] } +bitflags-f595c2ba2a3f28df = { package = "bitflags", version = "2.9.4", default-features = false, features = ["serde", "std"] } bstr = { version = "1.10.0" } buf-list = { version = "1.0.3", default-features = false, features = ["tokio1"] } byteorder = { version = "1.5.0" } @@ -218,6 +219,7 @@ indexmap = { version = "2.12.1", features = ["serde"] } inout = { version = "0.1.3", default-features = false, features = ["std"] } ipnet = { version = "2.11.0", features = ["serde"] } ipnetwork = { version = "0.21.1", features = ["schemars", "serde"] } +itertools-594e8ee84c453af0 = { package = "itertools", version = "0.13.0" } lalrpop-util = { version = "0.19.12" } lazy_static = { version = "1.5.0", default-features = false, features = ["spin_no_std"] } libc = { version = "0.2.174", features = ["extra_traits"] } @@ -304,7 +306,6 @@ zip-164d15cefe24d7eb = { package = "zip", version = "4.2.0", default-features = zip-3b31131e45eafb45 = { package = "zip", version = "0.6.6", default-features = false, features = ["bzip2", "deflate"] } [target.x86_64-unknown-linux-gnu.dependencies] -bitflags-f595c2ba2a3f28df = { package = "bitflags", version = "2.9.4", default-features = false, features = ["std"] } cookie = { version = "0.18.1", default-features = false, features = ["percent-encode"] } dof-468e82937335b1c9 = { package = "dof", version = "0.3.0", default-features = false, features = ["des"] } dof-9fbad63c4bcf4a8f = { package = "dof", version = "0.4.0", default-features = false, features = ["des"] } @@ -315,11 +316,10 @@ linux-raw-sys = { version = "0.4.14", default-features = false, features = ["elf miniz_oxide = { version = "0.8.5", default-features = false, features = ["with-alloc"] } mio = { version = "1.0.2", features = ["net", "os-ext"] } rustix-d585fab2519d2d1 = { package = "rustix", version = "0.38.37", features = ["event", "fs", "net", "pipe", "process", "stdio", "system", "termios", "time"] } -rustix-dff4ba8e3ae991db = { package = "rustix", version = "1.0.7", features = ["fs", "stdio", "termios"] } +rustix-dff4ba8e3ae991db = { package = "rustix", version = "1.1.2", features = ["fs", "stdio", "termios"] } zerocopy-ca01ad9e24f5d932 = { package = "zerocopy", version = "0.7.35", features = ["derive", "simd"] } [target.x86_64-unknown-linux-gnu.build-dependencies] -bitflags-f595c2ba2a3f28df = { package = "bitflags", version = "2.9.4", default-features = false, features = ["std"] } cookie = { version = "0.18.1", default-features = false, features = ["percent-encode"] } dof-468e82937335b1c9 = { package = "dof", version = "0.3.0", default-features = false, features = ["des"] } dof-9fbad63c4bcf4a8f = { package = "dof", version = "0.4.0", default-features = false, features = ["des"] } @@ -330,11 +330,10 @@ linux-raw-sys = { version = "0.4.14", default-features = false, features = ["elf miniz_oxide = { version = "0.8.5", default-features = false, features = ["with-alloc"] } mio = { version = "1.0.2", features = ["net", "os-ext"] } rustix-d585fab2519d2d1 = { package = "rustix", version = "0.38.37", features = ["event", "fs", "net", "pipe", "process", "stdio", "system", "termios", "time"] } -rustix-dff4ba8e3ae991db = { package = "rustix", version = "1.0.7", features = ["fs", "stdio", "termios"] } +rustix-dff4ba8e3ae991db = { package = "rustix", version = "1.1.2", features = ["fs", "stdio", "termios"] } zerocopy-ca01ad9e24f5d932 = { package = "zerocopy", version = "0.7.35", features = ["derive", "simd"] } [target.x86_64-apple-darwin.dependencies] -bitflags-f595c2ba2a3f28df = { package = "bitflags", version = "2.9.4", default-features = false, features = ["std"] } cookie = { version = "0.18.1", default-features = false, features = ["percent-encode"] } getrandom-468e82937335b1c9 = { package = "getrandom", version = "0.3.4", default-features = false, features = ["std"] } hyper-rustls = { version = "0.27.7", features = ["http2", "ring", "webpki-tokio"] } @@ -342,10 +341,9 @@ hyper-util = { version = "0.1.19", features = ["full"] } miniz_oxide = { version = "0.8.5", default-features = false, features = ["with-alloc"] } mio = { version = "1.0.2", features = ["net", "os-ext"] } rustix-d585fab2519d2d1 = { package = "rustix", version = "0.38.37", features = ["event", "fs", "net", "pipe", "process", "stdio", "system", "termios", "time"] } -rustix-dff4ba8e3ae991db = { package = "rustix", version = "1.0.7", features = ["fs", "stdio", "termios"] } +rustix-dff4ba8e3ae991db = { package = "rustix", version = "1.1.2", features = ["fs", "stdio", "termios"] } [target.x86_64-apple-darwin.build-dependencies] -bitflags-f595c2ba2a3f28df = { package = "bitflags", version = "2.9.4", default-features = false, features = ["std"] } cookie = { version = "0.18.1", default-features = false, features = ["percent-encode"] } getrandom-468e82937335b1c9 = { package = "getrandom", version = "0.3.4", default-features = false, features = ["std"] } hyper-rustls = { version = "0.27.7", features = ["http2", "ring", "webpki-tokio"] } @@ -353,10 +351,9 @@ hyper-util = { version = "0.1.19", features = ["full"] } miniz_oxide = { version = "0.8.5", default-features = false, features = ["with-alloc"] } mio = { version = "1.0.2", features = ["net", "os-ext"] } rustix-d585fab2519d2d1 = { package = "rustix", version = "0.38.37", features = ["event", "fs", "net", "pipe", "process", "stdio", "system", "termios", "time"] } -rustix-dff4ba8e3ae991db = { package = "rustix", version = "1.0.7", features = ["fs", "stdio", "termios"] } +rustix-dff4ba8e3ae991db = { package = "rustix", version = "1.1.2", features = ["fs", "stdio", "termios"] } [target.aarch64-apple-darwin.dependencies] -bitflags-f595c2ba2a3f28df = { package = "bitflags", version = "2.9.4", default-features = false, features = ["std"] } cookie = { version = "0.18.1", default-features = false, features = ["percent-encode"] } getrandom-468e82937335b1c9 = { package = "getrandom", version = "0.3.4", default-features = false, features = ["std"] } hyper-rustls = { version = "0.27.7", features = ["http2", "ring", "webpki-tokio"] } @@ -364,10 +361,9 @@ hyper-util = { version = "0.1.19", features = ["full"] } miniz_oxide = { version = "0.8.5", default-features = false, features = ["with-alloc"] } mio = { version = "1.0.2", features = ["net", "os-ext"] } rustix-d585fab2519d2d1 = { package = "rustix", version = "0.38.37", features = ["event", "fs", "net", "pipe", "process", "stdio", "system", "termios", "time"] } -rustix-dff4ba8e3ae991db = { package = "rustix", version = "1.0.7", features = ["fs", "stdio", "termios"] } +rustix-dff4ba8e3ae991db = { package = "rustix", version = "1.1.2", features = ["fs", "stdio", "termios"] } [target.aarch64-apple-darwin.build-dependencies] -bitflags-f595c2ba2a3f28df = { package = "bitflags", version = "2.9.4", default-features = false, features = ["std"] } cookie = { version = "0.18.1", default-features = false, features = ["percent-encode"] } getrandom-468e82937335b1c9 = { package = "getrandom", version = "0.3.4", default-features = false, features = ["std"] } hyper-rustls = { version = "0.27.7", features = ["http2", "ring", "webpki-tokio"] } @@ -375,28 +371,27 @@ hyper-util = { version = "0.1.19", features = ["full"] } miniz_oxide = { version = "0.8.5", default-features = false, features = ["with-alloc"] } mio = { version = "1.0.2", features = ["net", "os-ext"] } rustix-d585fab2519d2d1 = { package = "rustix", version = "0.38.37", features = ["event", "fs", "net", "pipe", "process", "stdio", "system", "termios", "time"] } -rustix-dff4ba8e3ae991db = { package = "rustix", version = "1.0.7", features = ["fs", "stdio", "termios"] } +rustix-dff4ba8e3ae991db = { package = "rustix", version = "1.1.2", features = ["fs", "stdio", "termios"] } [target.x86_64-unknown-illumos.dependencies] -bitflags-f595c2ba2a3f28df = { package = "bitflags", version = "2.9.4", default-features = false, features = ["std"] } cookie = { version = "0.18.1", default-features = false, features = ["percent-encode"] } dof-468e82937335b1c9 = { package = "dof", version = "0.3.0", default-features = false, features = ["des"] } dof-9fbad63c4bcf4a8f = { package = "dof", version = "0.4.0", default-features = false, features = ["des"] } getrandom-468e82937335b1c9 = { package = "getrandom", version = "0.3.4", default-features = false, features = ["std"] } hyper-rustls = { version = "0.27.7", features = ["http2", "ring", "webpki-tokio"] } hyper-util = { version = "0.1.19", features = ["full"] } -itertools = { version = "0.10.5" } +itertools-5ef9efb8ec2df382 = { package = "itertools", version = "0.12.1" } +itertools-93f6ce9d446188ac = { package = "itertools", version = "0.10.5" } miniz_oxide = { version = "0.8.5", default-features = false, features = ["with-alloc"] } mio = { version = "1.0.2", features = ["net", "os-ext"] } nom = { version = "7.1.3" } rustix-d585fab2519d2d1 = { package = "rustix", version = "0.38.37", features = ["event", "fs", "net", "pipe", "process", "stdio", "system", "termios", "time"] } -rustix-dff4ba8e3ae991db = { package = "rustix", version = "1.0.7", features = ["fs", "stdio", "termios"] } +rustix-dff4ba8e3ae991db = { package = "rustix", version = "1.1.2", features = ["fs", "stdio", "termios"] } toml_edit-cdcf2f9584511fe6 = { package = "toml_edit", version = "0.19.15", features = ["serde"] } winnow-3b31131e45eafb45 = { package = "winnow", version = "0.6.26", features = ["simd"] } zerocopy-ca01ad9e24f5d932 = { package = "zerocopy", version = "0.7.35", features = ["derive", "simd"] } [target.x86_64-unknown-illumos.build-dependencies] -bitflags-f595c2ba2a3f28df = { package = "bitflags", version = "2.9.4", default-features = false, features = ["std"] } clang-sys = { version = "1.8.1", default-features = false, features = ["clang_11_0", "runtime"] } cookie = { version = "0.18.1", default-features = false, features = ["percent-encode"] } dof-468e82937335b1c9 = { package = "dof", version = "0.3.0", default-features = false, features = ["des"] } @@ -404,12 +399,13 @@ dof-9fbad63c4bcf4a8f = { package = "dof", version = "0.4.0", default-features = getrandom-468e82937335b1c9 = { package = "getrandom", version = "0.3.4", default-features = false, features = ["std"] } hyper-rustls = { version = "0.27.7", features = ["http2", "ring", "webpki-tokio"] } hyper-util = { version = "0.1.19", features = ["full"] } -itertools = { version = "0.10.5" } +itertools-5ef9efb8ec2df382 = { package = "itertools", version = "0.12.1" } +itertools-93f6ce9d446188ac = { package = "itertools", version = "0.10.5" } miniz_oxide = { version = "0.8.5", default-features = false, features = ["with-alloc"] } mio = { version = "1.0.2", features = ["net", "os-ext"] } nom = { version = "7.1.3" } rustix-d585fab2519d2d1 = { package = "rustix", version = "0.38.37", features = ["event", "fs", "net", "pipe", "process", "stdio", "system", "termios", "time"] } -rustix-dff4ba8e3ae991db = { package = "rustix", version = "1.0.7", features = ["fs", "stdio", "termios"] } +rustix-dff4ba8e3ae991db = { package = "rustix", version = "1.1.2", features = ["fs", "stdio", "termios"] } toml_edit-cdcf2f9584511fe6 = { package = "toml_edit", version = "0.19.15", features = ["serde"] } winnow-3b31131e45eafb45 = { package = "winnow", version = "0.6.26", features = ["simd"] } zerocopy-ca01ad9e24f5d932 = { package = "zerocopy", version = "0.7.35", features = ["derive", "simd"] }