blob: f83403a0bb088a605b2a407d5b5ee149720ff485 [file] [log] [blame] [view] [edit]
# Routing a storage partition to a component
While most components interact with storage through a filesystem using their
storage capabilities, certain components may need to be able to directly read
and write a partition. This guide explains how to route a partition to a
component.
The steps, at a high level, are:
1. **Define a semantic label in the board configuration**: Define a mapping of
a physical partition label to a "semantic" label, which will be the name of
the partition used in capability routing.
2. **Update component manifests**: Routing the directory capability for the
block device to the component.
3. **Access the block device in the component**: The component uses the routed
directory capability to access the block device.
## Steps
### 1. Define a semantic label in the board configuration
The first step is to declare a semantic label for the physical partition in your
board's configuration, which is typically a `.bazel` or `.bzl` file located in
`//boards/` or a vendor-specific equivalent.
In the board's configuration, add a `block_devices` list to the `filesystems`
dictionary. Each entry in this list is a dictionary that defines a new named
device.
* `device`: The semantic label you will use to refer to this partition in
component manifests.
* `from`: Specifies where the partition should be found on the disk.
+ `label`: The GPT label of the partition to be routed.
+ `parent`: The parent device, which is usually "gpt".
**Example**: In your board's `BUILD.bazel` file:
```python
# In a board definition
fuchsia_board_configuration(
name = "my_board",
...
filesystems = {
"block_devices": [
{
"device": "my_partition",
"from": {
"label": "my-partition-label",
"parent": "gpt",
},
},
{
"device": "my_other_partition",
"from": {
"label": "my-other-partition-label",
"parent": "gpt",
},
},
],
...
},
...
)
```
This configuration is provided to `fshost` , which will match for GPT partitions
with the label "my-partition-label" and provide them at "/block/my_partition"
(and similarly for my-other-partition-label).
### 2. Route the Block Device to Your Component
Once the board is configured, you must route the capability for the block device
from `fshost` down to your component. This is done by adding `offer` stanzas to
the component manifests ( `.cml` files) of the parent components in the
topology.
The capability is a `directory` provided by `fshost` under the path `/block` .
The specific partition is selected by using the `subdir` parameter in the `offer`
stanza, which must match the `device` name you defined in the board
configuration.
In this example, we are routing a partition to a component in the `core` realm,
but steps are similar for other realms. Modify the core shard for the component
to route the partition to it:
```cml
// my_component.core_shard.cml
{
offer: [
{
directory: "block",
from: "parent",
to: "#my_component",
subdir: "my_partition",
as: "my_partition",
},
{
directory: "block",
from: "parent",
to: "#my_component",
subdir: "my_other_partition",
as: "my_other_partition",
},
...
],
...
}
```
### 3. Use the Block Device in Your Component
The final step is for your component to `use` the routed directory capability.
In your component's manifest ( `my_component.cml` ), add a `use` stanza for the
directory.
**Example**: `my_component.cml`
```cml
{
use: [
{
directory: "my_partition",
rights: [ "r*" ],
path: "/block/my_partition",
},
{
directory: "my_other_partition",
rights: [ "r*" ],
path: "/block/my_other_partition",
},
...
],
}
```
Your component can now access the partitions in its namespace at `/block` . To
connect to the `fuchsia.hardware.block.volume.Volume` protocol for a given
partition, you connect via this path:
```rust
use fidl_fuchsia_hardware_block_volume::VolumeMarker;
use block_client::RemoteBlockClient;
async fn connect_to_my_partition() -> Result<(), anyhow::Error> {
let proxy = fuchsia_component::client::connect_to_protocol_at::<VolumeMarker>(
"/block/my_partition/fuchsia.hardware.block.volume.Volume"
)?;
let block_client = RemoteBlockClient::new(proxy).await?;
// ... use the block client
Ok(())
}
```