Skip to content

Commit ac7b83a

Browse files
committed
storage: Add storvsc_manager and disk_storvsc
1 parent 736445b commit ac7b83a

File tree

23 files changed

+1424
-36
lines changed

23 files changed

+1424
-36
lines changed

Cargo.lock

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1335,6 +1335,40 @@ dependencies = [
13351335
"vm_resource",
13361336
]
13371337

1338+
[[package]]
1339+
name = "disk_storvsc"
1340+
version = "0.0.0"
1341+
dependencies = [
1342+
"anyhow",
1343+
"async-trait",
1344+
"disk_backend",
1345+
"futures",
1346+
"futures-concurrency",
1347+
"guestmem",
1348+
"guid",
1349+
"inspect",
1350+
"mesh",
1351+
"pal_async",
1352+
"scsi_buffers",
1353+
"scsi_defs",
1354+
"storvsc_driver",
1355+
"storvsp_protocol",
1356+
"task_control",
1357+
"test_with_tracing",
1358+
"thiserror 2.0.12",
1359+
"tracing",
1360+
"tracing_helpers",
1361+
"vm_resource",
1362+
"vmbus_async",
1363+
"vmbus_channel",
1364+
"vmbus_core",
1365+
"vmbus_relay_intercept_device",
1366+
"vmbus_ring",
1367+
"vmbus_user_channel",
1368+
"vmcore",
1369+
"zerocopy 0.8.24",
1370+
]
1371+
13381372
[[package]]
13391373
name = "disk_striped"
13401374
version = "0.0.0"
@@ -6636,6 +6670,7 @@ dependencies = [
66366670
"chipset_device",
66376671
"disk_backend",
66386672
"disk_nvme",
6673+
"disk_storvsc",
66396674
"disklayer_ram",
66406675
"guestmem",
66416676
"guid",
@@ -6664,10 +6699,12 @@ dependencies = [
66646699
name = "storvsc_driver"
66656700
version = "0.0.0"
66666701
dependencies = [
6702+
"anyhow",
66676703
"futures",
66686704
"futures-concurrency",
66696705
"guestmem",
66706706
"inspect",
6707+
"mesh",
66716708
"mesh_channel",
66726709
"pal_async",
66736710
"scsi_buffers",
@@ -6679,6 +6716,7 @@ dependencies = [
66796716
"thiserror 2.0.12",
66806717
"tracing",
66816718
"tracing_helpers",
6719+
"user_driver",
66826720
"vmbus_async",
66836721
"vmbus_channel",
66846722
"vmbus_ring",
@@ -6734,6 +6772,7 @@ version = "0.0.0"
67346772
dependencies = [
67356773
"arbitrary",
67366774
"guid",
6775+
"inspect",
67376776
"open_enum",
67386777
"scsi_defs",
67396778
"zerocopy 0.8.24",
@@ -7507,6 +7546,7 @@ dependencies = [
75077546
"disk_blockdevice",
75087547
"disk_get_vmgs",
75097548
"disk_nvme",
7549+
"disk_storvsc",
75107550
"firmware_pcat",
75117551
"firmware_uefi",
75127552
"firmware_uefi_custom_vars",
@@ -7573,7 +7613,9 @@ dependencies = [
75737613
"sparse_mmap",
75747614
"state_unit",
75757615
"storage_string",
7616+
"storvsc_driver",
75767617
"storvsp",
7618+
"storvsp_protocol",
75777619
"storvsp_resources",
75787620
"tee_call",
75797621
"thiserror 2.0.12",

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ disk_layered = { path = "vm/devices/storage/disk_layered" }
268268
disk_nvme = { path = "vm/devices/storage/disk_nvme" }
269269
disk_delay = { path = "vm/devices/storage/disk_delay" }
270270
disk_prwrap = { path = "vm/devices/storage/disk_prwrap" }
271+
disk_storvsc = { path = "vm/devices/storage/disk_storvsc" }
271272
disk_striped = { path = "vm/devices/storage/disk_striped" }
272273
disk_vhd1 = { path = "vm/devices/storage/disk_vhd1" }
273274
disk_vhdmp = { path = "vm/devices/storage/disk_vhdmp" }

openhcl/openhcl_boot/src/main.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,9 @@ fn build_kernel_command_line(
159159
"rdinit=/underhill-init",
160160
// Default to user-mode NVMe driver.
161161
"OPENHCL_NVME_VFIO=1",
162-
// The next three items reduce the memory overhead of the storvsc driver.
162+
// Default to user-mode storvsc driver.
163+
"OPENHCL_STORVSC_USERMODE=1",
164+
// The next three items reduce the memory overhead of the kernel storvsc driver.
163165
// Since it is only used for DVD, performance is not critical.
164166
"hv_storvsc.storvsc_vcpus_per_sub_channel=2048",
165167
// Fix number of hardware queues at 2.

openhcl/rootfs.config

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ file /lib/modules/001/pci-hyperv.ko ${OPENHCL_KERNEL_PATH}/build/native/
3535

3636
# Storvsc is last because it sometimes takes a long time to load and should not
3737
# block other device startup.
38-
file /lib/modules/999/hv_storvsc.ko ${OPENHCL_KERNEL_PATH}/build/native/bin/${OPENHCL_KERNEL_ARCH}/modules/kernel/drivers/scsi/hv_storvsc.ko 0644 0 0
38+
#file /lib/modules/999/hv_storvsc.ko ${OPENHCL_KERNEL_PATH}/build/native/bin/${OPENHCL_KERNEL_ARCH}/modules/kernel/drivers/scsi/hv_storvsc.ko 0644 0 0
3939

4040
# These nodes are needed for early logging before devfs is mounted.
4141
nod /dev/null 0666 0 0 c 1 3

openhcl/underhill_core/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ disk_backend_resources.workspace = true
4848
disk_blockdevice.workspace = true
4949
disk_get_vmgs.workspace = true
5050
disk_nvme.workspace = true
51+
disk_storvsc.workspace = true
5152
firmware_uefi.workspace = true
5253
firmware_uefi_custom_vars.workspace = true
5354
hyperv_ic_guest.workspace = true
@@ -79,7 +80,9 @@ scsidisk.workspace = true
7980
scsidisk_resources.workspace = true
8081
serial_16550_resources.workspace = true
8182
storage_string.workspace = true
83+
storvsc_driver.workspace = true
8284
storvsp.workspace = true
85+
storvsp_protocol.workspace = true
8386
storvsp_resources.workspace = true
8487
tpm_resources.workspace = true
8588
tpm = { workspace = true, features = ["tpm"] }

openhcl/underhill_core/src/dispatch/mod.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ use crate::reference_time::ReferenceTime;
1616
use crate::servicing;
1717
use crate::servicing::NvmeSavedState;
1818
use crate::servicing::ServicingState;
19+
use crate::servicing::StorvscSavedState;
20+
use crate::storvsc_manager::StorvscManager;
1921
use crate::vmbus_relay_unit::VmbusRelayHandle;
2022
use crate::worker::FirmwareType;
2123
use crate::worker::NetworkSettingsError;
@@ -142,6 +144,7 @@ pub(crate) struct LoadedVm {
142144
pub uevent_listener: Arc<UeventListener>,
143145
pub resolver: ResourceResolver,
144146
pub nvme_manager: Option<NvmeManager>,
147+
pub storvsc_manager: Option<StorvscManager>,
145148
pub emuplat_servicing: EmuplatServicing,
146149
pub device_interfaces: Option<DeviceInterfaces>,
147150
pub vmbus_client: Option<vmbus_client::VmbusClient>,
@@ -305,6 +308,7 @@ impl LoadedVm {
305308
resp.field("vmgs", self.vmgs.as_ref().map(|x| &x.0));
306309
resp.field("network", &self.network_settings);
307310
resp.field("nvme", &self.nvme_manager);
311+
resp.field("storvsc", &self.storvsc_manager);
308312
resp.field("resolver", &self.resolver);
309313
resp.field(
310314
"vtl0_memory_map",
@@ -538,6 +542,13 @@ impl LoadedVm {
538542
}
539543
};
540544

545+
// Reset all user-mode storvsc devices.
546+
let shutdown_storvsc = async {
547+
if let Some(storvsc_manager) = self.storvsc_manager.take() {
548+
storvsc_manager.shutdown().instrument(tracing::info_span!("shutdown_storvsc", CVM_ALLOWED, %correlation_id)).await;
549+
}
550+
};
551+
541552
// Unbind drivers from the PCI devices to prepare for a kernel
542553
// restart.
543554
let shutdown_pci = async {
@@ -546,7 +557,7 @@ impl LoadedVm {
546557
.await
547558
};
548559

549-
let (r, (), ()) = (shutdown_pci, shutdown_mana, shutdown_nvme).join().await;
560+
let (r, (), (), ()) = (shutdown_pci, shutdown_mana, shutdown_nvme, shutdown_storvsc).join().await;
550561
r?;
551562

552563
Ok(state)
@@ -692,6 +703,17 @@ impl LoadedVm {
692703
None
693704
};
694705

706+
let storvsc_state = if let Some(s) = &self.storvsc_manager {
707+
s.save()
708+
.instrument(tracing::info_span!("storvsc_manager_save", CVM_ALLOWED))
709+
.await
710+
.map(|state| StorvscSavedState {
711+
storvsc_state: state,
712+
})
713+
} else {
714+
None
715+
};
716+
695717
let units = self.save_units().await.context("state unit save failed")?;
696718
let vmgs = if let Some((vmgs_thin_client, vmgs_disk_metadata, _)) = self.vmgs.as_ref() {
697719
Some((
@@ -731,6 +753,7 @@ impl LoadedVm {
731753
nvme_state,
732754
dma_manager_state,
733755
vmbus_client,
756+
storvsc_state,
734757
},
735758
units,
736759
};

openhcl/underhill_core/src/dispatch/vtl2_settings_worker.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
66
use super::LoadedVm;
77
use crate::nvme_manager::NvmeDiskConfig;
8+
use crate::storvsc_manager::StorvscDiskConfig;
89
use crate::worker::NicConfig;
910
use anyhow::Context;
1011
use cvm_tracing::CVM_ALLOWED;
@@ -243,6 +244,7 @@ pub struct DeviceInterfaces {
243244
scsi_dvds: HashMap<StorageDevicePath, mesh::Sender<SimpleScsiDvdRequest>>,
244245
scsi_request: HashMap<Guid, mesh::Sender<ScsiControllerRequest>>,
245246
use_nvme_vfio: bool,
247+
use_storvsc_usermode: bool,
246248
}
247249

248250
impl Vtl2SettingsWorker {
@@ -376,6 +378,7 @@ impl Vtl2SettingsWorker {
376378
&StorageContext {
377379
uevent_listener,
378380
use_nvme_vfio: self.interfaces.use_nvme_vfio,
381+
use_storvsc_usermode: self.interfaces.use_storvsc_usermode,
379382
},
380383
&disk,
381384
false,
@@ -394,6 +397,7 @@ impl Vtl2SettingsWorker {
394397
&StorageContext {
395398
uevent_listener,
396399
use_nvme_vfio: self.interfaces.use_nvme_vfio,
400+
use_storvsc_usermode: self.interfaces.use_storvsc_usermode,
397401
},
398402
&disk,
399403
false,
@@ -957,6 +961,7 @@ async fn make_disk_type_from_physical_devices(
957961
struct StorageContext<'a> {
958962
uevent_listener: &'a UeventListener,
959963
use_nvme_vfio: bool,
964+
use_storvsc_usermode: bool,
960965
}
961966

962967
#[instrument(skip_all, fields(CVM_ALLOWED))]
@@ -1000,6 +1005,36 @@ async fn make_disk_type_from_physical_device(
10001005
}));
10011006
}
10021007

1008+
// Special case for VScsi when using usermode storvsc.
1009+
if storage_context.use_storvsc_usermode
1010+
&& matches!(
1011+
single_device.device_type,
1012+
underhill_config::DeviceType::VScsi
1013+
)
1014+
{
1015+
// Wait for the SCSI controller to arrive.
1016+
let devpath = uio_path(&controller_instance_id);
1017+
async {
1018+
ctx.until_cancelled(storage_context.uevent_listener.wait_for_devpath(&devpath))
1019+
.await??;
1020+
Ok(())
1021+
}
1022+
.await
1023+
.map_err(|err| Error::StorageCannotFindVtl2Device {
1024+
device_type: single_device.device_type,
1025+
instance_id: controller_instance_id,
1026+
sub_device_path,
1027+
source: err,
1028+
})?;
1029+
1030+
// Cannot validate device actually exists yet. Check this later
1031+
// TODO: Is this true?
1032+
return Ok(Resource::new(StorvscDiskConfig {
1033+
instance_guid: controller_instance_id,
1034+
lun: sub_device_path as u8,
1035+
}));
1036+
}
1037+
10031038
// Wait for the device to arrive.
10041039
let devname = async {
10051040
let devname = ctx
@@ -1428,6 +1463,7 @@ pub async fn create_storage_controllers_from_vtl2_settings(
14281463
ctx: &mut CancelContext,
14291464
uevent_listener: &UeventListener,
14301465
use_nvme_vfio: bool,
1466+
use_storvsc_usermode: bool,
14311467
settings: &Vtl2SettingsDynamic,
14321468
sub_channels: u16,
14331469
is_restoring: bool,
@@ -1443,6 +1479,7 @@ pub async fn create_storage_controllers_from_vtl2_settings(
14431479
let storage_context = StorageContext {
14441480
uevent_listener,
14451481
use_nvme_vfio,
1482+
use_storvsc_usermode,
14461483
};
14471484
let ide_controller =
14481485
make_ide_controller_config(ctx, &storage_context, settings, is_restoring).await?;
@@ -1643,6 +1680,11 @@ fn vpci_path(instance_id: &Guid) -> (String, PathBuf) {
16431680
(pci_id, devpath)
16441681
}
16451682

1683+
fn uio_path(instance_id: &Guid) -> PathBuf {
1684+
// TODO: Is this enough?
1685+
PathBuf::from(format!("/sys/bus/vmbus/devices/{instance_id}/uio"))
1686+
}
1687+
16461688
/// Waits for the PCI path to get populated. The PCI path is just a symlink to the actual
16471689
/// device path. This should be called once the device path is available.
16481690
pub async fn wait_for_pci_path(pci_id: &String) {
@@ -1782,6 +1824,7 @@ impl InitialControllers {
17821824
uevent_listener: &UeventListener,
17831825
dps: &DevicePlatformSettings,
17841826
use_nvme_vfio: bool,
1827+
use_storvsc_usermode: bool,
17851828
is_restoring: bool,
17861829
default_io_queue_depth: u32,
17871830
) -> anyhow::Result<Self> {
@@ -1801,6 +1844,7 @@ impl InitialControllers {
18011844
&mut context,
18021845
uevent_listener,
18031846
use_nvme_vfio,
1847+
use_storvsc_usermode,
18041848
dynamic,
18051849
fixed.scsi_sub_channels,
18061850
is_restoring,
@@ -1851,6 +1895,7 @@ impl InitialControllers {
18511895
scsi_dvds,
18521896
scsi_request,
18531897
use_nvme_vfio,
1898+
use_storvsc_usermode,
18541899
},
18551900
};
18561901

openhcl/underhill_core/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ mod nvme_manager;
2020
mod options;
2121
mod reference_time;
2222
mod servicing;
23+
mod storvsc_manager;
2324
mod threadpool_vm_task_backend;
2425
mod vmbus_relay_unit;
2526
mod vmgs_logger;
@@ -325,6 +326,7 @@ async fn launch_workers(
325326
nvme_keep_alive: opt.nvme_keep_alive,
326327
test_configuration: opt.test_configuration,
327328
disable_uefi_frontpage: opt.disable_uefi_frontpage,
329+
storvsc_usermode: opt.storvsc_usermode,
328330
};
329331

330332
let (mut remote_console_cfg, framebuffer_access) =

openhcl/underhill_core/src/options.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,10 @@ pub struct Options {
147147
/// will result in UEFI terminating, shutting down the guest instead of
148148
/// showing the frontpage.
149149
pub disable_uefi_frontpage: bool,
150+
151+
/// (OPENHCL_STORVSC_USERMODE=1)
152+
/// Use the user-mode storvsc driver instead of the Linux driver.
153+
pub storvsc_usermode: bool,
150154
}
151155

152156
impl Options {
@@ -246,6 +250,7 @@ impl Options {
246250
});
247251
let disable_uefi_frontpage = parse_env_bool("OPENHCL_DISABLE_UEFI_FRONTPAGE");
248252
let signal_vtl0_started = parse_env_bool("OPENHCL_SIGNAL_VTL0_STARTED");
253+
let storvsc_usermode = parse_env_bool("OPENHCL_STORVSC_USERMODE");
249254

250255
let mut args = std::env::args().chain(extra_args);
251256
// Skip our own filename.
@@ -301,6 +306,7 @@ impl Options {
301306
nvme_keep_alive,
302307
test_configuration,
303308
disable_uefi_frontpage,
309+
storvsc_usermode,
304310
})
305311
}
306312

0 commit comments

Comments
 (0)