@@ -15,6 +15,7 @@
#include "block/block.h"
#include "monitor/monitor.h"
#include "qemu/thread.h"
+#include "sysemu/sysemu.h"
/*
#define VNVRAM_DEBUG
@@ -821,3 +822,268 @@ static int vnvram_rwrequest_schedule(VNVRAMRWRequest *rwr)
return rc;
}
+
+/************************* VNVRAM APIs *******************************/
+/* VNVRAM APIs that can be used by QEMU to provide persistent storage*/
+/*********************************************************************/
+
+/*
+ * Initialize VNVRAM
+ *
+ * This must be called before any other APIs.
+ */
+int vnvram_init(void)
+{
+ qemu_mutex_init(&vnvram_rwrequests_mutex);
+ vnvram_bh = qemu_bh_new(vnvram_rwrequest_callback, NULL);
+ DPRINTF("%s: VNVRAM initialized\n", __func__);
+
+ return 0;
+}
+
+/*
+ * Create a VNVRAM instance
+ *
+ * The VNVRAM instance will use the drive with the corresponding ID as
+ * its persistent storage device.
+ */
+VNVRAM *vnvram_create(const char *drv_id, bool fail_on_invalid, int *errcode)
+{
+ int rc;
+ VNVRAM *vnvram = NULL;
+ VNVRAMDrvHdr hdr;
+ BlockDriverState *bds;
+
+ *errcode = 0;
+
+ if (runstate_check(RUN_STATE_INMIGRATE)) {
+ qerror_report(QERR_MIGRATION_ACTIVE);
+ rc = -EAGAIN;
+ goto err_exit;
+ }
+
+ bds = bdrv_find(drv_id);
+ if (!bds) {
+ qerror_report(QERR_DEVICE_NOT_FOUND, drv_id);
+ rc = -ENOENT;
+ goto err_exit;
+ }
+
+ if (bdrv_is_read_only(bds)) {
+ qerror_report(QERR_DEVICE_IS_READ_ONLY, drv_id);
+ rc = -EPERM;
+ goto err_exit;
+ }
+
+ bdrv_lock_medium(bds, true);
+
+ vnvram = vnvram_drv_find_by_id(drv_id);
+ if (vnvram) {
+ /* This VNVRAM was already created - sucess */
+ return vnvram;
+ }
+
+ vnvram = g_new0(VNVRAM, 1);
+ vnvram->drv_id = g_strdup(drv_id);
+ vnvram->bds = bds;
+
+ QLIST_INIT(&vnvram->entries_head);
+
+ rc = vnvram_drv_adjust_size(vnvram);
+ if (rc != 0) {
+ qerror_report(QERR_IO_ERROR);
+ goto err_exit;
+ }
+
+ rc = vnvram_drv_hdr_read(vnvram, (&hdr));
+ if (rc != 0) {
+ qerror_report(QERR_IO_ERROR);
+ goto err_exit;
+ }
+
+ if (vnvram_drv_hdr_is_valid(vnvram, (&hdr))) {
+ rc = vnvram_sync_from_drv(vnvram, (&hdr));
+ if (rc != 0) {
+ qerror_report(ERROR_CLASS_GENERIC_ERROR, "VNVRAM drive sync error");
+ goto err_exit;
+ }
+
+ if (vnvram_entries_are_valid(vnvram, bdrv_getlength(vnvram->bds))) {
+ /* Sync'd VNVRAM drive looks good - success */
+ goto exit;
+ }
+ }
+
+ /* Drive data looks invalid. Could be encrypted and we didn't get key? */
+ if (bdrv_is_encrypted(vnvram->bds)) {
+ DPRINTF("%s: VNVRAM drive is encrypted\n", __func__);
+ }
+
+ /* Either fail or reformat the drive. */
+ if (fail_on_invalid) {
+ qerror_report(ERROR_CLASS_GENERIC_ERROR, "VNVRAM drive not valid");
+ rc = -EIO;
+ goto err_exit;
+ }
+
+ rc = vnvram_drv_hdr_create_empty(vnvram);
+ if (rc != 0) {
+ qerror_report(QERR_IO_ERROR);
+ goto err_exit;
+ }
+
+exit:
+ QLIST_INSERT_HEAD(&vnvrams, vnvram, list);
+ DPRINTF("%s: VNVRAM with drive '%s' created\n", __func__, vnvram->drv_id);
+
+ return vnvram;
+
+err_exit:
+ if (vnvram) {
+ g_free(vnvram->drv_id);
+ }
+ g_free(vnvram);
+ *errcode = rc;
+
+ return NULL;
+}
+
+/*
+ * Register a VNVRAM entry
+ *
+ * The entry information will not be flushed to the drive until the next
+ * write.
+ */
+int vnvram_register_entry(VNVRAM *vnvram, const VNVRAMEntryName *entry_name,
+ uint32_t max_size)
+{
+ if (!vnvram_exists(vnvram)) {
+ qerror_report(ERROR_CLASS_GENERIC_ERROR, "VNVRAM has not been created");
+ return -EPERM;
+ }
+
+ return vnvram_register_entry_internal(vnvram, entry_name, 0, 0, max_size);
+}
+
+/*
+ * Deregister a VNVRAM entry
+ */
+int vnvram_deregister_entry(VNVRAM *vnvram, const VNVRAMEntryName *entry_name)
+{
+ VNVRAMEntry *entry;
+
+ if (!vnvram_exists(vnvram)) {
+ qerror_report(ERROR_CLASS_GENERIC_ERROR, "VNVRAM has not been created");
+ return -EPERM;
+ }
+
+ QLIST_FOREACH(entry, &vnvram->entries_head, next) {
+ if (!strncmp(entry->name, (char *)entry_name, sizeof(*entry_name))) {
+ if (entry->cur_size != 0) {
+ qerror_report(ERROR_CLASS_GENERIC_ERROR,
+ "VNVRAM entry already written to disk");
+ return -EPERM;
+ }
+ QLIST_REMOVE(entry, next);
+ g_free(entry);
+ DPRINTF("%s: Deregistered VNVRAM entry '%s'\n", __func__,
+ (char *)entry_name);
+ return 0;
+ }
+ }
+
+ qerror_report(ERROR_CLASS_GENERIC_ERROR, "VNVRAM entry not found");
+
+ return -ENOENT;
+}
+
+/*
+ * Read a VNVRAM blob from the specified drive entry
+ */
+int vnvram_read_entry(VNVRAM *vnvram, const VNVRAMEntryName *entry_name,
+ char **blob, uint32_t *blob_size)
+{
+ int rc;
+ VNVRAMEntry *entry;
+ VNVRAMRWRequest *rwr;
+
+ *blob = NULL;
+ *blob_size = 0;
+
+ if (!vnvram_exists(vnvram)) {
+ qerror_report(ERROR_CLASS_GENERIC_ERROR, "VNVRAM has not been created");
+ return -EPERM;
+ }
+
+ entry = vnvram_find_entry(vnvram, entry_name);
+ if (!entry) {
+ qerror_report(ERROR_CLASS_GENERIC_ERROR, "VNVRAM entry not found");
+ return -ENOENT;
+ }
+
+ rwr = vnvram_rwrequest_init_read(vnvram, entry, blob, blob_size);
+
+ rc = vnvram_rwrequest_schedule(rwr);
+
+ g_free(rwr);
+
+ return rc;
+}
+
+/*
+ * Write a VNVRAM blob to the specified drive entry
+ */
+int vnvram_write_entry(VNVRAM *vnvram, const VNVRAMEntryName *entry_name,
+ char *blob, uint32_t blob_size)
+{
+ int rc;
+ VNVRAMEntry *entry;
+ VNVRAMRWRequest *rwr;
+
+ if (!vnvram_exists(vnvram)) {
+ qerror_report(ERROR_CLASS_GENERIC_ERROR, "VNVRAM has not been created");
+ return -EPERM;
+ }
+
+ entry = vnvram_find_entry(vnvram, entry_name);
+ if (!entry) {
+ qerror_report(ERROR_CLASS_GENERIC_ERROR, "VNVRAM entry not found");
+ return -ENOENT;
+ }
+
+ rwr = vnvram_rwrequest_init_write(vnvram, entry, blob, blob_size);
+
+ rc = vnvram_rwrequest_schedule(rwr);
+
+ g_free(rwr);
+
+ return rc;
+}
+
+/*
+ * Delete a VNVRAM from memory
+ */
+int vnvram_delete(VNVRAM *vnvram)
+{
+ VNVRAMEntry *entry;
+
+ if (!vnvram_exists(vnvram)) {
+ qerror_report(ERROR_CLASS_GENERIC_ERROR, "VNVRAM has not been created");
+ return -EPERM;
+ }
+
+ QLIST_FOREACH(entry, &vnvram->entries_head, next) {
+ QLIST_REMOVE(entry, next);
+ g_free(entry);
+ }
+
+ QLIST_REMOVE(vnvram, list);
+
+ DPRINTF("%s: VNVRAM with drive '%s' deleted from memory\n",
+ __func__, vnvram->drv_id);
+
+ g_free(vnvram->drv_id);
+ g_free(vnvram);
+
+ return 0;
+}
@@ -14,9 +14,23 @@
#ifndef _QEMU_VNVRAM_H_
#define _QEMU_VNVRAM_H_
+#include <stdint.h>
+#include <stdbool.h>
+
typedef struct VNVRAM VNVRAM;
#define VNVRAM_ENTRY_NAME_LENGTH 16
typedef char VNVRAMEntryName[VNVRAM_ENTRY_NAME_LENGTH];
+int vnvram_init(void);
+VNVRAM *vnvram_create(const char *drv_id, bool fail_on_invalid, int *errcode);
+int vnvram_register_entry(VNVRAM *vnvram, const VNVRAMEntryName *entry_name,
+ uint32_t max_size);
+int vnvram_deregister_entry(VNVRAM *vnvram, const VNVRAMEntryName *entry_name);
+int vnvram_read_entry(VNVRAM *vnvram, const VNVRAMEntryName *entry_name,
+ char **blob, uint32_t *blob_size);
+int vnvram_write_entry(VNVRAM *vnvram, const VNVRAMEntryName *entry_name,
+ char *blob, uint32_t blob_size);
+int vnvram_delete(VNVRAM *vnvram);
+
#endif
Provides VNVRAM APIs that can be used by other areas of QEMU to provide persistent storage. Signed-off-by: Corey Bryant <coreyb@linux.vnet.ibm.com> --- vnvram.c | 266 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vnvram.h | 14 +++ 2 files changed, 280 insertions(+), 0 deletions(-)