Skip to main content

imago/storage/
mod.rs

1//! Helper functionality to access storage.
2//!
3//! While not the primary purpose of this crate, to open VM images, we need to be able to access
4//! different kinds of storage objects.  Such objects are abstracted behind the `Storage` trait.
5
6pub mod drivers;
7pub mod ext;
8
9use crate::io_buffers::{IoBuffer, IoVector, IoVectorMut};
10use drivers::CommonStorageHelper;
11use maybe_async::maybe_async;
12use std::any::Any;
13use std::fmt::{Debug, Display};
14#[cfg(feature = "async")]
15use std::future::Future;
16use std::path::{Path, PathBuf};
17#[cfg(feature = "async")]
18use std::pin::Pin;
19use std::sync::Arc;
20use std::{cmp, io};
21
22/// Parameters from which a storage object can be constructed.
23#[derive(Clone, Debug, Default)]
24pub struct StorageOpenOptions {
25    /// Filename to open.
26    pub(crate) filename: Option<PathBuf>,
27
28    /// Whether the object should be opened as writable or read-only.
29    pub(crate) writable: bool,
30
31    /// Whether to bypass the host page cache (if applicable).
32    pub(crate) direct: bool,
33
34    /// macOS-only: Use fsync() instead of F_FULLFSYNC on `sync()` method.
35    #[cfg(target_os = "macos")]
36    pub(crate) relaxed_sync: bool,
37}
38
39/// Parameters from which a new storage object can be created.
40#[derive(Clone, Debug)]
41pub struct StorageCreateOptions {
42    /// Options to open the image, includes the filename.
43    ///
44    /// `writable` should be ignored, created files should always be opened as writable.
45    pub(crate) open_opts: StorageOpenOptions,
46
47    /// Initial size.
48    pub(crate) size: u64,
49
50    /// Preallocation mode.
51    pub(crate) prealloc_mode: PreallocateMode,
52
53    /// Whether to overwrite an existing file.
54    pub(crate) overwrite: bool,
55}
56
57/// Implementation for storage objects.
58#[maybe_async(AFIT)]
59pub trait Storage: Debug + Display + Send + Sized + Sync {
60    /// Open a storage object.
61    ///
62    /// Different storage implementations may require different options.
63    #[allow(async_fn_in_trait)] // No need for Send
64    async fn open(_opts: StorageOpenOptions) -> io::Result<Self> {
65        Err(io::Error::new(
66            io::ErrorKind::Unsupported,
67            format!(
68                "Cannot open storage objects of type {}",
69                std::any::type_name::<Self>()
70            ),
71        ))
72    }
73
74    /// Synchronous wrapper around [`Storage::open()`].
75    #[cfg(feature = "sync-wrappers")]
76    fn open_sync(opts: StorageOpenOptions) -> io::Result<Self> {
77        tokio::runtime::Builder::new_current_thread()
78            .build()?
79            .block_on(Self::open(opts))
80    }
81
82    /// Create a storage object and open it.
83    ///
84    /// Different storage implementations may require different options.
85    ///
86    /// Note that newly created storage objects are always opened as writable.
87    #[allow(async_fn_in_trait)] // No need for Send
88    async fn create_open(_opts: StorageCreateOptions) -> io::Result<Self> {
89        Err(io::Error::new(
90            io::ErrorKind::Unsupported,
91            format!(
92                "Cannot create storage objects of type {}",
93                std::any::type_name::<Self>()
94            ),
95        ))
96    }
97
98    /// Create a storage object.
99    ///
100    /// Different storage implementations may require different options.
101    #[allow(async_fn_in_trait)] // No need for Send
102    async fn create(opts: StorageCreateOptions) -> io::Result<()> {
103        Self::create_open(opts).await?;
104        Ok(())
105    }
106
107    /// Minimum required alignment for memory buffers.
108    fn mem_align(&self) -> usize {
109        1
110    }
111
112    /// Minimum required alignment for offsets and lengths.
113    fn req_align(&self) -> usize {
114        1
115    }
116
117    /// Minimum required alignment for zero writes.
118    ///
119    /// Must be a multiple of [`Self::req_align()`].
120    fn zero_align(&self) -> usize {
121        self.req_align()
122    }
123
124    /// Minimum required alignment for effective discards.
125    ///
126    /// Must be a multiple of [`Self::req_align()`].
127    fn discard_align(&self) -> usize {
128        self.req_align()
129    }
130
131    /// Storage object length.
132    fn size(&self) -> io::Result<u64>;
133
134    /// Resolve the given path relative to this storage object.
135    ///
136    /// `relative` need not really be a relative path; it is up to the storage driver to check
137    /// whether it is an absolute path that does not need to be changed, or a relative path that
138    /// needs to be resolved.
139    ///
140    /// Must not return a relative path.
141    ///
142    /// The returned `PathBuf` should be usable with `StorageOpenOptions::filename()`.
143    fn resolve_relative_path<P: AsRef<Path>>(&self, _relative: P) -> io::Result<PathBuf> {
144        Err(io::ErrorKind::Unsupported.into())
145    }
146
147    /// Return a filename, if possible.
148    ///
149    /// Using the filename for [`StorageOpenOptions::filename()`] should open the same storage
150    /// object.
151    fn get_filename(&self) -> Option<PathBuf> {
152        None
153    }
154
155    /// Read data at `offset` into `bufv`.
156    ///
157    /// Reads until `bufv` is filled completely, i.e. will not do short reads.  When reaching the
158    /// end of file, the rest of `bufv` is filled with 0.
159    ///
160    /// # Safety
161    /// This is a pure read from storage.  The request must be fully aligned to
162    /// [`Self::mem_align()`] and [`Self::req_align()`], and safeguards we want to implement for
163    /// safe concurrent access may not be available.
164    ///
165    /// Use [`StorageExt::readv()`](crate::StorageExt::readv()) instead.
166    #[allow(async_fn_in_trait)] // No need for Send
167    async unsafe fn pure_readv(&self, bufv: IoVectorMut<'_>, offset: u64) -> io::Result<()>;
168
169    /// Write data from `bufv` to `offset`.
170    ///
171    /// Writes all data from `bufv`, i.e. will not do short writes.  When reaching the end of file,
172    /// grow it as necessary so that the new end of file will be at `offset + bufv.len()`.
173    ///
174    /// If growing is not possible, writes beyond the end of file (even if only partially) should
175    /// fail.
176    ///
177    /// # Safety
178    /// This is a pure write to storage.  The request must be fully aligned to
179    /// [`Self::mem_align()`] and [`Self::req_align()`], and safeguards we want to implement for
180    /// safe concurrent access may not be available.
181    ///
182    /// Use [`StorageExt::writev()`](crate::StorageExt::writev()) instead.
183    #[allow(async_fn_in_trait)] // No need for Send
184    async unsafe fn pure_writev(&self, bufv: IoVector<'_>, offset: u64) -> io::Result<()>;
185
186    /// Ensure the given range reads back as zeroes.
187    ///
188    /// The default implementation writes actual zeroes as data via [`Storage::pure_writev()`],
189    /// which is inefficient.  Storage drivers should override it with a more efficient
190    /// implementation.
191    ///
192    /// Because the default implementation uses [`Storage::pure_writev()`], offset and length
193    /// must also be aligned to [`Self::req_align()`].  Implementations that support
194    /// finer-grained zeroing (e.g. via `fallocate`) should override this method.
195    ///
196    /// # Safety
197    /// This is a pure write to storage.  The request must be fully aligned to
198    /// [`Self::zero_align()`], and safeguards we want to implement for safe concurrent access may
199    /// not be available.
200    ///
201    /// Use [`StorageExt::write_zeroes()`](crate::StorageExt::write_zeroes()) instead.
202    #[allow(async_fn_in_trait)] // No need for Send
203    async unsafe fn pure_write_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
204        unsafe { pure_write_full_zeroes(self, offset, length).await }
205    }
206
207    /// Ensure the given range is allocated, and reads back as zeroes.
208    ///
209    /// The default implementation writes actual zeroes as data via [`Storage::pure_writev()`],
210    /// which is inefficient.  Storage drivers should override it with a more efficient
211    /// implementation.
212    ///
213    /// Because the default implementation uses [`Storage::pure_writev()`], offset and length
214    /// must also be aligned to [`Self::req_align()`].  Implementations that support
215    /// finer-grained zeroing (e.g. via `fallocate`) should override this method.
216    ///
217    /// # Safety
218    /// This is a pure write to storage.  The request must be fully aligned to
219    /// [`Self::zero_align()`], and safeguards we want to implement for safe concurrent access may
220    /// not be available.
221    ///
222    /// Use [`StorageExt::write_allocated_zeroes()`](crate::StorageExt::write_allocated_zeroes())
223    /// instead.
224    #[allow(async_fn_in_trait)] // No need for Send
225    async unsafe fn pure_write_allocated_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
226        unsafe { pure_write_full_zeroes(self, offset, length).await }
227    }
228
229    /// Discard the given range, with undefined contents when read back.
230    ///
231    /// Tell the storage layer this range is no longer needed and need not be backed by actual
232    /// storage.  When read back, the data read will be undefined, i.e. not necessarily zeroes.
233    ///
234    /// No-op implementations therefore explicitly fulfill the interface contract.
235    ///
236    /// # Safety
237    /// This is a pure write to storage.  The request must be fully aligned to
238    /// [`Self::discard_align()`], and safeguards we want to implement for safe concurrent access
239    /// may not be available.
240    ///
241    /// Use [`StorageExt::discard()`](crate::StorageExt::discard()) instead.
242    #[allow(async_fn_in_trait)] // No need for Send
243    async unsafe fn pure_discard(&self, _offset: u64, _length: u64) -> io::Result<()> {
244        Ok(())
245    }
246
247    /// Flush internal buffers.
248    ///
249    /// Does not necessarily sync those buffers to disk.  When using `flush()`, consider whether
250    /// you want to call `sync()` afterwards.
251    ///
252    /// Note that this will not drop the buffers, so they may still be used to serve later
253    /// accesses.  Use [`Storage::invalidate_cache()`] to drop all buffers.
254    #[allow(async_fn_in_trait)] // No need for Send
255    async fn flush(&self) -> io::Result<()>;
256
257    /// Sync data already written to the storage hardware.
258    ///
259    /// This does not necessarily include flushing internal buffers, i.e. `flush`.  When using
260    /// `sync()`, consider whether you want to call `flush()` before it.
261    #[allow(async_fn_in_trait)] // No need for Send
262    async fn sync(&self) -> io::Result<()>;
263
264    /// Drop internal buffers.
265    ///
266    /// This drops all internal buffers, but does not flush them!  All cached data is reloaded on
267    /// subsequent accesses.
268    ///
269    /// # Safety
270    /// Not flushing internal buffers may cause corruption.  You must ensure the underlying storage
271    /// state is consistent.
272    #[allow(async_fn_in_trait)] // No need for Send
273    async unsafe fn invalidate_cache(&self) -> io::Result<()>;
274
275    /// Return the storage helper object (used by the [`StorageExt`](crate::StorageExt)
276    /// implementation).
277    fn get_storage_helper(&self) -> &CommonStorageHelper;
278
279    /// Resize to the given size.
280    ///
281    /// Set the size of this storage object to `new_size`.  If `new_size` is smaller than the
282    /// current size, ignore `prealloc_mode` and discard the data after `new_size`.
283    ///
284    /// If `new_size` is larger than the current size, `prealloc_mode` determines whether and how
285    /// the new range should be allocated; it is possible some preallocation modes are not
286    /// supported, in which case an [`std::io::ErrorKind::Unsupported`] is returned.
287    #[allow(async_fn_in_trait)] // No need for Send
288    async fn resize(&self, _new_size: u64, _prealloc_mode: PreallocateMode) -> io::Result<()> {
289        Err(io::ErrorKind::Unsupported.into())
290    }
291}
292
293/// Allow dynamic use of storage objects (i.e. is object safe).
294///
295/// When using normal `Storage` objects, they must all be of the same type within a single disk
296/// image chain.  For example, every storage object underneath a `FormatAccess<StdFile>` object
297/// must be of type `StdFile`.
298///
299/// `DynStorage` allows the use of `Box<dyn DynStorage>`, which implements `Storage`, to allow
300/// mixed storage object types.  Therefore, a `FormatAccess<Box<dyn DynStorage>>` allows e.g. the
301/// use of both `Box<StdFile>` and `Box<Null>` storage objects together.  (`Arc` instead of `Box`
302/// works, too.)
303///
304/// In async mode, async functions in `DynStorage` return boxed futures (`Pin<Box<dyn Future>>`),
305/// which makes them slightly less efficient than async functions in `Storage`, hence the
306/// distinction.  In sync mode, they return values directly, so there would be no need for this
307/// distinct trait, but we keep it for compatibility between sync and async.
308pub trait DynStorage: Any + Debug + Display + Send + Sync {
309    /// Wrapper around [`Storage::mem_align()`].
310    fn dyn_mem_align(&self) -> usize;
311
312    /// Wrapper around [`Storage::req_align()`].
313    fn dyn_req_align(&self) -> usize;
314
315    /// Wrapper around [`Storage::zero_align()`].
316    fn dyn_zero_align(&self) -> usize;
317
318    /// Wrapper around [`Storage::discard_align()`].
319    fn dyn_discard_align(&self) -> usize;
320
321    /// Wrapper around [`Storage::size()`].
322    fn dyn_size(&self) -> io::Result<u64>;
323
324    /// Wrapper around [`Storage::resolve_relative_path()`].
325    fn dyn_resolve_relative_path(&self, relative: &Path) -> io::Result<PathBuf>;
326
327    /// Wrapper around [`Storage::get_filename()`]
328    fn dyn_get_filename(&self) -> Option<PathBuf>;
329
330    /// Object-safe wrapper around [`Storage::pure_readv()`].
331    ///
332    /// # Safety
333    /// Same considerations as for [`Storage::pure_readv()`] apply.
334    #[cfg(feature = "async")]
335    unsafe fn dyn_pure_readv<'a>(
336        &'a self,
337        bufv: IoVectorMut<'a>,
338        offset: u64,
339    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + 'a>>;
340
341    /// Object-safe wrapper around [`Storage::pure_readv()`].
342    ///
343    /// # Safety
344    /// Same considerations as for [`Storage::pure_readv()`] apply.
345    #[cfg(feature = "sync")]
346    unsafe fn dyn_pure_readv(&self, bufv: IoVectorMut<'_>, offset: u64) -> io::Result<()>;
347
348    /// Object-safe wrapper around [`Storage::pure_writev()`].
349    ///
350    /// # Safety
351    /// Same considerations as for [`Storage::pure_writev()`] apply.
352    #[cfg(feature = "async")]
353    unsafe fn dyn_pure_writev<'a>(
354        &'a self,
355        bufv: IoVector<'a>,
356        offset: u64,
357    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + 'a>>;
358
359    /// Object-safe wrapper around [`Storage::pure_writev()`].
360    ///
361    /// # Safety
362    /// Same considerations as for [`Storage::pure_writev()`] apply.
363    #[cfg(feature = "sync")]
364    unsafe fn dyn_pure_writev(&self, bufv: IoVector<'_>, offset: u64) -> io::Result<()>;
365
366    /// Object-safe wrapper around [`Storage::pure_write_zeroes()`].
367    ///
368    /// # Safety
369    /// Same considerations as for [`Storage::pure_write_zeroes()`] apply.
370    #[cfg(feature = "async")]
371    unsafe fn dyn_pure_write_zeroes(
372        &self,
373        offset: u64,
374        length: u64,
375    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>>;
376
377    /// Object-safe wrapper around [`Storage::pure_write_zeroes()`].
378    ///
379    /// # Safety
380    /// Same considerations as for [`Storage::pure_write_zeroes()`] apply.
381    #[cfg(feature = "sync")]
382    unsafe fn dyn_pure_write_zeroes(&self, offset: u64, length: u64) -> io::Result<()>;
383
384    /// Object-safe wrapper around [`Storage::pure_write_allocated_zeroes()`].
385    ///
386    /// # Safety
387    /// Same considerations as for [`Storage::pure_write_allocated_zeroes()`] apply.
388    #[cfg(feature = "async")]
389    unsafe fn dyn_pure_write_allocated_zeroes(
390        &self,
391        offset: u64,
392        length: u64,
393    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>>;
394
395    /// Object-safe wrapper around [`Storage::pure_write_allocated_zeroes()`].
396    ///
397    /// # Safety
398    /// Same considerations as for [`Storage::pure_write_allocated_zeroes()`] apply.
399    #[cfg(feature = "sync")]
400    unsafe fn dyn_pure_write_allocated_zeroes(&self, offset: u64, length: u64) -> io::Result<()>;
401
402    /// Object-safe wrapper around [`Storage::pure_discard()`].
403    ///
404    /// # Safety
405    /// Same considerations as for [`Storage::pure_discard()`] apply.
406    #[cfg(feature = "async")]
407    unsafe fn dyn_pure_discard(
408        &self,
409        offset: u64,
410        length: u64,
411    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>>;
412
413    /// Object-safe wrapper around [`Storage::pure_discard()`].
414    ///
415    /// # Safety
416    /// Same considerations as for [`Storage::pure_discard()`] apply.
417    #[cfg(feature = "sync")]
418    unsafe fn dyn_pure_discard(&self, offset: u64, length: u64) -> io::Result<()>;
419
420    /// Object-safe wrapper around [`Storage::flush()`].
421    #[cfg(feature = "async")]
422    fn dyn_flush(&self) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>>;
423
424    /// Object-safe wrapper around [`Storage::flush()`].
425    #[cfg(feature = "sync")]
426    fn dyn_flush(&self) -> io::Result<()>;
427
428    /// Object-safe wrapper around [`Storage::sync()`].
429    #[cfg(feature = "async")]
430    fn dyn_sync(&self) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>>;
431
432    /// Object-safe wrapper around [`Storage::sync()`].
433    #[cfg(feature = "sync")]
434    fn dyn_sync(&self) -> io::Result<()>;
435
436    /// Object-safe wrapper around [`Storage::invalidate_cache()`].
437    ///
438    /// # Safety
439    /// Same considerations as for [`Storage::invalidate_cache()`] apply.
440    #[cfg(feature = "async")]
441    unsafe fn dyn_invalidate_cache(&self) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>>;
442
443    /// Object-safe wrapper around [`Storage::invalidate_cache()`].
444    ///
445    /// # Safety
446    /// Same considerations as for [`Storage::invalidate_cache()`] apply.
447    #[cfg(feature = "sync")]
448    unsafe fn dyn_invalidate_cache(&self) -> io::Result<()>;
449
450    /// Wrapper around [`Storage::get_storage_helper()`].
451    fn dyn_get_storage_helper(&self) -> &CommonStorageHelper;
452
453    /// Object-safe wrapper around [`Storage::resize()`].
454    #[cfg(feature = "async")]
455    fn dyn_resize(
456        &self,
457        new_size: u64,
458        prealloc_mode: PreallocateMode,
459    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>>;
460
461    /// Object-safe wrapper around [`Storage::resize()`].
462    #[cfg(feature = "sync")]
463    fn dyn_resize(&self, new_size: u64, prealloc_mode: PreallocateMode) -> io::Result<()>;
464}
465
466/// Storage object preallocation modes.
467///
468/// When resizing or creating storage objects, this mode determines whether and how the new data
469/// range is to be preallocated.
470#[derive(Clone, Copy, Debug, Eq, PartialEq)]
471#[non_exhaustive]
472pub enum PreallocateMode {
473    /// No preallocation.
474    ///
475    /// Reading the new range may return random data.
476    None,
477
478    /// Ensure range reads as zeroes.
479    ///
480    /// Does not necessarily allocate data, but has to ensure the new range will read back as
481    /// zeroes.
482    Zero,
483
484    /// Extent preallocation.
485    ///
486    /// Do not write data, but ensure all new extents are allocated.
487    Allocate,
488
489    /// Full data preallocation.
490    ///
491    /// Write zeroes to the whole range.
492    WriteData,
493}
494
495#[maybe_async(AFIT)]
496impl<S: Storage> Storage for &S {
497    fn mem_align(&self) -> usize {
498        (*self).mem_align()
499    }
500
501    fn req_align(&self) -> usize {
502        (*self).req_align()
503    }
504
505    fn zero_align(&self) -> usize {
506        (*self).zero_align()
507    }
508
509    fn discard_align(&self) -> usize {
510        (*self).discard_align()
511    }
512
513    fn size(&self) -> io::Result<u64> {
514        (*self).size()
515    }
516
517    fn resolve_relative_path<P: AsRef<Path>>(&self, relative: P) -> io::Result<PathBuf> {
518        (*self).resolve_relative_path(relative)
519    }
520
521    fn get_filename(&self) -> Option<PathBuf> {
522        (*self).get_filename()
523    }
524
525    async unsafe fn pure_readv(&self, bufv: IoVectorMut<'_>, offset: u64) -> io::Result<()> {
526        unsafe { (*self).pure_readv(bufv, offset).await }
527    }
528
529    async unsafe fn pure_writev(&self, bufv: IoVector<'_>, offset: u64) -> io::Result<()> {
530        unsafe { (*self).pure_writev(bufv, offset).await }
531    }
532
533    async unsafe fn pure_write_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
534        unsafe { (*self).pure_write_zeroes(offset, length).await }
535    }
536
537    async unsafe fn pure_write_allocated_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
538        unsafe { (*self).pure_write_allocated_zeroes(offset, length).await }
539    }
540
541    async unsafe fn pure_discard(&self, offset: u64, length: u64) -> io::Result<()> {
542        unsafe { (*self).pure_discard(offset, length).await }
543    }
544
545    async fn flush(&self) -> io::Result<()> {
546        (*self).flush().await
547    }
548
549    async fn sync(&self) -> io::Result<()> {
550        (*self).sync().await
551    }
552
553    async unsafe fn invalidate_cache(&self) -> io::Result<()> {
554        unsafe { (*self).invalidate_cache().await }
555    }
556
557    fn get_storage_helper(&self) -> &CommonStorageHelper {
558        (*self).get_storage_helper()
559    }
560
561    async fn resize(&self, new_size: u64, prealloc_mode: PreallocateMode) -> io::Result<()> {
562        (*self).resize(new_size, prealloc_mode).await
563    }
564}
565
566impl<S: Storage + 'static> DynStorage for S {
567    fn dyn_mem_align(&self) -> usize {
568        <S as Storage>::mem_align(self)
569    }
570
571    fn dyn_req_align(&self) -> usize {
572        <S as Storage>::req_align(self)
573    }
574
575    fn dyn_zero_align(&self) -> usize {
576        <S as Storage>::zero_align(self)
577    }
578
579    fn dyn_discard_align(&self) -> usize {
580        <S as Storage>::discard_align(self)
581    }
582
583    fn dyn_size(&self) -> io::Result<u64> {
584        <S as Storage>::size(self)
585    }
586
587    fn dyn_resolve_relative_path(&self, relative: &Path) -> io::Result<PathBuf> {
588        <S as Storage>::resolve_relative_path(self, relative)
589    }
590
591    fn dyn_get_filename(&self) -> Option<PathBuf> {
592        <S as Storage>::get_filename(self)
593    }
594
595    #[cfg(feature = "async")]
596    unsafe fn dyn_pure_readv<'a>(
597        &'a self,
598        bufv: IoVectorMut<'a>,
599        offset: u64,
600    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + 'a>> {
601        Box::pin(unsafe { <S as Storage>::pure_readv(self, bufv, offset) })
602    }
603
604    #[cfg(feature = "sync")]
605    unsafe fn dyn_pure_readv(&self, bufv: IoVectorMut<'_>, offset: u64) -> io::Result<()> {
606        unsafe { <S as Storage>::pure_readv(self, bufv, offset) }
607    }
608
609    #[cfg(feature = "async")]
610    unsafe fn dyn_pure_writev<'a>(
611        &'a self,
612        bufv: IoVector<'a>,
613        offset: u64,
614    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + 'a>> {
615        Box::pin(unsafe { <S as Storage>::pure_writev(self, bufv, offset) })
616    }
617
618    #[cfg(feature = "sync")]
619    unsafe fn dyn_pure_writev(&self, bufv: IoVector<'_>, offset: u64) -> io::Result<()> {
620        unsafe { <S as Storage>::pure_writev(self, bufv, offset) }
621    }
622
623    #[cfg(feature = "async")]
624    unsafe fn dyn_pure_write_zeroes(
625        &self,
626        offset: u64,
627        length: u64,
628    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>> {
629        Box::pin(unsafe { <S as Storage>::pure_write_zeroes(self, offset, length) })
630    }
631
632    #[cfg(feature = "sync")]
633    unsafe fn dyn_pure_write_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
634        unsafe { <S as Storage>::pure_write_zeroes(self, offset, length) }
635    }
636
637    #[cfg(feature = "async")]
638    unsafe fn dyn_pure_write_allocated_zeroes(
639        &self,
640        offset: u64,
641        length: u64,
642    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>> {
643        Box::pin(unsafe { <S as Storage>::pure_write_allocated_zeroes(self, offset, length) })
644    }
645
646    #[cfg(feature = "sync")]
647    unsafe fn dyn_pure_write_allocated_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
648        unsafe { <S as Storage>::pure_write_allocated_zeroes(self, offset, length) }
649    }
650
651    #[cfg(feature = "async")]
652    unsafe fn dyn_pure_discard(
653        &self,
654        offset: u64,
655        length: u64,
656    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>> {
657        Box::pin(unsafe { <S as Storage>::pure_discard(self, offset, length) })
658    }
659
660    #[cfg(feature = "sync")]
661    unsafe fn dyn_pure_discard(&self, offset: u64, length: u64) -> io::Result<()> {
662        unsafe { <S as Storage>::pure_discard(self, offset, length) }
663    }
664
665    #[cfg(feature = "async")]
666    fn dyn_flush(&self) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>> {
667        Box::pin(<S as Storage>::flush(self))
668    }
669
670    #[cfg(feature = "sync")]
671    fn dyn_flush(&self) -> io::Result<()> {
672        <S as Storage>::flush(self)
673    }
674
675    #[cfg(feature = "async")]
676    fn dyn_sync(&self) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>> {
677        Box::pin(<S as Storage>::sync(self))
678    }
679
680    #[cfg(feature = "sync")]
681    fn dyn_sync(&self) -> io::Result<()> {
682        <S as Storage>::sync(self)
683    }
684
685    #[cfg(feature = "async")]
686    unsafe fn dyn_invalidate_cache(&self) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>> {
687        Box::pin(unsafe { <S as Storage>::invalidate_cache(self) })
688    }
689
690    #[cfg(feature = "sync")]
691    unsafe fn dyn_invalidate_cache(&self) -> io::Result<()> {
692        unsafe { <S as Storage>::invalidate_cache(self) }
693    }
694
695    fn dyn_get_storage_helper(&self) -> &CommonStorageHelper {
696        <S as Storage>::get_storage_helper(self)
697    }
698
699    #[cfg(feature = "async")]
700    fn dyn_resize(
701        &self,
702        new_size: u64,
703        prealloc_mode: PreallocateMode,
704    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>> {
705        Box::pin(<S as Storage>::resize(self, new_size, prealloc_mode))
706    }
707
708    #[cfg(feature = "sync")]
709    fn dyn_resize(&self, new_size: u64, prealloc_mode: PreallocateMode) -> io::Result<()> {
710        <S as Storage>::resize(self, new_size, prealloc_mode)
711    }
712}
713
714#[maybe_async(AFIT)]
715impl Storage for Box<dyn DynStorage> {
716    async fn open(opts: StorageOpenOptions) -> io::Result<Self> {
717        // TODO: When we have more drivers, choose different defaults depending on the options
718        // given.  Right now, only `File` really supports being opened through options, so it is an
719        // obvious choice.
720        Ok(Box::new(crate::file::File::open(opts).await?))
721    }
722
723    async fn create_open(opts: StorageCreateOptions) -> io::Result<Self> {
724        // Same as `Self::open()`.
725        Ok(Box::new(crate::file::File::create_open(opts).await?))
726    }
727
728    fn mem_align(&self) -> usize {
729        self.as_ref().dyn_mem_align()
730    }
731
732    fn req_align(&self) -> usize {
733        self.as_ref().dyn_req_align()
734    }
735
736    fn zero_align(&self) -> usize {
737        self.as_ref().dyn_zero_align()
738    }
739
740    fn discard_align(&self) -> usize {
741        self.as_ref().dyn_discard_align()
742    }
743
744    fn size(&self) -> io::Result<u64> {
745        self.as_ref().dyn_size()
746    }
747
748    fn resolve_relative_path<P: AsRef<Path>>(&self, relative: P) -> io::Result<PathBuf> {
749        self.as_ref().dyn_resolve_relative_path(relative.as_ref())
750    }
751
752    fn get_filename(&self) -> Option<PathBuf> {
753        self.as_ref().dyn_get_filename()
754    }
755
756    async unsafe fn pure_readv(&self, bufv: IoVectorMut<'_>, offset: u64) -> io::Result<()> {
757        unsafe { self.as_ref().dyn_pure_readv(bufv, offset).await }
758    }
759
760    async unsafe fn pure_writev(&self, bufv: IoVector<'_>, offset: u64) -> io::Result<()> {
761        unsafe { self.as_ref().dyn_pure_writev(bufv, offset).await }
762    }
763
764    async unsafe fn pure_write_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
765        unsafe { self.as_ref().dyn_pure_write_zeroes(offset, length).await }
766    }
767
768    async unsafe fn pure_write_allocated_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
769        unsafe {
770            self.as_ref()
771                .dyn_pure_write_allocated_zeroes(offset, length)
772                .await
773        }
774    }
775
776    async unsafe fn pure_discard(&self, offset: u64, length: u64) -> io::Result<()> {
777        unsafe { self.as_ref().dyn_pure_discard(offset, length).await }
778    }
779
780    async fn flush(&self) -> io::Result<()> {
781        self.as_ref().dyn_flush().await
782    }
783
784    async fn sync(&self) -> io::Result<()> {
785        self.as_ref().dyn_sync().await
786    }
787
788    async unsafe fn invalidate_cache(&self) -> io::Result<()> {
789        unsafe { self.as_ref().dyn_invalidate_cache().await }
790    }
791
792    fn get_storage_helper(&self) -> &CommonStorageHelper {
793        self.as_ref().dyn_get_storage_helper()
794    }
795
796    async fn resize(&self, new_size: u64, prealloc_mode: PreallocateMode) -> io::Result<()> {
797        self.as_ref().dyn_resize(new_size, prealloc_mode).await
798    }
799}
800
801#[maybe_async(AFIT)]
802impl Storage for Arc<dyn DynStorage> {
803    async fn open(opts: StorageOpenOptions) -> io::Result<Self> {
804        Box::<dyn DynStorage>::open(opts).await.map(Into::into)
805    }
806
807    async fn create_open(opts: StorageCreateOptions) -> io::Result<Self> {
808        Box::<dyn DynStorage>::create_open(opts)
809            .await
810            .map(Into::into)
811    }
812
813    fn mem_align(&self) -> usize {
814        self.as_ref().dyn_mem_align()
815    }
816
817    fn req_align(&self) -> usize {
818        self.as_ref().dyn_req_align()
819    }
820
821    fn zero_align(&self) -> usize {
822        self.as_ref().dyn_zero_align()
823    }
824
825    fn discard_align(&self) -> usize {
826        self.as_ref().dyn_discard_align()
827    }
828
829    fn size(&self) -> io::Result<u64> {
830        self.as_ref().dyn_size()
831    }
832
833    fn resolve_relative_path<P: AsRef<Path>>(&self, relative: P) -> io::Result<PathBuf> {
834        self.as_ref().dyn_resolve_relative_path(relative.as_ref())
835    }
836
837    fn get_filename(&self) -> Option<PathBuf> {
838        self.as_ref().dyn_get_filename()
839    }
840
841    async unsafe fn pure_readv(&self, bufv: IoVectorMut<'_>, offset: u64) -> io::Result<()> {
842        unsafe { self.as_ref().dyn_pure_readv(bufv, offset) }.await
843    }
844
845    async unsafe fn pure_writev(&self, bufv: IoVector<'_>, offset: u64) -> io::Result<()> {
846        unsafe { self.as_ref().dyn_pure_writev(bufv, offset) }.await
847    }
848
849    async unsafe fn pure_write_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
850        unsafe { self.as_ref().dyn_pure_write_zeroes(offset, length) }.await
851    }
852
853    async unsafe fn pure_write_allocated_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
854        unsafe {
855            self.as_ref()
856                .dyn_pure_write_allocated_zeroes(offset, length)
857        }
858        .await
859    }
860
861    async unsafe fn pure_discard(&self, offset: u64, length: u64) -> io::Result<()> {
862        unsafe { self.as_ref().dyn_pure_discard(offset, length) }.await
863    }
864
865    async fn flush(&self) -> io::Result<()> {
866        self.as_ref().dyn_flush().await
867    }
868
869    async fn sync(&self) -> io::Result<()> {
870        self.as_ref().dyn_sync().await
871    }
872
873    async unsafe fn invalidate_cache(&self) -> io::Result<()> {
874        unsafe { self.as_ref().dyn_invalidate_cache().await }
875    }
876
877    fn get_storage_helper(&self) -> &CommonStorageHelper {
878        self.as_ref().dyn_get_storage_helper()
879    }
880
881    async fn resize(&self, new_size: u64, prealloc_mode: PreallocateMode) -> io::Result<()> {
882        self.as_ref().dyn_resize(new_size, prealloc_mode).await
883    }
884}
885
886impl StorageOpenOptions {
887    /// Create default options.
888    pub fn new() -> Self {
889        StorageOpenOptions::default()
890    }
891
892    /// Set a filename to open.
893    pub fn filename<P: AsRef<Path>>(mut self, filename: P) -> Self {
894        self.filename = Some(filename.as_ref().to_owned());
895        self
896    }
897
898    /// Whether the storage should be writable or not.
899    pub fn write(mut self, write: bool) -> Self {
900        self.writable = write;
901        self
902    }
903
904    /// Whether to bypass the host page cache (if applicable).
905    pub fn direct(mut self, direct: bool) -> Self {
906        self.direct = direct;
907        self
908    }
909
910    /// macOS-only: whether to use relaxed synchronization on `File`.
911    ///
912    /// If relaxed synchronization is enabled, `File::sync()` will use the `fsync()` syscall
913    /// instead of `fcntl(F_FULLFSYNC)`, which is a lighter synchronization mechanism that flushes
914    /// the filesystem cache to the drive, but doesn't request the drive to flush its internal
915    /// buffers to persistent storage.
916    #[cfg(target_os = "macos")]
917    pub fn relaxed_sync(mut self, relaxed_sync: bool) -> Self {
918        self.relaxed_sync = relaxed_sync;
919        self
920    }
921
922    /// Get the set filename (if any).
923    pub fn get_filename(&self) -> Option<&Path> {
924        self.filename.as_deref()
925    }
926
927    /// Return the set writable state.
928    pub fn get_writable(&self) -> bool {
929        self.writable
930    }
931
932    /// Return the set direct state.
933    pub fn get_direct(&self) -> bool {
934        self.direct
935    }
936
937    /// macOS-only: return the relaxed synchronization state.
938    #[cfg(target_os = "macos")]
939    pub fn get_relaxed_sync(&self) -> bool {
940        self.relaxed_sync
941    }
942}
943
944impl StorageCreateOptions {
945    /// Create default options.
946    pub fn new() -> Self {
947        StorageCreateOptions::default()
948    }
949
950    /// Set the filename of the file to create.
951    pub fn filename<P: AsRef<Path>>(self, filename: P) -> Self {
952        self.modify_open_opts(|o| o.filename(filename))
953    }
954
955    /// Set the initial size.
956    pub fn size(mut self, size: u64) -> Self {
957        self.size = size;
958        self
959    }
960
961    /// Set the desired preallocation mode.
962    pub fn preallocate(mut self, prealloc_mode: PreallocateMode) -> Self {
963        self.prealloc_mode = prealloc_mode;
964        self
965    }
966
967    /// Whether to overwrite an existing file.
968    pub fn overwrite(mut self, overwrite: bool) -> Self {
969        self.overwrite = overwrite;
970        self
971    }
972
973    /// Modify the options used for opening the file.
974    pub fn modify_open_opts<F: FnOnce(StorageOpenOptions) -> StorageOpenOptions>(
975        mut self,
976        f: F,
977    ) -> Self {
978        self.open_opts = f(self.open_opts);
979        self
980    }
981
982    /// Get the set filename (if any).
983    pub fn get_filename(&self) -> Option<&Path> {
984        self.open_opts.filename.as_deref()
985    }
986
987    /// Get the set size.
988    pub fn get_size(&self) -> u64 {
989        self.size
990    }
991
992    /// Get the preallocation mode.
993    pub fn get_preallocate(&self) -> PreallocateMode {
994        self.prealloc_mode
995    }
996
997    /// Check whether to overwrite an existing file.
998    pub fn get_overwrite(&self) -> bool {
999        self.overwrite
1000    }
1001
1002    /// Get the options for opening the created file.
1003    pub fn get_open_options(self) -> StorageOpenOptions {
1004        self.open_opts
1005    }
1006}
1007
1008impl Default for StorageCreateOptions {
1009    fn default() -> Self {
1010        StorageCreateOptions {
1011            open_opts: Default::default(),
1012            size: 0,
1013            prealloc_mode: PreallocateMode::None,
1014            overwrite: false,
1015        }
1016    }
1017}
1018
1019/// Write zero data to the given area.
1020///
1021/// Like [`ext::write_full_zeroes()`], this will actually write zero data, fully allocated.
1022///
1023/// # Safety
1024/// This is a pure write to storage.  The request must be fully aligned to
1025/// [`Storage::req_align()`], and safeguards we want to implement for safe concurrent access may
1026/// not be available.
1027///
1028/// To be used as the default implementation of [`Storage::pure_write_zeroes()`] and
1029/// [`Storage::pure_write_allocated_zeroes()`].
1030#[maybe_async]
1031async unsafe fn pure_write_full_zeroes<S: Storage>(
1032    storage: S,
1033    mut offset: u64,
1034    mut length: u64,
1035) -> io::Result<()> {
1036    let req_align = storage.req_align() as u64;
1037    if !(offset | length).is_multiple_of(req_align) {
1038        return Err(io::Error::new(
1039            io::ErrorKind::InvalidInput,
1040            "write_zeroes fallback: offset/length not aligned to request alignment",
1041        ));
1042    }
1043
1044    let mem_align = storage.mem_align() as u64;
1045    let max_chunk_len = cmp::max(cmp::max(req_align, mem_align), 1048576);
1046    let buflen = cmp::min(length, max_chunk_len) as usize;
1047    let mut buf = IoBuffer::new(buflen, storage.mem_align())?;
1048    buf.as_mut().into_slice().fill(0);
1049
1050    while length > 0 {
1051        let chunk_len = cmp::min(length, max_chunk_len) as usize;
1052        unsafe {
1053            storage
1054                .pure_writev(buf.as_ref_range(0..chunk_len).into(), offset)
1055                .await
1056        }?;
1057        offset += chunk_len as u64;
1058        length -= chunk_len as u64;
1059    }
1060
1061    Ok(())
1062}