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:

# 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:

// 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

{
    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:

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(())
}