From patchwork Thu May 23 17:44:44 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Corey Bryant X-Patchwork-Id: 245993 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 82BD52C009F for ; Fri, 24 May 2013 03:45:44 +1000 (EST) Received: from localhost ([::1]:50041 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UfZaA-0003iX-Mh for incoming@patchwork.ozlabs.org; Thu, 23 May 2013 13:45:42 -0400 Received: from eggs.gnu.org ([208.118.235.92]:39092) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UfZZb-0003d0-Nr for qemu-devel@nongnu.org; Thu, 23 May 2013 13:45:09 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1UfZZV-0006Ri-2a for qemu-devel@nongnu.org; Thu, 23 May 2013 13:45:07 -0400 Received: from e39.co.us.ibm.com ([32.97.110.160]:59407) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UfZZU-0006RO-RE for qemu-devel@nongnu.org; Thu, 23 May 2013 13:45:01 -0400 Received: from /spool/local by e39.co.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Thu, 23 May 2013 11:45:00 -0600 Received: from d03dlp01.boulder.ibm.com (9.17.202.177) by e39.co.us.ibm.com (192.168.1.139) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Thu, 23 May 2013 11:44:59 -0600 Received: from d03relay02.boulder.ibm.com (d03relay02.boulder.ibm.com [9.17.195.227]) by d03dlp01.boulder.ibm.com (Postfix) with ESMTP id 666701FF001F for ; Thu, 23 May 2013 11:39:49 -0600 (MDT) Received: from d03av04.boulder.ibm.com (d03av04.boulder.ibm.com [9.17.195.170]) by d03relay02.boulder.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id r4NHit1J134014 for ; Thu, 23 May 2013 11:44:57 -0600 Received: from d03av04.boulder.ibm.com (loopback [127.0.0.1]) by d03av04.boulder.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id r4NHitO1007177 for ; Thu, 23 May 2013 11:44:55 -0600 Received: from localhost ([9.80.101.134]) by d03av04.boulder.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id r4NHiscc007104; Thu, 23 May 2013 11:44:54 -0600 From: Corey Bryant To: qemu-devel@nongnu.org Date: Thu, 23 May 2013 13:44:44 -0400 Message-Id: <1369331087-22345-5-git-send-email-coreyb@linux.vnet.ibm.com> X-Mailer: git-send-email 1.8.1.4 In-Reply-To: <1369331087-22345-1-git-send-email-coreyb@linux.vnet.ibm.com> References: <1369331087-22345-1-git-send-email-coreyb@linux.vnet.ibm.com> X-TM-AS-MML: No X-Content-Scanned: Fidelis XPS MAILER x-cbid: 13052317-3620-0000-0000-000002A7F1C7 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.4.x-2.6.x [generic] X-Received-From: 32.97.110.160 Cc: kwolf@redhat.com, aliguori@us.ibm.com, stefanb@linux.vnet.ibm.com, Corey Bryant , mdroth@linux.vnet.ibm.com, lcapitulino@redhat.com, jschopp@linux.vnet.ibm.com, stefanha@redhat.com Subject: [Qemu-devel] [PATCH 4/7] vnvram: VNVRAM internal APIs X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Provides VNVRAM APIs that can be used by other areas of QEMU to provide persistent storage. Signed-off-by: Corey Bryant --- vnvram.c | 266 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vnvram.h | 14 +++ 2 files changed, 280 insertions(+), 0 deletions(-) diff --git a/vnvram.c b/vnvram.c index 4157482..357923d 100644 --- a/vnvram.c +++ b/vnvram.c @@ -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; +} diff --git a/vnvram.h b/vnvram.h index b6d7cd7..c1055b4 100644 --- a/vnvram.h +++ b/vnvram.h @@ -14,9 +14,23 @@ #ifndef _QEMU_VNVRAM_H_ #define _QEMU_VNVRAM_H_ +#include +#include + 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