| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| library fuchsia.hardware.block.volume; |
| |
| using fuchsia.device as device; |
| using fuchsia.hardware.block.partition as partition; |
| using fuchsia.io as io; |
| using zx; |
| |
| /// VolumeManagerInfo describes the properties of the volume manager and not each individual volume. |
| type VolumeManagerInfo = struct { |
| /// Size of a single slice, in bytes. |
| slice_size uint64; |
| |
| /// Number of slices the volume manager is able use right now. This counts the |
| /// allocated_slice_count plus the number of available slices. |
| slice_count uint64; |
| |
| /// Number of slices currently assigned to partitions. |
| assigned_slice_count uint64; |
| |
| /// The maximum capacity which the Volume Manager could grow to utilize if the partition |
| /// containing the Volume Manager itself expands (i.e., the Volume Manager is initialized on a |
| /// GPT partition that has extended beyond the originally allocated capacity). This value is |
| /// the number of entries reserved in the volume manager header and is not related to the size |
| /// of the physical device (which may be larger or smaller). |
| maximum_slice_count uint64; |
| |
| /// Largest value that can be used for a virtual slice number. |
| max_virtual_slice uint64; |
| }; |
| |
| type VolumeInfo = struct { |
| /// Number of slices allocated to the volume. |
| partition_slice_count uint64; |
| |
| /// Limit on the maximum slices assigned to this partition, if there is one. If the size of the |
| /// partition is not limited, this value will be 0. Partitions can grow into free slices |
| /// available in the volume manager as long as their slices are less than or equal to this |
| /// value. |
| /// |
| /// The partition may be larger than this limit if a smaller limit was applied after the |
| /// partition had already grown to the current size. |
| /// |
| /// See `VolumeManager.GetPartitionLimit()` |
| slice_limit uint64; |
| }; |
| |
| /// Indicates that the partition should be created as inactive, implying that it |
| /// will be destroyed on reboot (unless activated by a call to "Activate"). |
| const ALLOCATE_PARTITION_FLAG_INACTIVE uint32 = 0x00000001; |
| |
| /// VolumeManager controls a collection of Volumes. |
| protocol VolumeManager { |
| /// Allocates a virtual partition with the requested features. |
| /// |
| /// `slice_count` is the number of slices initially allocated to the partition, at |
| /// offset zero. The number of slices allocated to a new partition must be at least one. |
| /// `type` and `value` indicate type and instance GUIDs for the partition, respectively. |
| /// `name` indicates the name of the new partition. |
| AllocatePartition(struct { |
| slice_count uint64; |
| type partition.Guid; |
| instance partition.Guid; |
| name string:partition.NAME_LENGTH; |
| flags uint32; |
| }) -> (struct { |
| status zx.status; |
| }); |
| |
| /// Gets the VolumeManagerInfo describing this instance of the `VolumeManager`. |
| GetInfo() -> (struct { |
| status zx.status; |
| info box<VolumeManagerInfo>; |
| }); |
| |
| /// Atomically marks a vpartition (by instance GUID) as inactive, while finding |
| /// another partition (by instance GUID) and marking it as active. |
| /// |
| /// If the "old" partition does not exist, the GUID is ignored. |
| /// If the "old" partition is the same as the "new" partition, the "old" |
| /// GUID is ignored. |
| /// If the "new" partition does not exist, `ZX_ERR_NOT_FOUND` is returned. |
| /// |
| /// This function does not destroy the "old" partition, it just marks it as |
| /// inactive -- to reclaim that space, the "old" partition must be explicitly |
| /// destroyed. This destruction can also occur automatically when the FVM driver |
| /// is rebound (i.e., on reboot). |
| /// |
| /// This function may be useful for A/B updates within the FVM, |
| /// since it will allow activating updated partitions. |
| Activate(struct { |
| old_guid partition.Guid; |
| new_guid partition.Guid; |
| }) -> (struct { |
| status zx.status; |
| }); |
| |
| /// Retrieves the allocation limit for the partition. A return value of 0 indicates that there |
| /// is no limit and the partition can be extended as long as there is available space on the |
| /// device. |
| /// |
| /// The partition may be larger than this limit if a smaller limit was applied after the |
| /// partition had already grown to the current size. |
| /// |
| /// Currently the partition limit is not persisted across reboots but this may change in the |
| /// future. |
| GetPartitionLimit(struct { |
| guid partition.Guid; |
| }) -> (struct { |
| status zx.status; |
| slice_count uint64; |
| }); |
| |
| /// Sets the allocation limit for the partition. Partitions can not be extended beyond their |
| /// allocation limit. The partition limit will never shrink partitions so if this value is |
| /// less than the current partition size, it will keep the current size but prevent further |
| /// growth. |
| /// |
| /// The allocation limits are on the VolumeManager API rather than on the partition because |
| /// they represent a higher capability level. These limits are designed to put guards on |
| /// users of the block device (and hence the Volume API). |
| /// |
| /// Currently the partition limit is not persisted across reboots but this may change in the |
| /// future. |
| SetPartitionLimit(struct { |
| guid partition.Guid; |
| slice_count uint64; |
| }) -> (struct { |
| status zx.status; |
| }); |
| |
| /// Renames the specified partition. Any existing devices that include the name of the partition |
| /// in their topological path might *not* reflect the name change until the next time that the |
| /// device is instantiated. |
| SetPartitionName(struct { |
| guid partition.Guid; |
| name string:<partition.NAME_LENGTH>; |
| }) -> () error zx.status; |
| }; |
| |
| /// An arbitrary cap on the number of slices which may be requested when querying |
| /// for allocation information from a volume. |
| const MAX_SLICE_REQUESTS uint32 = 16; |
| |
| /// VsliceRange describes a range of virtual slices: start, length, and allocated status. |
| /// |
| /// These ranges are returned in an ordered container, which implicitly describes the |
| /// starting offset, starting from the "index zero" slice. |
| type VsliceRange = struct { |
| /// True if the virtual slices are allocated, false otherwise. |
| allocated bool; |
| |
| /// The number of contiguous virtual slices. |
| count uint64; |
| }; |
| |
| /// Volume is a partition which may access virtually-mapped blocks within a device. |
| protocol Volume { |
| compose partition.Partition; |
| |
| /// Returns the number of contiguous allocated (or unallocated) vslices |
| /// starting from each vslice. |
| /// |
| // TODO(smklein): Replace array with vector; doing so would be non-simple. |
| QuerySlices(struct { |
| start_slices vector<uint64>:MAX_SLICE_REQUESTS; |
| }) -> (struct { |
| status zx.status; |
| response array<VsliceRange, MAX_SLICE_REQUESTS>; |
| response_count uint64; |
| }); |
| |
| /// Returns the information about this volume and the volume manager it is embedded in. |
| GetVolumeInfo() -> (struct { |
| status zx.status; |
| manager box<VolumeManagerInfo>; |
| volume box<VolumeInfo>; |
| }); |
| |
| /// Extends the mapping of this partition. |
| /// |
| /// The ability to extend the partition is dependent on having sufficient free space on the |
| /// underlying device, having sufficient free slots for tracking the bytes in the volume |
| /// manager header, and the partition limit (see VolumeManager.SetPartitionLimit). |
| Extend(struct { |
| start_slice uint64; |
| slice_count uint64; |
| }) -> (struct { |
| status zx.status; |
| }); |
| |
| /// Shrinks a virtual partition. Returns `ZX_OK` if ANY slices are |
| /// freed, even if part of the requested range contains unallocated slices. |
| Shrink(struct { |
| start_slice uint64; |
| slice_count uint64; |
| }) -> (struct { |
| status zx.status; |
| }); |
| |
| /// Destroys the current partition, removing it from the VolumeManager, and |
| /// freeing all underlying storage. The connection to the volume is also closed. |
| Destroy() -> (struct { |
| status zx.status; |
| }); |
| }; |
| |
| /// This protocol is intended to emulate a block device. |
| // TODO(https://fxbug.dev/103827): Make this protocol test-only. |
| // TODO(https://fxbug.dev/112484): Remove this protocol entirely. |
| closed protocol VolumeAndNode { |
| compose Volume; |
| compose io.Node; |
| compose device.Controller; |
| }; |