1#![forbid(unsafe_code)]
7
8pub mod resolver;
9
10use anyhow::Context;
11use disk_backend::Disk;
12use disk_backend::DiskError;
13use disk_backend::UnmapBehavior;
14use disk_layered::DiskLayer;
15use disk_layered::LayerAttach;
16use disk_layered::LayerConfiguration;
17use disk_layered::LayerIo;
18use disk_layered::LayeredDisk;
19use disk_layered::SectorMarker;
20use disk_layered::WriteNoOverwrite;
21use guestmem::MemoryRead;
22use guestmem::MemoryWrite;
23use inspect::Inspect;
24use parking_lot::RwLock;
25use scsi_buffers::RequestBuffers;
26use std::collections::BTreeMap;
27use std::collections::btree_map::Entry;
28use std::fmt;
29use std::fmt::Debug;
30use std::sync::atomic::AtomicU64;
31use std::sync::atomic::Ordering;
32use thiserror::Error;
33
34pub const DEFAULT_SECTOR_SIZE: u32 = 512;
36
37pub struct LazyRamDiskLayer {
40 len: Option<u64>,
41 sector_size: Option<u32>,
42}
43
44impl LazyRamDiskLayer {
45 pub fn new() -> Self {
51 Self {
52 len: None,
53 sector_size: None,
54 }
55 }
56
57 pub fn with_len(mut self, len: u64) -> Self {
61 self.len = Some(len);
62 self
63 }
64
65 pub fn with_sector_size(mut self, sector_size: u32) -> Self {
70 self.sector_size = Some(sector_size);
71 self
72 }
73}
74
75#[derive(Inspect)]
77#[inspect(extra = "Self::inspect_extra")]
78pub struct RamDiskLayer {
79 #[inspect(flatten)]
80 state: RwLock<RamState>,
81 #[inspect(skip)]
82 sector_count: AtomicU64,
83 #[inspect(skip)]
84 resize_event: event_listener::Event,
85 sector_size: u32,
86 #[inspect(skip)]
87 sector_shift: u32,
88}
89
90#[derive(Inspect)]
91struct RamState {
92 #[inspect(skip)]
93 data: BTreeMap<u64, Box<[u8]>>,
94 #[inspect(skip)] sector_count: u64,
96 zero_after: u64,
97}
98
99impl RamDiskLayer {
100 fn inspect_extra(&self, resp: &mut inspect::Response<'_>) {
101 resp.field_with("committed_size", || {
102 self.state.read().data.len() * self.sector_size as usize
103 })
104 .field_mut_with("sector_count", |new_count| {
105 if let Some(new_count) = new_count {
106 self.resize(new_count.parse().context("invalid sector count")?)?;
107 }
108 anyhow::Ok(self.sector_count())
109 });
110 }
111}
112
113impl Debug for RamDiskLayer {
114 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115 f.debug_struct("RamDiskLayer")
116 .field("sector_count", &self.sector_count)
117 .finish()
118 }
119}
120
121#[derive(Error, Debug)]
123pub enum Error {
124 #[error("disk size {disk_size:#x} is not a multiple of the sector size {sector_size}")]
126 NotSectorMultiple {
127 disk_size: u64,
129 sector_size: u32,
131 },
132 #[error("disk has no sectors")]
134 EmptyDisk,
135 #[error("sector size {0} is not a power-of-two >= 512")]
137 InvalidSectorSize(u32),
138}
139
140impl RamDiskLayer {
141 pub fn new(size: u64) -> Result<Self, Error> {
143 Self::new_with_sector_size(size, DEFAULT_SECTOR_SIZE)
144 }
145
146 pub fn new_with_sector_size(size: u64, sector_size: u32) -> Result<Self, Error> {
150 if !sector_size.is_power_of_two() || sector_size < DEFAULT_SECTOR_SIZE {
151 return Err(Error::InvalidSectorSize(sector_size));
152 }
153 let sector_shift = sector_size.trailing_zeros();
154 let sector_count = {
155 if size == 0 {
156 return Err(Error::EmptyDisk);
157 }
158 if !size.is_multiple_of(sector_size as u64) {
159 return Err(Error::NotSectorMultiple {
160 disk_size: size,
161 sector_size,
162 });
163 }
164 size >> sector_shift
165 };
166 Ok(Self {
167 state: RwLock::new(RamState {
168 data: BTreeMap::new(),
169 sector_count,
170 zero_after: sector_count,
171 }),
172 sector_count: sector_count.into(),
173 resize_event: Default::default(),
174 sector_size,
175 sector_shift,
176 })
177 }
178
179 fn resize(&self, new_sector_count: u64) -> anyhow::Result<()> {
180 if new_sector_count == 0 {
181 anyhow::bail!("invalid sector count");
182 }
183 let _removed = {
185 let mut state = self.state.write();
186 state.zero_after = new_sector_count.min(state.zero_after);
188 state.sector_count = new_sector_count;
189 self.sector_count.store(new_sector_count, Ordering::Relaxed);
194 state.data.split_off(&new_sector_count)
195 };
196 self.resize_event.notify(usize::MAX);
197 Ok(())
198 }
199
200 fn write_maybe_overwrite(
201 &self,
202 buffers: &RequestBuffers<'_>,
203 sector: u64,
204 overwrite: bool,
205 ) -> Result<(), DiskError> {
206 let sector_bytes = self.sector_size as usize;
207 let count = buffers.len() >> self.sector_shift;
208 tracing::trace!(sector, count, "write");
209 let mut state = self.state.write();
210 if sector + count as u64 > state.sector_count {
211 return Err(DiskError::IllegalBlock);
212 }
213 for i in 0..count {
214 let cur = sector + i as u64;
215 let buf = buffers.subrange(i << self.sector_shift, sector_bytes);
216 let mut reader = buf.reader();
217 match state.data.entry(cur) {
218 Entry::Vacant(entry) => {
219 let mut data = vec![0u8; sector_bytes].into_boxed_slice();
220 reader.read(&mut data)?;
221 entry.insert(data);
222 }
223 Entry::Occupied(mut entry) => {
224 if overwrite {
225 reader.read(entry.get_mut())?;
226 }
227 }
228 }
229 }
230 Ok(())
231 }
232}
233
234impl LayerAttach for LazyRamDiskLayer {
235 type Error = Error;
236 type Layer = RamDiskLayer;
237
238 async fn attach(
239 self,
240 lower_layer_metadata: Option<disk_layered::DiskLayerMetadata>,
241 ) -> Result<Self::Layer, Self::Error> {
242 let sector_size = self
243 .sector_size
244 .or(lower_layer_metadata.as_ref().map(|meta| meta.sector_size))
245 .unwrap_or(DEFAULT_SECTOR_SIZE);
246 let total_size = match self.len {
247 Some(len) => len,
248 None => {
249 let meta = lower_layer_metadata.ok_or(Error::EmptyDisk)?;
250 meta.sector_count * meta.sector_size as u64
251 }
252 };
253 RamDiskLayer::new_with_sector_size(total_size, sector_size)
254 }
255}
256
257impl LayerIo for RamDiskLayer {
258 fn layer_type(&self) -> &str {
259 "ram"
260 }
261
262 fn sector_count(&self) -> u64 {
263 self.sector_count.load(Ordering::Relaxed)
264 }
265
266 fn sector_size(&self) -> u32 {
267 self.sector_size
268 }
269
270 fn is_logically_read_only(&self) -> bool {
271 false
272 }
273
274 fn disk_id(&self) -> Option<[u8; 16]> {
275 None
276 }
277
278 fn physical_sector_size(&self) -> u32 {
279 self.sector_size
280 }
281
282 fn is_fua_respected(&self) -> bool {
283 true
284 }
285
286 async fn read(
287 &self,
288 buffers: &RequestBuffers<'_>,
289 sector: u64,
290 mut marker: SectorMarker<'_>,
291 ) -> Result<(), DiskError> {
292 let sector_bytes = self.sector_size as usize;
293 let count = (buffers.len() >> self.sector_shift) as u64;
294 let end = sector + count;
295 tracing::trace!(sector, count, "read");
296 let state = self.state.read();
297 if end > state.sector_count {
298 return Err(DiskError::IllegalBlock);
299 }
300 let mut range = state.data.range(sector..end);
301 let mut last = sector;
302 while last < end {
303 let r = range.next();
304 let next = r.map(|(&s, _)| s).unwrap_or(end);
305 if next > last && next > state.zero_after {
306 let zero_start = last.max(state.zero_after);
309 let zero_count = next - zero_start;
310 let offset = ((zero_start - sector) as usize) << self.sector_shift;
311 let len = (zero_count as usize) << self.sector_shift;
312 buffers.subrange(offset, len).writer().zero(len)?;
313 marker.set_range(zero_start..next);
314 }
315 if let Some((&s, buf)) = r {
316 let offset = ((s - sector) as usize) << self.sector_shift;
317 buffers.subrange(offset, sector_bytes).writer().write(buf)?;
318
319 marker.set(s);
320 }
321 last = next;
322 }
323 Ok(())
324 }
325
326 async fn write(
327 &self,
328 buffers: &RequestBuffers<'_>,
329 sector: u64,
330 _fua: bool,
331 ) -> Result<(), DiskError> {
332 self.write_maybe_overwrite(buffers, sector, true)
333 }
334
335 fn write_no_overwrite(&self) -> Option<impl WriteNoOverwrite> {
336 Some(self)
337 }
338
339 async fn sync_cache(&self) -> Result<(), DiskError> {
340 tracing::trace!("sync_cache");
341 Ok(())
342 }
343
344 async fn wait_resize(&self, sector_count: u64) -> u64 {
345 loop {
346 let listen = self.resize_event.listen();
347 let current = self.sector_count();
348 if current != sector_count {
349 break current;
350 }
351 listen.await;
352 }
353 }
354
355 async fn unmap(
356 &self,
357 sector_offset: u64,
358 sector_count: u64,
359 _block_level_only: bool,
360 next_is_zero: bool,
361 ) -> Result<(), DiskError> {
362 tracing::trace!(sector_offset, sector_count, "unmap");
363 let mut state = self.state.write();
364 if sector_offset + sector_count > state.sector_count {
365 return Err(DiskError::IllegalBlock);
366 }
367 if !next_is_zero {
368 if sector_offset + sector_count < state.zero_after {
371 return Ok(());
372 }
373 state.zero_after = state.zero_after.min(sector_offset);
376 }
377 let end = sector_offset + sector_count;
378 if sector_offset < end {
379 state
380 .data
381 .extract_if(sector_offset..end, |_, _| true)
382 .for_each(drop);
383 }
384 Ok(())
385 }
386
387 fn unmap_behavior(&self) -> UnmapBehavior {
388 UnmapBehavior::Unspecified
391 }
392
393 fn optimal_unmap_sectors(&self) -> u32 {
394 1
395 }
396}
397
398impl WriteNoOverwrite for RamDiskLayer {
399 async fn write_no_overwrite(
400 &self,
401 buffers: &RequestBuffers<'_>,
402 sector: u64,
403 ) -> Result<(), DiskError> {
404 self.write_maybe_overwrite(buffers, sector, false)
405 }
406}
407
408pub fn ram_disk(size: u64, read_only: bool) -> anyhow::Result<Disk> {
414 ram_disk_with_sector_size(size, read_only, DEFAULT_SECTOR_SIZE)
415}
416
417pub fn ram_disk_with_sector_size(
422 size: u64,
423 read_only: bool,
424 sector_size: u32,
425) -> anyhow::Result<Disk> {
426 use futures::future::FutureExt;
427
428 let disk = Disk::new(
429 LayeredDisk::new(
430 read_only,
431 vec![LayerConfiguration {
432 layer: DiskLayer::new(RamDiskLayer::new_with_sector_size(size, sector_size)?),
433 write_through: false,
434 read_cache: false,
435 }],
436 )
437 .now_or_never()
438 .expect("RamDiskLayer won't block")?,
439 )?;
440
441 Ok(disk)
442}
443
444#[cfg(test)]
445mod tests {
446 use super::RamDiskLayer;
447 use disk_backend::DiskIo;
448 use disk_layered::DiskLayer;
449 use disk_layered::LayerConfiguration;
450 use disk_layered::LayerIo;
451 use disk_layered::LayeredDisk;
452 use guestmem::GuestMemory;
453 use pal_async::async_test;
454 use scsi_buffers::OwnedRequestBuffers;
455 use test_with_tracing::test;
456 use zerocopy::IntoBytes;
457
458 const SECTOR_SIZE: u32 = 512;
459 const SECTOR_U64: u64 = SECTOR_SIZE as u64;
460 const SECTOR_USIZE: usize = SECTOR_SIZE as usize;
461
462 const CONFORMANCE_DISK_SIZE: u64 = 1024 * 1024;
463
464 #[async_test]
465 async fn sector_range_conformance() {
466 let disk = crate::ram_disk(CONFORMANCE_DISK_SIZE, false).unwrap();
467 storage_tests::sector_range::test_disk_sector_range_conformance(&disk).await;
468 }
469
470 #[async_test]
472 async fn sector_range_conformance_4k() {
473 let disk = crate::ram_disk_with_sector_size(CONFORMANCE_DISK_SIZE, false, 4096).unwrap();
474 storage_tests::sector_range::test_disk_representability(&disk).await;
475 }
476
477 #[async_test]
480 async fn layer_sector_range_conformance() {
481 let layer = RamDiskLayer::new(CONFORMANCE_DISK_SIZE).unwrap();
482 storage_tests::sector_range::test_layer_sector_range(&layer).await;
483 }
484
485 fn check(mem: &GuestMemory, sector: u64, start: usize, count: usize, high: u8) {
486 let mut buf = vec![0u32; count * SECTOR_USIZE / 4];
487 mem.read_at(start as u64 * SECTOR_U64, buf.as_mut_bytes())
488 .unwrap();
489 for (i, &b) in buf.iter().enumerate() {
490 let offset = sector * SECTOR_U64 + i as u64 * 4;
491 let expected = (offset as u32 / 4) | ((high as u32) << 24);
492 assert!(
493 b == expected,
494 "at sector {}, word {}, got {:#x}, expected {:#x}",
495 offset / SECTOR_U64,
496 (offset % SECTOR_U64) / 4,
497 b,
498 expected
499 );
500 }
501 }
502
503 async fn read(mem: &GuestMemory, disk: &mut impl DiskIo, sector: u64, count: usize) {
504 disk.read_vectored(
505 &OwnedRequestBuffers::linear(0, count * SECTOR_USIZE, true).buffer(mem),
506 sector,
507 )
508 .await
509 .unwrap();
510 }
511
512 async fn write_layer(
513 mem: &GuestMemory,
514 disk: &mut impl LayerIo,
515 sector: u64,
516 count: usize,
517 high: u8,
518 ) {
519 let buf: Vec<_> = (sector * SECTOR_U64 / 4..(sector + count as u64) * SECTOR_U64 / 4)
520 .map(|x| x as u32 | ((high as u32) << 24))
521 .collect();
522 let len = SECTOR_USIZE * count;
523 mem.write_at(0, &buf.as_bytes()[..len]).unwrap();
524
525 disk.write(
526 &OwnedRequestBuffers::linear(0, len, false).buffer(mem),
527 sector,
528 false,
529 )
530 .await
531 .unwrap();
532 }
533
534 async fn write(mem: &GuestMemory, disk: &mut impl DiskIo, sector: u64, count: usize, high: u8) {
535 let buf: Vec<_> = (sector * SECTOR_U64 / 4..(sector + count as u64) * SECTOR_U64 / 4)
536 .map(|x| x as u32 | ((high as u32) << 24))
537 .collect();
538 let len = SECTOR_USIZE * count;
539 mem.write_at(0, &buf.as_bytes()[..len]).unwrap();
540
541 disk.write_vectored(
542 &OwnedRequestBuffers::linear(0, len, false).buffer(mem),
543 sector,
544 false,
545 )
546 .await
547 .unwrap();
548 }
549
550 async fn prep_disk(size: usize) -> (GuestMemory, LayeredDisk) {
551 let guest_mem = GuestMemory::allocate(size);
552 let mut lower = RamDiskLayer::new(size as u64).unwrap();
553 write_layer(&guest_mem, &mut lower, 0, size / SECTOR_USIZE, 0).await;
554 let upper = RamDiskLayer::new(size as u64).unwrap();
555 let upper = LayeredDisk::new(
556 false,
557 Vec::from_iter([upper, lower].map(|layer| LayerConfiguration {
558 layer: DiskLayer::new(layer),
559 write_through: false,
560 read_cache: false,
561 })),
562 )
563 .await
564 .unwrap();
565 (guest_mem, upper)
566 }
567
568 #[async_test]
569 async fn diff() {
570 const SIZE: usize = 1024 * 1024;
571
572 let (guest_mem, mut upper) = prep_disk(SIZE).await;
573 read(&guest_mem, &mut upper, 10, 2).await;
574 check(&guest_mem, 10, 0, 2, 0);
575 write(&guest_mem, &mut upper, 10, 2, 1).await;
576 write(&guest_mem, &mut upper, 11, 1, 2).await;
577 read(&guest_mem, &mut upper, 9, 5).await;
578 check(&guest_mem, 9, 0, 1, 0);
579 check(&guest_mem, 10, 1, 1, 1);
580 check(&guest_mem, 11, 2, 1, 2);
581 check(&guest_mem, 12, 3, 1, 0);
582 }
583
584 async fn resize(disk: &LayeredDisk, new_size: u64) {
585 let inspect::ValueKind::Unsigned(v) =
586 inspect::update("layers/0/backing/sector_count", &new_size.to_string(), disk)
587 .await
588 .unwrap()
589 .kind
590 else {
591 panic!("bad inspect value")
592 };
593 assert_eq!(new_size, v);
594 }
595
596 #[async_test]
597 async fn test_resize() {
598 const SIZE: usize = 1024 * 1024;
599 const SECTORS: usize = SIZE / SECTOR_USIZE;
600
601 let (guest_mem, mut upper) = prep_disk(SIZE).await;
602 check(&guest_mem, 0, 0, SECTORS, 0);
603 resize(&upper, SECTORS as u64 / 2).await;
604 resize(&upper, SECTORS as u64).await;
605 read(&guest_mem, &mut upper, 0, SECTORS).await;
606 check(&guest_mem, 0, 0, SECTORS / 2, 0);
607 for s in SECTORS / 2..SECTORS {
608 let mut buf = [0u8; SECTOR_USIZE];
609 guest_mem.read_at(s as u64 * SECTOR_U64, &mut buf).unwrap();
610 assert_eq!(buf, [0u8; SECTOR_USIZE]);
611 }
612 }
613
614 #[async_test]
615 async fn test_unmap() {
616 const SIZE: usize = 1024 * 1024;
617 const SECTORS: usize = SIZE / SECTOR_USIZE;
618
619 let (guest_mem, mut upper) = prep_disk(SIZE).await;
620 upper.unmap(0, SECTORS as u64 - 1, false).await.unwrap();
621 read(&guest_mem, &mut upper, 0, SECTORS).await;
622 check(&guest_mem, 0, 0, SECTORS, 0);
623 upper
624 .unmap(SECTORS as u64 / 2, SECTORS as u64 / 2, false)
625 .await
626 .unwrap();
627 read(&guest_mem, &mut upper, 0, SECTORS).await;
628 check(&guest_mem, 0, 0, SECTORS / 2, 0);
629 for s in SECTORS / 2..SECTORS {
630 let mut buf = [0u8; SECTOR_USIZE];
631 guest_mem.read_at(s as u64 * SECTOR_U64, &mut buf).unwrap();
632 assert_eq!(buf, [0u8; SECTOR_USIZE]);
633 }
634 }
635
636 #[async_test]
637 async fn test_unmap_sparse_range() {
638 let guest_mem = GuestMemory::allocate(SECTOR_USIZE);
639 for (offset, count, expected) in [
640 (1, 0, &[0, 2, 4, 7][..]),
641 (1, 1, &[0, 2, 4, 7][..]),
642 (2, 2, &[0, 4, 7][..]),
643 (1, 6, &[0, 7][..]),
644 (0, 8, &[][..]),
645 (8, 0, &[0, 2, 4, 7][..]),
646 ] {
647 let mut layer = RamDiskLayer::new(8 * SECTOR_U64).unwrap();
648 for sector in [0, 2, 4, 7] {
649 write_layer(&guest_mem, &mut layer, sector, 1, 0).await;
650 }
651
652 layer.unmap(offset, count, false, true).await.unwrap();
653
654 assert_eq!(
655 layer.state.read().data.keys().copied().collect::<Vec<_>>(),
656 expected,
657 "unmap {offset}..{}",
658 offset + count,
659 );
660 }
661 }
662
663 #[async_test]
664 async fn test_4096_sector_write_read() {
665 const SECTOR_4K: usize = 4096;
666 const DISK_SIZE: u64 = 1024 * 1024; const SECTOR_COUNT: u64 = DISK_SIZE / SECTOR_4K as u64;
668
669 let layer = RamDiskLayer::new_with_sector_size(DISK_SIZE, 4096).unwrap();
670 assert_eq!(layer.sector_size(), 4096);
671 assert_eq!(layer.physical_sector_size(), 4096);
672 assert_eq!(layer.sector_count(), SECTOR_COUNT);
673
674 let guest_mem = GuestMemory::allocate(SECTOR_4K * 2);
675
676 let pattern: Vec<u8> = (0..SECTOR_4K).map(|i| (i % 251) as u8).collect();
678 guest_mem.write_at(0, &pattern).unwrap();
679 let bufs = OwnedRequestBuffers::linear(0, SECTOR_4K, false);
680 layer
681 .write(&bufs.buffer(&guest_mem), 0, false)
682 .await
683 .unwrap();
684
685 let disk = LayeredDisk::new(
687 false,
688 vec![LayerConfiguration {
689 layer: DiskLayer::new(layer),
690 write_through: false,
691 read_cache: false,
692 }],
693 )
694 .await
695 .unwrap();
696
697 guest_mem.write_at(0, &vec![0u8; SECTOR_4K]).unwrap();
699 disk.read_vectored(
700 &OwnedRequestBuffers::linear(0, SECTOR_4K, true).buffer(&guest_mem),
701 0,
702 )
703 .await
704 .unwrap();
705
706 let mut readback = vec![0u8; SECTOR_4K];
707 guest_mem.read_at(0, &mut readback).unwrap();
708 assert_eq!(readback, pattern);
709 }
710
711 #[test]
712 fn test_sector_count_4096() {
713 let layer = RamDiskLayer::new_with_sector_size(1024 * 1024, 4096).unwrap();
714 assert_eq!(layer.sector_count(), 256); }
716
717 #[test]
718 fn test_invalid_sector_size_not_power_of_two() {
719 let err = RamDiskLayer::new_with_sector_size(4096, 1000).unwrap_err();
720 assert!(matches!(err, super::Error::InvalidSectorSize(1000)));
721 }
722
723 #[test]
724 fn test_invalid_sector_size_too_small() {
725 let err = RamDiskLayer::new_with_sector_size(4096, 256).unwrap_err();
726 assert!(matches!(err, super::Error::InvalidSectorSize(256)));
727 }
728
729 #[test]
730 fn test_invalid_disk_size_not_multiple() {
731 let err = RamDiskLayer::new_with_sector_size(5000, 4096).unwrap_err();
732 assert!(matches!(
733 err,
734 super::Error::NotSectorMultiple {
735 disk_size: 5000,
736 sector_size: 4096
737 }
738 ));
739 }
740
741 #[async_test]
742 async fn test_lazy_inherits_sector_size() {
743 let lower = RamDiskLayer::new_with_sector_size(1024 * 1024, 4096).unwrap();
744 let upper = LayeredDisk::new(
745 false,
746 vec![
747 LayerConfiguration {
748 layer: DiskLayer::new(super::LazyRamDiskLayer::new()),
749 write_through: false,
750 read_cache: false,
751 },
752 LayerConfiguration {
753 layer: DiskLayer::new(lower),
754 write_through: false,
755 read_cache: false,
756 },
757 ],
758 )
759 .await
760 .unwrap();
761
762 assert_eq!(upper.sector_size(), 4096);
763 assert_eq!(upper.sector_count(), 256);
764 }
765
766 #[async_test]
767 async fn test_mismatched_sector_sizes_rejected() {
768 const DISK_SIZE: u64 = 1024 * 1024;
769
770 let result = LayeredDisk::new(
772 false,
773 vec![
774 LayerConfiguration {
775 layer: DiskLayer::new(
776 RamDiskLayer::new_with_sector_size(DISK_SIZE, 4096).unwrap(),
777 ),
778 write_through: false,
779 read_cache: false,
780 },
781 LayerConfiguration {
782 layer: DiskLayer::new(RamDiskLayer::new(DISK_SIZE).unwrap()),
783 write_through: false,
784 read_cache: false,
785 },
786 ],
787 )
788 .await;
789 assert!(result.is_err());
790
791 let result = LayeredDisk::new(
793 false,
794 vec![
795 LayerConfiguration {
796 layer: DiskLayer::new(RamDiskLayer::new(DISK_SIZE).unwrap()),
797 write_through: false,
798 read_cache: false,
799 },
800 LayerConfiguration {
801 layer: DiskLayer::new(
802 RamDiskLayer::new_with_sector_size(DISK_SIZE, 4096).unwrap(),
803 ),
804 write_through: false,
805 read_cache: false,
806 },
807 ],
808 )
809 .await;
810 assert!(result.is_err());
811 }
812}