Skip to content

Conversation

@jmpesp
Copy link
Contributor

@jmpesp jmpesp commented Jan 20, 2026

Using a dataset that inherits encryption for raw zvols isn't possible, so create a new unencrypted parent dataset for local storage, and switch over to using that.

Note that there isn't a migration plan for existing disks backed by local storage. The sled-agent API simply switches over to using the unencrypted dataset instead, and Nexus' allocation routines similarly switch over. All existing disks backed by local storage should be deleted before this PR lands!

Using a dataset that inherits encryption for raw zvols isn't possible,
so create a new unencrypted parent dataset for local storage, and switch
over to using that.

Note that there isn't a migration plan for existing disks backed by
local storage. The sled-agent API simply switches over to using the
unencrypted dataset instead, and Nexus' allocation routines similarly
switch over. All existing disks backed by local storage should be
deleted before this PR lands!
@jmpesp jmpesp requested a review from jgallagher January 20, 2026 18:03
@leftwo leftwo added the local storage relating to the local storage feature label Jan 20, 2026
@leftwo leftwo added this to the 18 milestone Jan 20, 2026
@jmpesp jmpesp self-assigned this Jan 20, 2026
/// Delegate a slice of the local storage dataset present on this pool into
/// the zone.
/// Delegate a slice of the unencrypted local storage dataset present on
/// this pool into the zone.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it okay to change the meaning of this variant as opposed to adding a LocalStorageUnencrypted variant to match the two dataset kinds? I'm wondering if this will be a pain when we get back to DatasetKind::LocalStorage (encrypted) support.

Comment on lines +250 to +255
(Some(_), Some(_)) => {
return Err(Error::internal_error(&format!(
"LocalStorageDisk {} has multiple allocations!",
self.id(),
)));
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we encode this requirement in the type system? E.g., instead of two Option fields, a single field with a enum with variants spelling out the valid options?

format!("{zpool_name}/crypt/local_storage"),
format!("{dataset_id}/vol"),
]
.join("/");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realize this was already here but I guess I missed in the last PR. It seems very fishy for Nexus to be building up paths to devices on sleds - can this level of detail be left to sled-agent, and Nexus deal with higher level things (like just the zpool / dataset IDs)?

Comment on lines +409 to +410
local_storage_dataset_allocation,
local_storage_unencrypted_dataset_allocation,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this function can return Ok(_) with both of these fields set to Some(_) or None(_), which will end up causing errors above. I feel more strongly this should be a single field, now, but if for some reason it can't, should this function check that exactly one of these fields is Some(_)?


/// List one page of unencrypted local storage datasets
///
/// This fetches all datasets, including those that have been tombstoned.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Including tombstoned datasets seems unusual for a _list function - should we make the name scarier sounding so it's more obvious to callers that they may need to consider each item's status?

{
info!(&log, "disk.local_storage_dataset_allocation.is_some()");
return Err(SledReservationTransactionError::Reservation(
SledReservationError::NotFound,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this error indicate that we can't reserve this disk because there's an older local storage dataset that needs to be cleaned up?

let mut stats = DatasetsRendezvousStats::default();

for bp_dataset in blueprint_datasets {
// Filter down to LocalStorage datasets...
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Filter down to LocalStorage datasets...
// Filter down to LocalStorageUnencrypted datasets...

for bp_dataset in blueprint_datasets {
// Filter down to LocalStorage datasets...
let dataset = match (&bp_dataset.kind, bp_dataset.address) {
(DatasetKind::LocalStorageUnencrypted, None) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we match on an address of None here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

local storage relating to the local storage feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants