Skip to content

Commit 1fb1e25

Browse files
gurasinghMSmattkur
andauthored
[disk_delay] A disk wrapper with runtime configurable I/O read and write delays to any underlying disk (#1614)
This change is part of changes for nvme keepalive testing and it will be used in the nvme emulator to induce artificial delays and thus attempt to capture perf of keepalive during servicing. As a long term goal, the functionality in this crate will be expanded to include configurable I/O drops, randomized slowdown and much more in order to make testing of devices easier. --------- Co-authored-by: Matt LaFayette (Kurjanowicz) <mattkur@microsoft.com>
1 parent 79b5118 commit 1fb1e25

File tree

18 files changed

+272
-32
lines changed

18 files changed

+272
-32
lines changed

Cargo.lock

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1144,6 +1144,7 @@ dependencies = [
11441144
"stackfuture",
11451145
"thiserror 2.0.12",
11461146
"vm_resource",
1147+
"vmcore",
11471148
]
11481149

11491150
[[package]]
@@ -1239,6 +1240,22 @@ dependencies = [
12391240
"vm_resource",
12401241
]
12411242

1243+
[[package]]
1244+
name = "disk_delay"
1245+
version = "0.0.0"
1246+
dependencies = [
1247+
"anyhow",
1248+
"async-trait",
1249+
"disk_backend",
1250+
"disk_backend_resources",
1251+
"inspect",
1252+
"mesh",
1253+
"pal_async",
1254+
"scsi_buffers",
1255+
"vm_resource",
1256+
"vmcore",
1257+
]
1258+
12421259
[[package]]
12431260
name = "disk_file"
12441261
version = "0.0.0"
@@ -1286,6 +1303,7 @@ dependencies = [
12861303
"thiserror 2.0.12",
12871304
"tracelimit",
12881305
"vm_resource",
1306+
"vmcore",
12891307
]
12901308

12911309
[[package]]

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ members = [
4646
"vm/loader/igvmfilegen",
4747
"vm/vmgs/vmgs_lib",
4848
"vm/vmgs/vmgstool",
49+
"vm/devices/storage/disk_delay", # Used for internal microsoft testing
4950
]
5051
exclude = [
5152
"xsync",

openhcl/underhill_core/src/dispatch/vtl2_settings_worker.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ use vm_resource::ResourceResolver;
5959
use vm_resource::kind::DiskHandleKind;
6060
use vm_resource::kind::PciDeviceHandleKind;
6161
use vm_resource::kind::VmbusDeviceHandleKind;
62+
use vmcore::vm_task::VmTaskDriverSource;
6263

6364
#[derive(Error, Debug)]
6465
enum Error<'a> {
@@ -552,13 +553,14 @@ pub async fn disk_from_disk_type(
552553
disk_type: Resource<DiskHandleKind>,
553554
read_only: bool,
554555
resolver: &ResourceResolver,
556+
driver_source: &VmTaskDriverSource,
555557
) -> Result<Disk, Vtl2SettingsErrorInfo> {
556558
let disk = resolver
557559
.resolve(
558560
disk_type,
559561
ResolveDiskParameters {
560562
read_only,
561-
_async_trait_workaround: &(),
563+
driver_source,
562564
},
563565
)
564566
.await

openhcl/underhill_core/src/worker.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2215,7 +2215,9 @@ async fn new_underhill_vm(
22152215
read_only,
22162216
disk_parameters,
22172217
} => {
2218-
let disk = disk_from_disk_type(disk_type, read_only, &resolver).await?;
2218+
let disk =
2219+
disk_from_disk_type(disk_type, read_only, &resolver, &driver_source)
2220+
.await?;
22192221
let scsi_disk = Arc::new(scsidisk::SimpleScsiDisk::new(
22202222
disk.clone(),
22212223
disk_parameters.unwrap_or_default(),

openvmm/hvlite_core/src/worker/dispatch.rs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -241,13 +241,14 @@ async fn open_simple_disk(
241241
resolver: &ResourceResolver,
242242
disk_type: Resource<DiskHandleKind>,
243243
read_only: bool,
244+
driver_source: &VmTaskDriverSource,
244245
) -> anyhow::Result<Disk> {
245246
let disk = resolver
246247
.resolve(
247248
disk_type,
248249
ResolveDiskParameters {
249250
read_only,
250-
_async_trait_workaround: &(),
251+
driver_source,
251252
},
252253
)
253254
.await?;
@@ -968,7 +969,7 @@ impl InitializedVm {
968969
let vmgs = match cfg.vmgs {
969970
Some(VmgsResource::Disk(disk)) => Some(
970971
vmgs::Vmgs::try_open(
971-
open_simple_disk(&resolver, disk, false).await?,
972+
open_simple_disk(&resolver, disk, false, &driver_source).await?,
972973
None,
973974
true,
974975
false,
@@ -978,7 +979,7 @@ impl InitializedVm {
978979
),
979980
Some(VmgsResource::ReprovisionOnFailure(disk)) => Some(
980981
vmgs::Vmgs::try_open(
981-
open_simple_disk(&resolver, disk, false).await?,
982+
open_simple_disk(&resolver, disk, false, &driver_source).await?,
982983
None,
983984
true,
984985
true,
@@ -987,9 +988,12 @@ impl InitializedVm {
987988
.context("failed to open vmgs file")?,
988989
),
989990
Some(VmgsResource::Reprovision(disk)) => Some(
990-
vmgs::Vmgs::format_new(open_simple_disk(&resolver, disk, false).await?, None)
991-
.await
992-
.context("failed to format vmgs file")?,
991+
vmgs::Vmgs::format_new(
992+
open_simple_disk(&resolver, disk, false, &driver_source).await?,
993+
None,
994+
)
995+
.await
996+
.context("failed to format vmgs file")?,
993997
),
994998
Some(VmgsResource::Ephemeral) => None,
995999
// TODO: make sure we don't need a VMGS
@@ -1284,9 +1288,10 @@ impl InitializedVm {
12841288
read_only,
12851289
disk_parameters,
12861290
} => {
1287-
let disk = open_simple_disk(&resolver, disk_type, read_only)
1288-
.await
1289-
.context("failed to open IDE disk")?;
1291+
let disk =
1292+
open_simple_disk(&resolver, disk_type, read_only, &driver_source)
1293+
.await
1294+
.context("failed to open IDE disk")?;
12901295

12911296
// Only disks get accelerator channels. DVDs dont.
12921297
let scsi_disk = ScsiControllerDisk::new(Arc::new(SimpleScsiDisk::new(
@@ -1392,7 +1397,7 @@ impl InitializedVm {
13921397
read_only,
13931398
} = disk_cfg;
13941399

1395-
let disk = open_simple_disk(&resolver, disk_type, read_only)
1400+
let disk = open_simple_disk(&resolver, disk_type, read_only, &driver_source)
13961401
.await
13971402
.context("failed to open floppy disk")?;
13981403
tracing::trace!("floppy opened based on config into DriveRibbon");

vm/devices/get/guest_emulation_device/src/resolver.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ impl AsyncResolveResource<VmbusDeviceHandleKind, GuestEmulationDeviceHandle>
8888
disk,
8989
ResolveDiskParameters {
9090
read_only: false,
91-
_async_trait_workaround: &(),
91+
driver_source: input.driver_source,
9292
},
9393
)
9494
.await

vm/devices/storage/disk_backend/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ rust-version.workspace = true
88

99
[dependencies]
1010
scsi_buffers.workspace = true
11+
vmcore.workspace = true
1112

1213
guestmem.workspace = true
1314
vm_resource.workspace = true

vm/devices/storage/disk_backend/src/resolve.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use crate::DiskIo;
88
use crate::InvalidDisk;
99
use vm_resource::CanResolveTo;
1010
use vm_resource::kind::DiskHandleKind;
11+
use vmcore::vm_task::VmTaskDriverSource;
1112

1213
impl CanResolveTo<ResolvedDisk> for DiskHandleKind {
1314
type Input<'a> = ResolveDiskParameters<'a>;
@@ -18,11 +19,8 @@ impl CanResolveTo<ResolvedDisk> for DiskHandleKind {
1819
pub struct ResolveDiskParameters<'a> {
1920
/// Whether the disk is being opened for read-only use.
2021
pub read_only: bool,
21-
#[doc(hidden)]
22-
// Workaround for async_trait not working well with GAT input parameters
23-
// with missing lifetimes. Remove once we stop using async_trait for async
24-
// resolvers.
25-
pub _async_trait_workaround: &'a (),
22+
/// The task driver source for the VM.
23+
pub driver_source: &'a VmTaskDriverSource,
2624
}
2725

2826
/// A resolved [`Disk`].

vm/devices/storage/disk_backend_resources/src/lib.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77

88
pub mod layer;
99

10+
use mesh::Cell;
1011
use mesh::MeshPayload;
12+
use std::time::Duration;
1113
use vm_resource::IntoResource;
1214
use vm_resource::Resource;
1315
use vm_resource::ResourceId;
@@ -33,6 +35,19 @@ impl ResourceId<DiskHandleKind> for DiskWithReservationsHandle {
3335
const ID: &'static str = "prwrap";
3436
}
3537

38+
/// Disk handle for a delay disk.
39+
#[derive(MeshPayload)]
40+
pub struct DelayDiskHandle {
41+
/// The underlying disk resource.
42+
pub disk: Resource<DiskHandleKind>,
43+
/// The delay to add to each I/O operation.
44+
pub delay: Cell<Duration>,
45+
}
46+
47+
impl ResourceId<DiskHandleKind> for DelayDiskHandle {
48+
const ID: &'static str = "delay";
49+
}
50+
3651
/// Disk handle for a fixed VHD1 disk.
3752
#[derive(MeshPayload)]
3853
pub struct FixedVhd1DiskHandle(pub std::fs::File);

vm/devices/storage/disk_crypt/src/resolver.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ impl AsyncResolveResource<DiskHandleKind, DiskCryptHandle> for DiskCryptResolver
5353
resource.disk,
5454
ResolveDiskParameters {
5555
read_only: input.read_only,
56-
_async_trait_workaround: &(),
56+
driver_source: input.driver_source,
5757
},
5858
)
5959
.await

0 commit comments

Comments
 (0)