Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewjstone committed Oct 3, 2023
1 parent 9651217 commit 4a38f90
Show file tree
Hide file tree
Showing 5 changed files with 248 additions and 445 deletions.
1 change: 1 addition & 0 deletions sled-hardware/src/disk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ impl UnparsedDisk {
/// from the ZFS related logic which can also operate on file backed zpools.
/// Doing things this way allows us to not put higher level concepts like
/// storage keys into this hardware related package.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct PooledDisk {
pub paths: DiskPaths,
pub slot: i64,
Expand Down
229 changes: 140 additions & 89 deletions sled-storage/src/disk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,163 +4,214 @@

//! Disk related types
use camino::Utf8PathBuf;
use illumos_utils::zpool::{ZpoolKind, ZpoolName};
use camino::{Utf8Path, Utf8PathBuf};
use derive_more::From;
use illumos_utils::zpool::{Zpool, ZpoolKind, ZpoolName};
use key_manager::StorageKeyRequester;
use omicron_common::disk::DiskIdentity;
use sled_hardware::{
DiskPaths, DiskVariant, Partition, PooledDisk, PooledDiskError,
UnparsedDisk,
DiskVariant, Partition, PooledDisk, PooledDiskError, UnparsedDisk,
};
use slog::Logger;
use std::fs::File;

use crate::dataset;

/// A wrapper around real disks or synthetic disks backed by a file
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum DiskWrapper {
Real { disk: Disk, devfs_path: Utf8PathBuf },
Synthetic { zpool_name: ZpoolName },
#[derive(Debug, thiserror::Error)]
pub enum DiskError {
#[error(transparent)]
Dataset(#[from] crate::dataset::DatasetError),
#[error(transparent)]
PooledDisk(#[from] sled_hardware::PooledDiskError),
}

// A synthetic disk that acts as one "found" by the hardware and that is backed
// by a zpool
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct SyntheticDisk {
identity: DiskIdentity,
zpool_name: ZpoolName,
}

impl From<Disk> for DiskWrapper {
fn from(disk: Disk) -> Self {
let devfs_path = disk.devfs_path().clone();
Self::Real { disk, devfs_path }
impl SyntheticDisk {
// Create a zpool and import it for the synthetic disk
// Zpools willl be set to the min size of 64Mib
pub fn create_zpool(
dir: &Utf8Path,
zpool_name: &ZpoolName,
) -> SyntheticDisk {
// 64 MiB (min size of zpool)
const DISK_SIZE: u64 = 64 * 1024 * 1024;
let path = dir.join(zpool_name.to_string());
let file = File::create(&path).unwrap();
file.set_len(DISK_SIZE).unwrap();
drop(file);
Zpool::create(zpool_name, &path).unwrap();
Zpool::import(zpool_name).unwrap();
Zpool::set_failmode_continue(zpool_name).unwrap();
Self::new(zpool_name.clone())
}

pub fn new(zpool_name: ZpoolName) -> SyntheticDisk {
let id = zpool_name.id();
let identity = DiskIdentity {
vendor: "synthetic-vendor".to_string(),
serial: format!("synthetic-serial-{id}"),
model: "synthetic-model".to_string(),
};
SyntheticDisk { identity, zpool_name }
}
}

impl DiskWrapper {
pub fn identity(&self) -> DiskIdentity {
// An [`UnparsedDisk`] disk learned about from the hardware or a wrapped zpool
#[derive(Debug, Clone, PartialEq, Eq, Hash, From)]
pub enum RawDisk {
Real(UnparsedDisk),
Synthetic(SyntheticDisk),
}

impl RawDisk {
pub fn is_boot_disk(&self) -> bool {
match self {
DiskWrapper::Real { disk, .. } => disk.identity().clone(),
DiskWrapper::Synthetic { zpool_name } => {
let id = zpool_name.id();
DiskIdentity {
vendor: "synthetic-vendor".to_string(),
serial: format!("synthetic-serial-{id}"),
model: "synthetic-model".to_string(),
}
Self::Real(disk) => disk.is_boot_disk(),
Self::Synthetic(disk) => {
// Just label any M.2 the boot disk.
disk.zpool_name.kind() == ZpoolKind::Internal
}
}
}

pub fn variant(&self) -> DiskVariant {
pub fn identity(&self) -> &DiskIdentity {
match self {
DiskWrapper::Real { disk, .. } => disk.variant(),
DiskWrapper::Synthetic { zpool_name } => match zpool_name.kind() {
ZpoolKind::External => DiskVariant::U2,
ZpoolKind::Internal => DiskVariant::M2,
},
Self::Real(disk) => &disk.identity(),
Self::Synthetic(disk) => &disk.identity,
}
}

pub fn zpool_name(&self) -> &ZpoolName {
pub fn variant(&self) -> DiskVariant {
match self {
DiskWrapper::Real { disk, .. } => disk.zpool_name(),
DiskWrapper::Synthetic { zpool_name } => zpool_name,
Self::Real(disk) => disk.variant(),
Self::Synthetic(disk) => match disk.zpool_name.kind() {
ZpoolKind::External => DiskVariant::U2,
ZpoolKind::Internal => DiskVariant::M2,
},
}
}
}

#[derive(Debug, thiserror::Error)]
pub enum DiskError {
#[error(transparent)]
Dataset(#[from] crate::dataset::DatasetError),
#[error(transparent)]
PooledDisk(#[from] sled_hardware::PooledDiskError),
}

/// A physical disk conforming to the expected partition layout
/// and which contains provisioned zpools and datasets. This disk
/// is ready for usage by higher level software.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Disk {
paths: DiskPaths,
slot: i64,
variant: DiskVariant,
identity: DiskIdentity,
is_boot_disk: bool,
partitions: Vec<Partition>,

// This embeds the assumtion that there is exactly one parsed zpool per
// disk.
zpool_name: ZpoolName,
/// A physical [`PooledDisk`] or a [`SyntheticDisk`] that contains or is backed
/// by a single zpool and that has provisioned datasets. This disk is ready for
/// usage by higher level software.
#[derive(Debug, Clone, PartialEq, Eq, Hash, From)]
pub enum Disk {
Real(PooledDisk),
Synthetic(SyntheticDisk),
}

impl Disk {
pub async fn new(
log: &Logger,
unparsed_disk: UnparsedDisk,
raw_disk: RawDisk,
key_requester: Option<&StorageKeyRequester>,
) -> Result<Self, DiskError> {
let disk = PooledDisk::new(log, unparsed_disk)?;
let disk = match raw_disk {
RawDisk::Real(disk) => PooledDisk::new(log, disk)?.into(),
RawDisk::Synthetic(disk) => Disk::Synthetic(disk),
};
dataset::ensure_zpool_has_datasets(
log,
&disk.zpool_name,
&disk.identity,
disk.zpool_name(),
disk.identity(),
key_requester,
)
.await?;
Ok(disk.into())
Ok(disk)
}

pub fn is_synthetic(&self) -> bool {
match self {
Self::Real(_) => false,
Self::Synthetic(_) => true,
}
}

pub fn is_real(&self) -> bool {
!self.is_synthetic()
}

pub fn is_boot_disk(&self) -> bool {
self.is_boot_disk
match self {
Self::Real(disk) => disk.is_boot_disk,
Self::Synthetic(disk) => {
// Just label any M.2 the boot disk.
disk.zpool_name.kind() == ZpoolKind::Internal
}
}
}

pub fn identity(&self) -> &DiskIdentity {
&self.identity
match self {
Self::Real(disk) => &disk.identity,
Self::Synthetic(disk) => &disk.identity,
}
}

pub fn variant(&self) -> DiskVariant {
self.variant
match self {
Self::Real(disk) => disk.variant,
Self::Synthetic(disk) => match disk.zpool_name.kind() {
ZpoolKind::External => DiskVariant::U2,
ZpoolKind::Internal => DiskVariant::M2,
},
}
}

pub fn devfs_path(&self) -> &Utf8PathBuf {
&self.paths.devfs_path
match self {
Self::Real(disk) => &disk.paths.devfs_path,
Self::Synthetic(_) => unreachable!(),
}
}

pub fn zpool_name(&self) -> &ZpoolName {
&self.zpool_name
match self {
Self::Real(disk) => &disk.zpool_name,
Self::Synthetic(disk) => &disk.zpool_name,
}
}

pub fn boot_image_devfs_path(
&self,
raw: bool,
) -> Result<Utf8PathBuf, PooledDiskError> {
self.paths.partition_device_path(
&self.partitions,
Partition::BootImage,
raw,
)
match self {
Self::Real(disk) => disk.paths.partition_device_path(
&disk.partitions,
Partition::BootImage,
raw,
),
Self::Synthetic(_) => unreachable!(),
}
}

pub fn dump_device_devfs_path(
&self,
raw: bool,
) -> Result<Utf8PathBuf, PooledDiskError> {
self.paths.partition_device_path(
&self.partitions,
Partition::DumpDevice,
raw,
)
match self {
Self::Real(disk) => disk.paths.partition_device_path(
&disk.partitions,
Partition::DumpDevice,
raw,
),
Self::Synthetic(_) => unreachable!(),
}
}

pub fn slot(&self) -> i64 {
self.slot
}
}

impl From<PooledDisk> for Disk {
fn from(pd: PooledDisk) -> Self {
Self {
paths: pd.paths,
slot: pd.slot,
variant: pd.variant,
identity: pd.identity,
is_boot_disk: pd.is_boot_disk,
partitions: pd.partitions,
zpool_name: pd.zpool_name,
match self {
Self::Real(disk) => disk.slot,
Self::Synthetic(_) => unreachable!(),
}
}
}
Loading

0 comments on commit 4a38f90

Please sign in to comment.