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    /// Wait for all modifying requests issued before this call to settle.
265    ///
266    /// When this returns, all modifying requests (writes, write-zeroes, discards) issued before
267    /// this call have completed (successfully or not), including requests whose futures were
268    /// dropped before they completed. Use this before reusing an area of the storage that such
269    /// requests may still target.
270    ///
271    /// This does not flush or sync anything; use [`Storage::flush()`] and [`Storage::sync()`] for
272    /// that.
273    ///
274    /// Implementations whose modifying requests may still be performed after their futures have
275    /// been dropped (e.g. because they submit them to the kernel via io_uring, or to a thread pool)
276    /// must override the default implementation (which does nothing).
277    ///
278    /// NOTE: This method will be *required* to be implemented starting from the imago 0.3 release.
279    #[allow(async_fn_in_trait)] // No need for Send
280    async fn settle_writes(&self) -> io::Result<()> {
281        Ok(())
282    }
283
284    /// Drop internal buffers.
285    ///
286    /// This drops all internal buffers, but does not flush them!  All cached data is reloaded on
287    /// subsequent accesses.
288    ///
289    /// # Safety
290    /// Not flushing internal buffers may cause corruption.  You must ensure the underlying storage
291    /// state is consistent.
292    #[allow(async_fn_in_trait)] // No need for Send
293    async unsafe fn invalidate_cache(&self) -> io::Result<()>;
294
295    /// Return the storage helper object (used by the [`StorageExt`](crate::StorageExt)
296    /// implementation).
297    fn get_storage_helper(&self) -> &CommonStorageHelper;
298
299    /// Resize to the given size.
300    ///
301    /// Set the size of this storage object to `new_size`.  If `new_size` is smaller than the
302    /// current size, ignore `prealloc_mode` and discard the data after `new_size`.
303    ///
304    /// If `new_size` is larger than the current size, `prealloc_mode` determines whether and how
305    /// the new range should be allocated; it is possible some preallocation modes are not
306    /// supported, in which case an [`std::io::ErrorKind::Unsupported`] is returned.
307    #[allow(async_fn_in_trait)] // No need for Send
308    async fn resize(&self, _new_size: u64, _prealloc_mode: PreallocateMode) -> io::Result<()> {
309        Err(io::ErrorKind::Unsupported.into())
310    }
311}
312
313/// Allow dynamic use of storage objects (i.e. is object safe).
314///
315/// When using normal `Storage` objects, they must all be of the same type within a single disk
316/// image chain.  For example, every storage object underneath a `FormatAccess<StdFile>` object
317/// must be of type `StdFile`.
318///
319/// `DynStorage` allows the use of `Box<dyn DynStorage>`, which implements `Storage`, to allow
320/// mixed storage object types.  Therefore, a `FormatAccess<Box<dyn DynStorage>>` allows e.g. the
321/// use of both `Box<StdFile>` and `Box<Null>` storage objects together.  (`Arc` instead of `Box`
322/// works, too.)
323///
324/// In async mode, async functions in `DynStorage` return boxed futures (`Pin<Box<dyn Future>>`),
325/// which makes them slightly less efficient than async functions in `Storage`, hence the
326/// distinction.  In sync mode, they return values directly, so there would be no need for this
327/// distinct trait, but we keep it for compatibility between sync and async.
328pub trait DynStorage: Any + Debug + Display + Send + Sync {
329    /// Wrapper around [`Storage::mem_align()`].
330    fn dyn_mem_align(&self) -> usize;
331
332    /// Wrapper around [`Storage::req_align()`].
333    fn dyn_req_align(&self) -> usize;
334
335    /// Wrapper around [`Storage::zero_align()`].
336    fn dyn_zero_align(&self) -> usize;
337
338    /// Wrapper around [`Storage::discard_align()`].
339    fn dyn_discard_align(&self) -> usize;
340
341    /// Wrapper around [`Storage::size()`].
342    fn dyn_size(&self) -> io::Result<u64>;
343
344    /// Wrapper around [`Storage::resolve_relative_path()`].
345    fn dyn_resolve_relative_path(&self, relative: &Path) -> io::Result<PathBuf>;
346
347    /// Wrapper around [`Storage::get_filename()`]
348    fn dyn_get_filename(&self) -> Option<PathBuf>;
349
350    /// Object-safe wrapper around [`Storage::pure_readv()`].
351    ///
352    /// # Safety
353    /// Same considerations as for [`Storage::pure_readv()`] apply.
354    #[cfg(feature = "async")]
355    unsafe fn dyn_pure_readv<'a>(
356        &'a self,
357        bufv: IoVectorMut<'a>,
358        offset: u64,
359    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + 'a>>;
360
361    /// Object-safe wrapper around [`Storage::pure_readv()`].
362    ///
363    /// # Safety
364    /// Same considerations as for [`Storage::pure_readv()`] apply.
365    #[cfg(feature = "sync")]
366    unsafe fn dyn_pure_readv(&self, bufv: IoVectorMut<'_>, offset: u64) -> io::Result<()>;
367
368    /// Object-safe wrapper around [`Storage::pure_writev()`].
369    ///
370    /// # Safety
371    /// Same considerations as for [`Storage::pure_writev()`] apply.
372    #[cfg(feature = "async")]
373    unsafe fn dyn_pure_writev<'a>(
374        &'a self,
375        bufv: IoVector<'a>,
376        offset: u64,
377    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + 'a>>;
378
379    /// Object-safe wrapper around [`Storage::pure_writev()`].
380    ///
381    /// # Safety
382    /// Same considerations as for [`Storage::pure_writev()`] apply.
383    #[cfg(feature = "sync")]
384    unsafe fn dyn_pure_writev(&self, bufv: IoVector<'_>, offset: u64) -> io::Result<()>;
385
386    /// Object-safe wrapper around [`Storage::pure_write_zeroes()`].
387    ///
388    /// # Safety
389    /// Same considerations as for [`Storage::pure_write_zeroes()`] apply.
390    #[cfg(feature = "async")]
391    unsafe fn dyn_pure_write_zeroes(
392        &self,
393        offset: u64,
394        length: u64,
395    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>>;
396
397    /// Object-safe wrapper around [`Storage::pure_write_zeroes()`].
398    ///
399    /// # Safety
400    /// Same considerations as for [`Storage::pure_write_zeroes()`] apply.
401    #[cfg(feature = "sync")]
402    unsafe fn dyn_pure_write_zeroes(&self, offset: u64, length: u64) -> io::Result<()>;
403
404    /// Object-safe wrapper around [`Storage::pure_write_allocated_zeroes()`].
405    ///
406    /// # Safety
407    /// Same considerations as for [`Storage::pure_write_allocated_zeroes()`] apply.
408    #[cfg(feature = "async")]
409    unsafe fn dyn_pure_write_allocated_zeroes(
410        &self,
411        offset: u64,
412        length: u64,
413    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>>;
414
415    /// Object-safe wrapper around [`Storage::pure_write_allocated_zeroes()`].
416    ///
417    /// # Safety
418    /// Same considerations as for [`Storage::pure_write_allocated_zeroes()`] apply.
419    #[cfg(feature = "sync")]
420    unsafe fn dyn_pure_write_allocated_zeroes(&self, offset: u64, length: u64) -> io::Result<()>;
421
422    /// Object-safe wrapper around [`Storage::pure_discard()`].
423    ///
424    /// # Safety
425    /// Same considerations as for [`Storage::pure_discard()`] apply.
426    #[cfg(feature = "async")]
427    unsafe fn dyn_pure_discard(
428        &self,
429        offset: u64,
430        length: u64,
431    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>>;
432
433    /// Object-safe wrapper around [`Storage::pure_discard()`].
434    ///
435    /// # Safety
436    /// Same considerations as for [`Storage::pure_discard()`] apply.
437    #[cfg(feature = "sync")]
438    unsafe fn dyn_pure_discard(&self, offset: u64, length: u64) -> io::Result<()>;
439
440    /// Object-safe wrapper around [`Storage::flush()`].
441    #[cfg(feature = "async")]
442    fn dyn_flush(&self) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>>;
443
444    /// Object-safe wrapper around [`Storage::flush()`].
445    #[cfg(feature = "sync")]
446    fn dyn_flush(&self) -> io::Result<()>;
447
448    /// Object-safe wrapper around [`Storage::sync()`].
449    #[cfg(feature = "async")]
450    fn dyn_sync(&self) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>>;
451
452    /// Object-safe wrapper around [`Storage::sync()`].
453    #[cfg(feature = "sync")]
454    fn dyn_sync(&self) -> io::Result<()>;
455
456    /// Object-safe wrapper around [`Storage::settle_writes()`].
457    #[cfg(feature = "async")]
458    fn dyn_settle_writes(&self) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>>;
459
460    /// Object-safe wrapper around [`Storage::settle_writes()`].
461    #[cfg(feature = "sync")]
462    fn dyn_settle_writes(&self) -> io::Result<()>;
463
464    /// Object-safe wrapper around [`Storage::invalidate_cache()`].
465    ///
466    /// # Safety
467    /// Same considerations as for [`Storage::invalidate_cache()`] apply.
468    #[cfg(feature = "async")]
469    unsafe fn dyn_invalidate_cache(&self) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>>;
470
471    /// Object-safe wrapper around [`Storage::invalidate_cache()`].
472    ///
473    /// # Safety
474    /// Same considerations as for [`Storage::invalidate_cache()`] apply.
475    #[cfg(feature = "sync")]
476    unsafe fn dyn_invalidate_cache(&self) -> io::Result<()>;
477
478    /// Wrapper around [`Storage::get_storage_helper()`].
479    fn dyn_get_storage_helper(&self) -> &CommonStorageHelper;
480
481    /// Object-safe wrapper around [`Storage::resize()`].
482    #[cfg(feature = "async")]
483    fn dyn_resize(
484        &self,
485        new_size: u64,
486        prealloc_mode: PreallocateMode,
487    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>>;
488
489    /// Object-safe wrapper around [`Storage::resize()`].
490    #[cfg(feature = "sync")]
491    fn dyn_resize(&self, new_size: u64, prealloc_mode: PreallocateMode) -> io::Result<()>;
492}
493
494/// Storage object preallocation modes.
495///
496/// When resizing or creating storage objects, this mode determines whether and how the new data
497/// range is to be preallocated.
498#[derive(Clone, Copy, Debug, Eq, PartialEq)]
499#[non_exhaustive]
500pub enum PreallocateMode {
501    /// No preallocation.
502    ///
503    /// Reading the new range may return random data.
504    None,
505
506    /// Ensure range reads as zeroes.
507    ///
508    /// Does not necessarily allocate data, but has to ensure the new range will read back as
509    /// zeroes.
510    Zero,
511
512    /// Extent preallocation.
513    ///
514    /// Do not write data, but ensure all new extents are allocated.
515    Allocate,
516
517    /// Full data preallocation.
518    ///
519    /// Write zeroes to the whole range.
520    WriteData,
521}
522
523#[maybe_async(AFIT)]
524impl<S: Storage> Storage for &S {
525    fn mem_align(&self) -> usize {
526        (*self).mem_align()
527    }
528
529    fn req_align(&self) -> usize {
530        (*self).req_align()
531    }
532
533    fn zero_align(&self) -> usize {
534        (*self).zero_align()
535    }
536
537    fn discard_align(&self) -> usize {
538        (*self).discard_align()
539    }
540
541    fn size(&self) -> io::Result<u64> {
542        (*self).size()
543    }
544
545    fn resolve_relative_path<P: AsRef<Path>>(&self, relative: P) -> io::Result<PathBuf> {
546        (*self).resolve_relative_path(relative)
547    }
548
549    fn get_filename(&self) -> Option<PathBuf> {
550        (*self).get_filename()
551    }
552
553    async unsafe fn pure_readv(&self, bufv: IoVectorMut<'_>, offset: u64) -> io::Result<()> {
554        unsafe { (*self).pure_readv(bufv, offset).await }
555    }
556
557    async unsafe fn pure_writev(&self, bufv: IoVector<'_>, offset: u64) -> io::Result<()> {
558        unsafe { (*self).pure_writev(bufv, offset).await }
559    }
560
561    async unsafe fn pure_write_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
562        unsafe { (*self).pure_write_zeroes(offset, length).await }
563    }
564
565    async unsafe fn pure_write_allocated_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
566        unsafe { (*self).pure_write_allocated_zeroes(offset, length).await }
567    }
568
569    async unsafe fn pure_discard(&self, offset: u64, length: u64) -> io::Result<()> {
570        unsafe { (*self).pure_discard(offset, length).await }
571    }
572
573    async fn flush(&self) -> io::Result<()> {
574        (*self).flush().await
575    }
576
577    async fn sync(&self) -> io::Result<()> {
578        (*self).sync().await
579    }
580
581    async fn settle_writes(&self) -> io::Result<()> {
582        (*self).settle_writes().await
583    }
584
585    async unsafe fn invalidate_cache(&self) -> io::Result<()> {
586        unsafe { (*self).invalidate_cache().await }
587    }
588
589    fn get_storage_helper(&self) -> &CommonStorageHelper {
590        (*self).get_storage_helper()
591    }
592
593    async fn resize(&self, new_size: u64, prealloc_mode: PreallocateMode) -> io::Result<()> {
594        (*self).resize(new_size, prealloc_mode).await
595    }
596}
597
598impl<S: Storage + 'static> DynStorage for S {
599    fn dyn_mem_align(&self) -> usize {
600        <S as Storage>::mem_align(self)
601    }
602
603    fn dyn_req_align(&self) -> usize {
604        <S as Storage>::req_align(self)
605    }
606
607    fn dyn_zero_align(&self) -> usize {
608        <S as Storage>::zero_align(self)
609    }
610
611    fn dyn_discard_align(&self) -> usize {
612        <S as Storage>::discard_align(self)
613    }
614
615    fn dyn_size(&self) -> io::Result<u64> {
616        <S as Storage>::size(self)
617    }
618
619    fn dyn_resolve_relative_path(&self, relative: &Path) -> io::Result<PathBuf> {
620        <S as Storage>::resolve_relative_path(self, relative)
621    }
622
623    fn dyn_get_filename(&self) -> Option<PathBuf> {
624        <S as Storage>::get_filename(self)
625    }
626
627    #[cfg(feature = "async")]
628    unsafe fn dyn_pure_readv<'a>(
629        &'a self,
630        bufv: IoVectorMut<'a>,
631        offset: u64,
632    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + 'a>> {
633        Box::pin(unsafe { <S as Storage>::pure_readv(self, bufv, offset) })
634    }
635
636    #[cfg(feature = "sync")]
637    unsafe fn dyn_pure_readv(&self, bufv: IoVectorMut<'_>, offset: u64) -> io::Result<()> {
638        unsafe { <S as Storage>::pure_readv(self, bufv, offset) }
639    }
640
641    #[cfg(feature = "async")]
642    unsafe fn dyn_pure_writev<'a>(
643        &'a self,
644        bufv: IoVector<'a>,
645        offset: u64,
646    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + 'a>> {
647        Box::pin(unsafe { <S as Storage>::pure_writev(self, bufv, offset) })
648    }
649
650    #[cfg(feature = "sync")]
651    unsafe fn dyn_pure_writev(&self, bufv: IoVector<'_>, offset: u64) -> io::Result<()> {
652        unsafe { <S as Storage>::pure_writev(self, bufv, offset) }
653    }
654
655    #[cfg(feature = "async")]
656    unsafe fn dyn_pure_write_zeroes(
657        &self,
658        offset: u64,
659        length: u64,
660    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>> {
661        Box::pin(unsafe { <S as Storage>::pure_write_zeroes(self, offset, length) })
662    }
663
664    #[cfg(feature = "sync")]
665    unsafe fn dyn_pure_write_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
666        unsafe { <S as Storage>::pure_write_zeroes(self, offset, length) }
667    }
668
669    #[cfg(feature = "async")]
670    unsafe fn dyn_pure_write_allocated_zeroes(
671        &self,
672        offset: u64,
673        length: u64,
674    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>> {
675        Box::pin(unsafe { <S as Storage>::pure_write_allocated_zeroes(self, offset, length) })
676    }
677
678    #[cfg(feature = "sync")]
679    unsafe fn dyn_pure_write_allocated_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
680        unsafe { <S as Storage>::pure_write_allocated_zeroes(self, offset, length) }
681    }
682
683    #[cfg(feature = "async")]
684    unsafe fn dyn_pure_discard(
685        &self,
686        offset: u64,
687        length: u64,
688    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>> {
689        Box::pin(unsafe { <S as Storage>::pure_discard(self, offset, length) })
690    }
691
692    #[cfg(feature = "sync")]
693    unsafe fn dyn_pure_discard(&self, offset: u64, length: u64) -> io::Result<()> {
694        unsafe { <S as Storage>::pure_discard(self, offset, length) }
695    }
696
697    #[cfg(feature = "async")]
698    fn dyn_flush(&self) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>> {
699        Box::pin(<S as Storage>::flush(self))
700    }
701
702    #[cfg(feature = "sync")]
703    fn dyn_flush(&self) -> io::Result<()> {
704        <S as Storage>::flush(self)
705    }
706
707    #[cfg(feature = "async")]
708    fn dyn_sync(&self) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>> {
709        Box::pin(<S as Storage>::sync(self))
710    }
711
712    #[cfg(feature = "sync")]
713    fn dyn_sync(&self) -> io::Result<()> {
714        <S as Storage>::sync(self)
715    }
716
717    #[cfg(feature = "async")]
718    fn dyn_settle_writes(&self) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>> {
719        Box::pin(<S as Storage>::settle_writes(self))
720    }
721
722    #[cfg(feature = "sync")]
723    fn dyn_settle_writes(&self) -> io::Result<()> {
724        <S as Storage>::settle_writes(self)
725    }
726
727    #[cfg(feature = "async")]
728    unsafe fn dyn_invalidate_cache(&self) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>> {
729        Box::pin(unsafe { <S as Storage>::invalidate_cache(self) })
730    }
731
732    #[cfg(feature = "sync")]
733    unsafe fn dyn_invalidate_cache(&self) -> io::Result<()> {
734        unsafe { <S as Storage>::invalidate_cache(self) }
735    }
736
737    fn dyn_get_storage_helper(&self) -> &CommonStorageHelper {
738        <S as Storage>::get_storage_helper(self)
739    }
740
741    #[cfg(feature = "async")]
742    fn dyn_resize(
743        &self,
744        new_size: u64,
745        prealloc_mode: PreallocateMode,
746    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>> {
747        Box::pin(<S as Storage>::resize(self, new_size, prealloc_mode))
748    }
749
750    #[cfg(feature = "sync")]
751    fn dyn_resize(&self, new_size: u64, prealloc_mode: PreallocateMode) -> io::Result<()> {
752        <S as Storage>::resize(self, new_size, prealloc_mode)
753    }
754}
755
756#[maybe_async(AFIT)]
757impl Storage for Box<dyn DynStorage> {
758    async fn open(opts: StorageOpenOptions) -> io::Result<Self> {
759        // TODO: When we have more drivers, choose different defaults depending on the options
760        // given.  Right now, only `File` really supports being opened through options, so it is an
761        // obvious choice.
762        Ok(Box::new(crate::file::File::open(opts).await?))
763    }
764
765    async fn create_open(opts: StorageCreateOptions) -> io::Result<Self> {
766        // Same as `Self::open()`.
767        Ok(Box::new(crate::file::File::create_open(opts).await?))
768    }
769
770    fn mem_align(&self) -> usize {
771        self.as_ref().dyn_mem_align()
772    }
773
774    fn req_align(&self) -> usize {
775        self.as_ref().dyn_req_align()
776    }
777
778    fn zero_align(&self) -> usize {
779        self.as_ref().dyn_zero_align()
780    }
781
782    fn discard_align(&self) -> usize {
783        self.as_ref().dyn_discard_align()
784    }
785
786    fn size(&self) -> io::Result<u64> {
787        self.as_ref().dyn_size()
788    }
789
790    fn resolve_relative_path<P: AsRef<Path>>(&self, relative: P) -> io::Result<PathBuf> {
791        self.as_ref().dyn_resolve_relative_path(relative.as_ref())
792    }
793
794    fn get_filename(&self) -> Option<PathBuf> {
795        self.as_ref().dyn_get_filename()
796    }
797
798    async unsafe fn pure_readv(&self, bufv: IoVectorMut<'_>, offset: u64) -> io::Result<()> {
799        unsafe { self.as_ref().dyn_pure_readv(bufv, offset).await }
800    }
801
802    async unsafe fn pure_writev(&self, bufv: IoVector<'_>, offset: u64) -> io::Result<()> {
803        unsafe { self.as_ref().dyn_pure_writev(bufv, offset).await }
804    }
805
806    async unsafe fn pure_write_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
807        unsafe { self.as_ref().dyn_pure_write_zeroes(offset, length).await }
808    }
809
810    async unsafe fn pure_write_allocated_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
811        unsafe {
812            self.as_ref()
813                .dyn_pure_write_allocated_zeroes(offset, length)
814                .await
815        }
816    }
817
818    async unsafe fn pure_discard(&self, offset: u64, length: u64) -> io::Result<()> {
819        unsafe { self.as_ref().dyn_pure_discard(offset, length).await }
820    }
821
822    async fn flush(&self) -> io::Result<()> {
823        self.as_ref().dyn_flush().await
824    }
825
826    async fn sync(&self) -> io::Result<()> {
827        self.as_ref().dyn_sync().await
828    }
829
830    async fn settle_writes(&self) -> io::Result<()> {
831        self.as_ref().dyn_settle_writes().await
832    }
833
834    async unsafe fn invalidate_cache(&self) -> io::Result<()> {
835        unsafe { self.as_ref().dyn_invalidate_cache().await }
836    }
837
838    fn get_storage_helper(&self) -> &CommonStorageHelper {
839        self.as_ref().dyn_get_storage_helper()
840    }
841
842    async fn resize(&self, new_size: u64, prealloc_mode: PreallocateMode) -> io::Result<()> {
843        self.as_ref().dyn_resize(new_size, prealloc_mode).await
844    }
845}
846
847#[maybe_async(AFIT)]
848impl Storage for Arc<dyn DynStorage> {
849    async fn open(opts: StorageOpenOptions) -> io::Result<Self> {
850        Box::<dyn DynStorage>::open(opts).await.map(Into::into)
851    }
852
853    async fn create_open(opts: StorageCreateOptions) -> io::Result<Self> {
854        Box::<dyn DynStorage>::create_open(opts)
855            .await
856            .map(Into::into)
857    }
858
859    fn mem_align(&self) -> usize {
860        self.as_ref().dyn_mem_align()
861    }
862
863    fn req_align(&self) -> usize {
864        self.as_ref().dyn_req_align()
865    }
866
867    fn zero_align(&self) -> usize {
868        self.as_ref().dyn_zero_align()
869    }
870
871    fn discard_align(&self) -> usize {
872        self.as_ref().dyn_discard_align()
873    }
874
875    fn size(&self) -> io::Result<u64> {
876        self.as_ref().dyn_size()
877    }
878
879    fn resolve_relative_path<P: AsRef<Path>>(&self, relative: P) -> io::Result<PathBuf> {
880        self.as_ref().dyn_resolve_relative_path(relative.as_ref())
881    }
882
883    fn get_filename(&self) -> Option<PathBuf> {
884        self.as_ref().dyn_get_filename()
885    }
886
887    async unsafe fn pure_readv(&self, bufv: IoVectorMut<'_>, offset: u64) -> io::Result<()> {
888        unsafe { self.as_ref().dyn_pure_readv(bufv, offset) }.await
889    }
890
891    async unsafe fn pure_writev(&self, bufv: IoVector<'_>, offset: u64) -> io::Result<()> {
892        unsafe { self.as_ref().dyn_pure_writev(bufv, offset) }.await
893    }
894
895    async unsafe fn pure_write_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
896        unsafe { self.as_ref().dyn_pure_write_zeroes(offset, length) }.await
897    }
898
899    async unsafe fn pure_write_allocated_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
900        unsafe {
901            self.as_ref()
902                .dyn_pure_write_allocated_zeroes(offset, length)
903        }
904        .await
905    }
906
907    async unsafe fn pure_discard(&self, offset: u64, length: u64) -> io::Result<()> {
908        unsafe { self.as_ref().dyn_pure_discard(offset, length) }.await
909    }
910
911    async fn flush(&self) -> io::Result<()> {
912        self.as_ref().dyn_flush().await
913    }
914
915    async fn sync(&self) -> io::Result<()> {
916        self.as_ref().dyn_sync().await
917    }
918
919    async fn settle_writes(&self) -> io::Result<()> {
920        self.as_ref().dyn_settle_writes().await
921    }
922
923    async unsafe fn invalidate_cache(&self) -> io::Result<()> {
924        unsafe { self.as_ref().dyn_invalidate_cache().await }
925    }
926
927    fn get_storage_helper(&self) -> &CommonStorageHelper {
928        self.as_ref().dyn_get_storage_helper()
929    }
930
931    async fn resize(&self, new_size: u64, prealloc_mode: PreallocateMode) -> io::Result<()> {
932        self.as_ref().dyn_resize(new_size, prealloc_mode).await
933    }
934}
935
936impl StorageOpenOptions {
937    /// Create default options.
938    pub fn new() -> Self {
939        StorageOpenOptions::default()
940    }
941
942    /// Set a filename to open.
943    pub fn filename<P: AsRef<Path>>(mut self, filename: P) -> Self {
944        self.filename = Some(filename.as_ref().to_owned());
945        self
946    }
947
948    /// Whether the storage should be writable or not.
949    pub fn write(mut self, write: bool) -> Self {
950        self.writable = write;
951        self
952    }
953
954    /// Whether to bypass the host page cache (if applicable).
955    pub fn direct(mut self, direct: bool) -> Self {
956        self.direct = direct;
957        self
958    }
959
960    /// macOS-only: whether to use relaxed synchronization on `File`.
961    ///
962    /// If relaxed synchronization is enabled, `File::sync()` will use the `fsync()` syscall
963    /// instead of `fcntl(F_FULLFSYNC)`, which is a lighter synchronization mechanism that flushes
964    /// the filesystem cache to the drive, but doesn't request the drive to flush its internal
965    /// buffers to persistent storage.
966    #[cfg(target_os = "macos")]
967    pub fn relaxed_sync(mut self, relaxed_sync: bool) -> Self {
968        self.relaxed_sync = relaxed_sync;
969        self
970    }
971
972    /// Get the set filename (if any).
973    pub fn get_filename(&self) -> Option<&Path> {
974        self.filename.as_deref()
975    }
976
977    /// Return the set writable state.
978    pub fn get_writable(&self) -> bool {
979        self.writable
980    }
981
982    /// Return the set direct state.
983    pub fn get_direct(&self) -> bool {
984        self.direct
985    }
986
987    /// macOS-only: return the relaxed synchronization state.
988    #[cfg(target_os = "macos")]
989    pub fn get_relaxed_sync(&self) -> bool {
990        self.relaxed_sync
991    }
992}
993
994impl StorageCreateOptions {
995    /// Create default options.
996    pub fn new() -> Self {
997        StorageCreateOptions::default()
998    }
999
1000    /// Set the filename of the file to create.
1001    pub fn filename<P: AsRef<Path>>(self, filename: P) -> Self {
1002        self.modify_open_opts(|o| o.filename(filename))
1003    }
1004
1005    /// Set the initial size.
1006    pub fn size(mut self, size: u64) -> Self {
1007        self.size = size;
1008        self
1009    }
1010
1011    /// Set the desired preallocation mode.
1012    pub fn preallocate(mut self, prealloc_mode: PreallocateMode) -> Self {
1013        self.prealloc_mode = prealloc_mode;
1014        self
1015    }
1016
1017    /// Whether to overwrite an existing file.
1018    pub fn overwrite(mut self, overwrite: bool) -> Self {
1019        self.overwrite = overwrite;
1020        self
1021    }
1022
1023    /// Modify the options used for opening the file.
1024    pub fn modify_open_opts<F: FnOnce(StorageOpenOptions) -> StorageOpenOptions>(
1025        mut self,
1026        f: F,
1027    ) -> Self {
1028        self.open_opts = f(self.open_opts);
1029        self
1030    }
1031
1032    /// Get the set filename (if any).
1033    pub fn get_filename(&self) -> Option<&Path> {
1034        self.open_opts.filename.as_deref()
1035    }
1036
1037    /// Get the set size.
1038    pub fn get_size(&self) -> u64 {
1039        self.size
1040    }
1041
1042    /// Get the preallocation mode.
1043    pub fn get_preallocate(&self) -> PreallocateMode {
1044        self.prealloc_mode
1045    }
1046
1047    /// Check whether to overwrite an existing file.
1048    pub fn get_overwrite(&self) -> bool {
1049        self.overwrite
1050    }
1051
1052    /// Get the options for opening the created file.
1053    pub fn get_open_options(self) -> StorageOpenOptions {
1054        self.open_opts
1055    }
1056}
1057
1058impl Default for StorageCreateOptions {
1059    fn default() -> Self {
1060        StorageCreateOptions {
1061            open_opts: Default::default(),
1062            size: 0,
1063            prealloc_mode: PreallocateMode::None,
1064            overwrite: false,
1065        }
1066    }
1067}
1068
1069/// Write zero data to the given area.
1070///
1071/// Like [`ext::write_full_zeroes()`], this will actually write zero data, fully allocated.
1072///
1073/// # Safety
1074/// This is a pure write to storage.  The request must be fully aligned to
1075/// [`Storage::req_align()`], and safeguards we want to implement for safe concurrent access may
1076/// not be available.
1077///
1078/// To be used as the default implementation of [`Storage::pure_write_zeroes()`] and
1079/// [`Storage::pure_write_allocated_zeroes()`].
1080#[maybe_async]
1081async unsafe fn pure_write_full_zeroes<S: Storage>(
1082    storage: S,
1083    mut offset: u64,
1084    mut length: u64,
1085) -> io::Result<()> {
1086    let req_align = storage.req_align() as u64;
1087    if !(offset | length).is_multiple_of(req_align) {
1088        return Err(io::Error::new(
1089            io::ErrorKind::InvalidInput,
1090            "write_zeroes fallback: offset/length not aligned to request alignment",
1091        ));
1092    }
1093
1094    let mem_align = storage.mem_align() as u64;
1095    let max_chunk_len = cmp::max(cmp::max(req_align, mem_align), 1048576);
1096    let buflen = cmp::min(length, max_chunk_len) as usize;
1097    let mut buf = IoBuffer::new(buflen, storage.mem_align())?;
1098    buf.as_mut().into_slice().fill(0);
1099
1100    while length > 0 {
1101        let chunk_len = cmp::min(length, max_chunk_len) as usize;
1102        unsafe {
1103            storage
1104                .pure_writev(buf.as_ref_range(0..chunk_len).into(), offset)
1105                .await
1106        }?;
1107        offset += chunk_len as u64;
1108        length -= chunk_len as u64;
1109    }
1110
1111    Ok(())
1112}