Trait FormatDriverInstance

Source
pub trait FormatDriverInstance:
    Any
    + Debug
    + Display
    + Send
    + Sync {
    type Storage: Storage;

Show 18 methods // Required methods fn format(&self) -> Format; unsafe fn probe<'life0, 'async_trait>( storage: &'life0 Self::Storage, ) -> Pin<Box<dyn Future<Output = Result<bool>> + 'async_trait>> where Self: Sized + 'async_trait, 'life0: 'async_trait; fn size(&self) -> u64; fn collect_storage_dependencies(&self) -> Vec<&Self::Storage>; fn writable(&self) -> bool; fn get_mapping<'a, 'async_trait>( &'a self, offset: u64, max_length: u64, ) -> Pin<Box<dyn Future<Output = Result<(ShallowMapping<'a, Self::Storage>, u64)>> + 'async_trait>> where Self: 'async_trait, 'a: 'async_trait; fn ensure_data_mapping<'a, 'async_trait>( &'a self, offset: u64, length: u64, overwrite: bool, ) -> Pin<Box<dyn Future<Output = Result<(&'a Self::Storage, u64, u64)>> + 'async_trait>> where Self: 'async_trait, 'a: 'async_trait; fn flush<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<()>> + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait; fn sync<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<()>> + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait; unsafe fn invalidate_cache<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<()>> + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait; fn resize_grow<'life0, 'async_trait>( &'life0 self, new_size: u64, prealloc_mode: PreallocateMode, ) -> Pin<Box<dyn Future<Output = Result<()>> + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait; fn resize_shrink<'life0, 'async_trait>( &'life0 mut self, new_size: u64, ) -> Pin<Box<dyn Future<Output = Result<()>> + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait; // Provided methods fn zero_granularity(&self) -> Option<u64> { ... } fn ensure_zero_mapping<'life0, 'async_trait>( &'life0 self, _offset: u64, _length: u64, ) -> Pin<Box<dyn Future<Output = Result<(u64, u64)>> + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait { ... } fn discard_to_zero<'life0, 'async_trait>( &'life0 mut self, _offset: u64, _length: u64, ) -> Pin<Box<dyn Future<Output = Result<(u64, u64)>> + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait { ... } fn discard_to_any<'life0, 'async_trait>( &'life0 mut self, _offset: u64, _length: u64, ) -> Pin<Box<dyn Future<Output = Result<(u64, u64)>> + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait { ... } fn discard_to_backing<'life0, 'async_trait>( &'life0 mut self, _offset: u64, _length: u64, ) -> Pin<Box<dyn Future<Output = Result<(u64, u64)>> + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait { ... } fn readv_special<'life0, 'life1, 'async_trait>( &'life0 self, _bufv: IoVectorMut<'life1>, _offset: u64, ) -> Pin<Box<dyn Future<Output = Result<()>> + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait { ... }
}
Expand description

Implementation of a disk image format.

Required Associated Types§

Source

type Storage: Storage

Type of storage used.

Required Methods§

Source

fn format(&self) -> Format

Return which format this is.

Source

