blob: e01d91c60b57979f691b16e8a8dfaf018e4c37ad [file] [log] [blame]
// 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.
closed 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.
strict 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`.
///
/// **NOTE**: GetInfo() is used to synchronize child partition device visibility with devfs.
/// Implementations must only respond once all child partitions of `VolumeManager` have been
/// added to devfs, to guarantee clients can safely enumerate them.
///
/// See https://fxbug.dev/42077585 for more information.
strict 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.
strict 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.
strict 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.
strict 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.
strict 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.
closed 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.
strict 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.
strict 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).
strict 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.
strict 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.
strict Destroy() -> (struct {
status zx.Status;
});
};
/// This protocol is intended to emulate a block device.
// TODO(https://fxbug.dev/42054916): Make this protocol test-only.
// TODO(https://fxbug.dev/42063787): Remove this protocol entirely.
closed protocol VolumeAndNode {
compose Volume;
compose io.Node;
compose device.Controller;
};