Add volume_factory
The volume_factory defines a common interface for constructing and
destroying storage volume objects. A factory may construct any
concrete volume to suite the needs of a deployment. A single flash
volume factory is included that constructs volume objects that
present storage partitions on a block device as volumes. A single
storage device is assumed by the factory.
Signed-off-by: Julian Hall <julian.hall@arm.com>
Change-Id: I12a0a070c41cbcf2a8dbddaabbbde2aba4f244fa
diff --git a/components/media/volume/factory/single_flash/component.cmake b/components/media/volume/factory/single_flash/component.cmake
new file mode 100644
index 0000000..fe1c9c6
--- /dev/null
+++ b/components/media/volume/factory/single_flash/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/volume_factory.c"
+)
\ No newline at end of file
diff --git a/components/media/volume/factory/single_flash/volume_factory.c b/components/media/volume/factory/single_flash/volume_factory.c
new file mode 100644
index 0000000..0f302cc
--- /dev/null
+++ b/components/media/volume/factory/single_flash/volume_factory.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <trace.h>
+#include <service/block_storage/factory/block_store_factory.h>
+#include <service/block_storage/block_store/block_store.h>
+#include <media/volume/factory/volume_factory.h>
+#include <media/volume/block_volume/block_volume.h>
+#include <media/disk/guid.h>
+
+/**
+ * A volume factory for single flash deployments where underlying block-level
+ * access is provided by a block_store object. The block_store used is provided
+ * by the block_store_factory selected for the deployment. This could construct
+ * any suitable block_store.
+ */
+static struct block_store *single_block_store;
+
+int volume_factory_init(
+ struct uuid_octets *device_uuids,
+ size_t device_uuids_size,
+ size_t *num_device_uuids)
+{
+ assert(device_uuids || !device_uuids_size);
+ assert(num_device_uuids);
+
+ *num_device_uuids = 0;
+ single_block_store = block_store_factory_create();
+
+ if (!single_block_store) {
+
+ EMSG("Failed to construct block_store");
+ return -EIO;
+ }
+
+ if (device_uuids_size > 0) {
+
+ struct storage_partition_info device_info;
+ struct uuid_octets uuid;
+
+ /* Query for GPT partition to get info about the parent device */
+ uuid_guid_octets_from_canonical(&uuid,
+ DISK_GUID_UNIQUE_PARTITION_DISK_HEADER);
+
+ psa_status_t psa_status = block_store_get_partition_info(single_block_store,
+ &uuid, &device_info);
+
+ if (psa_status == PSA_SUCCESS)
+ device_uuids[0] = device_info.parent_guid;
+ else
+ memset(&device_uuids[0], 0, sizeof(struct uuid_octets));
+
+ *num_device_uuids = 1;
+ }
+
+ return 0;
+}
+
+void volume_factory_deinit(void)
+{
+ block_store_factory_destroy(single_block_store);
+ single_block_store = NULL;
+}
+
+struct volume *volume_factory_create_volume(
+ const struct uuid_octets *partition_uuid,
+ const struct uuid_octets *device_uuid)
+{
+ struct volume *product = NULL;
+
+ assert(single_block_store);
+
+ /* This factory assumes that all volumes are backed by a single block device */
+ (void)device_uuid;
+
+ struct block_volume *block_volume =
+ (struct block_volume *)malloc(sizeof(struct block_volume));
+
+ if (block_volume) {
+
+ int status = block_volume_init(block_volume,
+ single_block_store, partition_uuid,
+ &product);
+
+ if (status) {
+
+ EMSG("Failed to init block volume: %d", status);
+ product = NULL;
+ free(block_volume);
+ }
+ } else {
+
+ EMSG("Failed to alloc block volume");
+ }
+
+ return product;
+}
+
+void volume_factory_destroy_volume(
+ struct volume *volume)
+{
+ if (volume && volume->io_spec)
+ free((void *)volume->io_spec);
+}
diff --git a/components/media/volume/factory/volume_factory.h b/components/media/volume/factory/volume_factory.h
new file mode 100644
index 0000000..f7e9115
--- /dev/null
+++ b/components/media/volume/factory/volume_factory.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MEDIA_VOLUME_FACTORY_H
+#define MEDIA_VOLUME_FACTORY_H
+
+#include <stddef.h>
+#include <common/uuid/uuid.h>
+#include <media/volume/volume.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Initialise the singleton volume_factory
+ *
+ * Initialises the deployment specific volume factory. Once initialised, the volume_factory
+ * will be ready to construct volume objects that can provide IO access to the requested
+ * storage. The details of how the storage is accessed is hidden from the client. A set
+ * of device UUIDs is returned, each identifying a storage device that can potentially be
+ * accessed using a constructed volume.
+ *
+ * \param[out] device_uuids Array of available device UUIDs
+ * \param[in] device_uuids_size Number of slots in the provided array
+ * \param[out] num_device_uuids The number of device UUIDs actually returned
+ *
+ * \return Status (0 on success)
+ */
+int volume_factory_init(
+ struct uuid_octets *device_uuids,
+ size_t device_uuids_size,
+ size_t *num_device_uuids);
+
+/**
+ * \brief De-initialises the volume_factory
+ */
+void volume_factory_deinit(void);
+
+/**
+ * \brief Common interface for constructing volume objects
+ *
+ * The volume_factory provides a common interface for constructing volume objects,
+ * decoupling client code from the details of initialising a concrete volume.
+ * Volume objects created by the factory should also be destroyed by the factory.
+ *
+ * \param[in] partition_uuid Identifies the unit of storage (e.g. a unique partition uuid)
+ * \param[in] device_uuid Identifies the parent device
+ *
+ * \return Pointer to volume or NULL
+ */
+struct volume *volume_factory_create_volume(
+ const struct uuid_octets *partition_uuid,
+ const struct uuid_octets *device_uuid);
+
+/**
+ * \brief Destroys a volume object
+ *
+ * \param[in] volume Volume to destroy
+ */
+void volume_factory_destroy_volume(
+ struct volume *volume);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MEDIA_VOLUME_FACTORY_H */