unsafe fn probe<'life0, 'async_trait>( storage: &'life0 Self::Storage, ) -> Pin<Box<dyn Future<Output = Result<bool>> + 'async_trait>>
where Self: Sized + 'async_trait, 'life0: 'async_trait,

Check whether storage has this format.

This is only a rough test and does not guarantee that opening storage under this format will succeed. Generally, it will only check the magic bytes (if available). For formats that do not have distinct features (like raw), this will always return true.

§Safety

Probing is inherently dangerous: Image formats like qcow2 allow referencing external files; if you use imago to give untrusted parties (like VM guests) access to VM disk image files, this will give those parties access to data in those files. Opening images from untrusted sources can therefore be quite dangerous. Gating (ImplicitOpenGate) can help mitigate this.

If you do not know an image’s format, that is a sign it does not come from a trusted source, and so opening it in a non-raw format may be quite dangerous.

Perhaps most important to note is that giving an untrusted party (like a VM guest) access to a raw image file allows that party to modify the whole file. It may write image headers into this image file, causing a subsequent probe operation to recognize it as a non-raw image, referencing arbitrary files on the host filesystem!

When using imago to give an untrusted third party access to VM disk images, the guidelines for probing are thus:

  • Do not probe. If at all possible, obtain an image’s format from a trusted side channel.
  • If there is no other way, probe each given image only once, before that untrusted third party (like a VM guest) had write access to it; remember the probed format, and open the image exclusively as that format.

When working with even potentially untrusted images, you should always use an ImplicitOpenGate to prevent access to files you do not wish to access.

Source

fn size(&self) -> u64

Size of the disk represented by this image.

Source

fn collect_storage_dependencies(&self) -> Vec<&Self::Storage>

Recursively collect all storage objects associated with this image.

“Recursive” means to recurse to other images like e.g. a backing file.

Source

fn writable(&self) -> bool

Return whether this image may be modified.

This state must not change via interior mutability, i.e. as long as this FDI is wrapped in a FormatAccess, its writability must remain constant.

Source

fn get_mapping<'a, 'async_trait>( &'a self, offset: u64, max_length: u64, ) -> Pin<Box<dyn Future<Output = Result<(ShallowMapping<'a, Self::Storage>, u64)>> + 'async_trait>>
where Self: 'async_trait, 'a: 'async_trait,

Return the mapping at offset.

Find what offset is mapped to, return that mapping information, and the length of that continuous mapping (from offset).

To determine that continuous mapping length, drivers should not perform additional I/O beyond what is necessary to get mapping information for offset itself.

max_length is a hint how long of a range is required at all, but the returned length may exceed that value if that simplifies the implementation.

The returned length must only be 0 if ShallowMapping::Eof is returned.

Source

fn ensure_data_mapping<'a, 'async_trait>( &'a self, offset: u64, length: u64, overwrite: bool, ) -> Pin<Box<dyn Future<Output = Result<(&'a Self::Storage, u64, u64)>> + 'async_trait>>
where Self: 'async_trait, 'a: 'async_trait,

Ensure that offset is directly mapped to some storage object, up to a length of length.

Return the storage object, the corresponding offset there, and the continuous length that the driver was able to map (less than or equal to length).

If the returned length is less than length, drivers can expect subsequent calls to allocate the rest of the original range. Therefore, if a driver knows in advance that it is impossible to fully map the given range (e.g. because it lies partially or fully beyond the end of the disk), it should return an error immediately.

If overwrite is true, the contents in the range are supposed to be overwritten and may be discarded. Otherwise, they must be kept.

Should not break existing data mappings, i.e. not discard or repurpose existing data mappings. Making them unused, but retaining them as allocated so they can safely be written to (albeit with no effect) is OK; discarding them so that they may be reused for other mappings is not.

Source

fn flush<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<()>> + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Flush internal buffers.

Does not need to ensure those buffers are synced to disk (hardware), and does not need to drop them, i.e. they may still be used on later accesses.

Source

fn sync<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<()>> + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Sync data already written to the storage hardware.

Does not need to ensure internal buffers are written, i.e. should generally just be passed through to Storage::sync() for all underlying storage objects.

Source

unsafe fn invalidate_cache<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<()>> + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Drop internal buffers.

Drop all internal buffers, but do not flush them! All internal data must then be reloaded from disk.

§Safety

Not flushing internal buffers may cause image corruption. The caller must ensure the on-disk state is consistent.

Source

fn resize_grow<'life0, 'async_trait>( &'life0 self, new_size: u64, prealloc_mode: PreallocateMode, ) -> Pin<Box<dyn Future<Output = Result<()>> + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Resize to the given size, which must be greater than the current size.

Set the disk size to new_size, preallocating the new space according to prealloc_mode. Depending on the image format, it is possible some preallocation modes are not supported, in which case an std::io::ErrorKind::Unsupported is returned.

If the current size is already new_size or greater, do nothing.

Source

fn resize_shrink<'life0, 'async_trait>( &'life0 mut self, new_size: u64, ) -> Pin<Box<dyn Future<Output = Result<()>> + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Truncate to the given size, which must be smaller than the current size.

Set the disk size to new_size, discarding the data after new_size.

May break existing data mappings thanks to the mutable self reference.

If the current size is already new_size or smaller, do nothing.

Provided Methods§

Source

fn zero_granularity(&self) -> Option<u64>

Granularity on which blocks can be marked as zero.

This is the granularity for FormatDriverInstance::ensure_zero_mapping().

Return None if zero blocks are not supported.

Source

fn ensure_zero_mapping<'life0, 'async_trait>( &'life0 self, _offset: u64, _length: u64, ) -> Pin<Box<dyn Future<Output = Result<(u64, u64)>> + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Ensure that the given range is efficiently mapped as zeroes.

Must not write any data. Return the range (offset and length) that could actually be zeroed, which must be a subset of the range given by offset and length. The returned offset must be as close to offset as possible, i.e. no zero mapping is possible between offset and the returned offset (e.g. because of format-inherent granularity).

The returned length may be zero in case zeroing would theoretically be possible, but not for this range at this granularity.

Should not break existing data mappings, i.e. not discard or repurpose existing data mappings. Making them unused, but retaining them as allocated so they can safely be written to (albeit with no effect) is OK; discarding them so that they may be reused for other mappings is not.

Source

fn discard_to_zero<'life0, 'async_trait>( &'life0 mut self, _offset: u64, _length: u64, ) -> Pin<Box<dyn Future<Output = Result<(u64, u64)>> + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Discard the given range, ensure it is read back as zeroes.

Effectively the same as FormatDriverInstance::ensure_zero_mapping(), but may break existing data mappings thanks to the mutable self reference, which ensures that old data mappings returned by FormatDriverInstance::get_mapping() cannot be held onto.

Source

fn discard_to_any<'life0, 'async_trait>( &'life0 mut self, _offset: u64, _length: u64, ) -> Pin<Box<dyn Future<Output = Result<(u64, u64)>> + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Discard the given range.

Effectively the same as FormatDriverInstance::discard_to_zero(), but the discarded area may read as any data. Backing file data should not reappear, however.

Source

fn discard_to_backing<'life0, 'async_trait>( &'life0 mut self, _offset: u64, _length: u64, ) -> Pin<Box<dyn Future<Output = Result<(u64, u64)>> + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Discard the given range, such that the backing image becomes visible.

Deallocate the range such that in deallocated blocks, the backing image’s data (if one exists) will show, i.e. FormatDriverInstance::get_mapping() should return an indirect mapping. When there is no backing image, those blocks should appear as zero.

Return the range (offset and length) that could actually be discarded, which must be a subset of offset and length, and the returned offset must be as close to offset as possible (like for FormatDriverInstance::discard_to_backing().

May break existing data mappings thanks to the mutable self reference.

Source

fn readv_special<'life0, 'life1, 'async_trait>( &'life0 self, _bufv: IoVectorMut<'life1>, _offset: u64, ) -> Pin<Box<dyn Future<Output = Result<()>> + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Read data from a ShallowMapping::Special area.

Implementors§