diff mbox

[1/7] vnvram: VNVRAM bdrv support

Message ID 1369331087-22345-2-git-send-email-coreyb@linux.vnet.ibm.com
State New
Headers show

Commit Message

Corey Bryant May 23, 2013, 5:44 p.m. UTC
Provides low-level VNVRAM functionality that reads and writes data,
such as an entry's binary blob, to a drive image using the block
driver.

Signed-off-by: Corey Bryant <coreyb@linux.vnet.ibm.com>
---
 Makefile.objs |    2 +
 vnvram.c      |  487 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 vnvram.h      |   22 +++
 3 files changed, 511 insertions(+), 0 deletions(-)
 create mode 100644 vnvram.c
 create mode 100644 vnvram.h

Comments

Kevin Wolf May 24, 2013, 1:06 p.m. UTC | #1
Am 23.05.2013 um 19:44 hat Corey Bryant geschrieben:
> Provides low-level VNVRAM functionality that reads and writes data,
> such as an entry's binary blob, to a drive image using the block
> driver.
> 
> Signed-off-by: Corey Bryant <coreyb@linux.vnet.ibm.com>

> +/*
> + * Increase the drive size if it's too small to fit the VNVRAM data
> + */
> +static int vnvram_drv_adjust_size(VNVRAM *vnvram)
> +{
> +    int rc = 0;
> +    int64_t needed_size;
> +
> +    needed_size = 0;
> +
> +    if (bdrv_getlength(vnvram->bds) < needed_size) {
> +        rc = bdrv_truncate(vnvram->bds, needed_size);
> +        if (rc != 0) {
> +            DPRINTF("%s: VNVRAM drive too small\n", __func__);
> +        }
> +    }
> +
> +    return rc;
> +}

This function doesn't make a whole lot of sense. It truncates the file
to size 0 if and only if bdrv_getlength() returns an error.

> +
> +/*
> + * Write a header to the drive with entry count of zero
> + */
> +static int vnvram_drv_hdr_create_empty(VNVRAM *vnvram)
> +{
> +    VNVRAMDrvHdr hdr;
> +
> +    hdr.version = VNVRAM_CURRENT_VERSION;
> +    hdr.magic = VNVRAM_MAGIC;
> +    hdr.num_entries = 0;
> +
> +    vnvram_drv_hdr_cpu_to_be((&hdr));
> +
> +    if (bdrv_pwrite(vnvram->bds, 0, (&hdr), sizeof(hdr)) != sizeof(hdr)) {
> +        DPRINTF("%s: Write of header to drive failed\n", __func__);
> +        return -EIO;
> +    }
> +
> +    vnvram->end_offset = sizeof(VNVRAMDrvHdr);
> +
> +    return 0;
> +}
> +
> +/*
> + * Read the header from the drive
> + */
> +static int vnvram_drv_hdr_read(VNVRAM *vnvram, VNVRAMDrvHdr *hdr)
> +{
> +    if (bdrv_pread(vnvram->bds, 0, hdr, sizeof(*hdr)) != sizeof(*hdr)) {
> +        DPRINTF("%s: Read of header from drive failed\n", __func__);
> +        return -EIO;
> +    }

Why do you turn all errors into -EIO instead of returning the real error
code? (More instances of the same thing follow)

> +
> +    vnvram_drv_hdr_be_to_cpu(hdr);
> +
> +    return 0;
> +}
> +}

Kevin
Corey Bryant May 24, 2013, 3:33 p.m. UTC | #2
On 05/24/2013 09:06 AM, Kevin Wolf wrote:
> Am 23.05.2013 um 19:44 hat Corey Bryant geschrieben:
>> Provides low-level VNVRAM functionality that reads and writes data,
>> such as an entry's binary blob, to a drive image using the block
>> driver.
>>
>> Signed-off-by: Corey Bryant <coreyb@linux.vnet.ibm.com>
>
>> +/*
>> + * Increase the drive size if it's too small to fit the VNVRAM data
>> + */
>> +static int vnvram_drv_adjust_size(VNVRAM *vnvram)
>> +{
>> +    int rc = 0;
>> +    int64_t needed_size;
>> +
>> +    needed_size = 0;
>> +
>> +    if (bdrv_getlength(vnvram->bds) < needed_size) {
>> +        rc = bdrv_truncate(vnvram->bds, needed_size);
>> +        if (rc != 0) {
>> +            DPRINTF("%s: VNVRAM drive too small\n", __func__);
>> +        }
>> +    }
>> +
>> +    return rc;
>> +}
>
> This function doesn't make a whole lot of sense. It truncates the file
> to size 0 if and only if bdrv_getlength() returns an error.
>

There's a later patch that adds a "get size" function and changes the 
initialization of needed_size to the actual size needed to store VNVRAM 
data.  Anyway I should probably just include that change in this patch. 
  I think I'll still need this function or part of it with the new 
simplified approach that it looks like we're going to take.

>> +
>> +/*
>> + * Write a header to the drive with entry count of zero
>> + */
>> +static int vnvram_drv_hdr_create_empty(VNVRAM *vnvram)
>> +{
>> +    VNVRAMDrvHdr hdr;
>> +
>> +    hdr.version = VNVRAM_CURRENT_VERSION;
>> +    hdr.magic = VNVRAM_MAGIC;
>> +    hdr.num_entries = 0;
>> +
>> +    vnvram_drv_hdr_cpu_to_be((&hdr));
>> +
>> +    if (bdrv_pwrite(vnvram->bds, 0, (&hdr), sizeof(hdr)) != sizeof(hdr)) {
>> +        DPRINTF("%s: Write of header to drive failed\n", __func__);
>> +        return -EIO;
>> +    }
>> +
>> +    vnvram->end_offset = sizeof(VNVRAMDrvHdr);
>> +
>> +    return 0;
>> +}
>> +
>> +/*
>> + * Read the header from the drive
>> + */
>> +static int vnvram_drv_hdr_read(VNVRAM *vnvram, VNVRAMDrvHdr *hdr)
>> +{
>> +    if (bdrv_pread(vnvram->bds, 0, hdr, sizeof(*hdr)) != sizeof(*hdr)) {
>> +        DPRINTF("%s: Read of header from drive failed\n", __func__);
>> +        return -EIO;
>> +    }
>
> Why do you turn all errors into -EIO instead of returning the real error
> code? (More instances of the same thing follow)
>

Good point, there's no reason to mask the original error code.

>> +
>> +    vnvram_drv_hdr_be_to_cpu(hdr);
>> +
>> +    return 0;
>> +}
>> +}
>
> Kevin
>
>
>
Kevin Wolf May 24, 2013, 3:37 p.m. UTC | #3
Am 24.05.2013 um 17:33 hat Corey Bryant geschrieben:
> 
> 
> On 05/24/2013 09:06 AM, Kevin Wolf wrote:
> >Am 23.05.2013 um 19:44 hat Corey Bryant geschrieben:
> >>Provides low-level VNVRAM functionality that reads and writes data,
> >>such as an entry's binary blob, to a drive image using the block
> >>driver.
> >>
> >>Signed-off-by: Corey Bryant <coreyb@linux.vnet.ibm.com>
> >
> >>+/*
> >>+ * Increase the drive size if it's too small to fit the VNVRAM data
> >>+ */
> >>+static int vnvram_drv_adjust_size(VNVRAM *vnvram)
> >>+{
> >>+    int rc = 0;
> >>+    int64_t needed_size;
> >>+
> >>+    needed_size = 0;
> >>+
> >>+    if (bdrv_getlength(vnvram->bds) < needed_size) {
> >>+        rc = bdrv_truncate(vnvram->bds, needed_size);
> >>+        if (rc != 0) {
> >>+            DPRINTF("%s: VNVRAM drive too small\n", __func__);
> >>+        }
> >>+    }
> >>+
> >>+    return rc;
> >>+}
> >
> >This function doesn't make a whole lot of sense. It truncates the file
> >to size 0 if and only if bdrv_getlength() returns an error.
> >
> 
> There's a later patch that adds a "get size" function and changes
> the initialization of needed_size to the actual size needed to store
> VNVRAM data.  Anyway I should probably just include that change in
> this patch.  I think I'll still need this function or part of it
> with the new simplified approach that it looks like we're going to
> take.

Okay. But even then, do you really want to truncate on errors?

Kevin
Corey Bryant May 24, 2013, 3:47 p.m. UTC | #4
On 05/24/2013 11:37 AM, Kevin Wolf wrote:
> Am 24.05.2013 um 17:33 hat Corey Bryant geschrieben:
>>
>>
>> On 05/24/2013 09:06 AM, Kevin Wolf wrote:
>>> Am 23.05.2013 um 19:44 hat Corey Bryant geschrieben:
>>>> Provides low-level VNVRAM functionality that reads and writes data,
>>>> such as an entry's binary blob, to a drive image using the block
>>>> driver.
>>>>
>>>> Signed-off-by: Corey Bryant <coreyb@linux.vnet.ibm.com>
>>>
>>>> +/*
>>>> + * Increase the drive size if it's too small to fit the VNVRAM data
>>>> + */
>>>> +static int vnvram_drv_adjust_size(VNVRAM *vnvram)
>>>> +{
>>>> +    int rc = 0;
>>>> +    int64_t needed_size;
>>>> +
>>>> +    needed_size = 0;
>>>> +
>>>> +    if (bdrv_getlength(vnvram->bds) < needed_size) {
>>>> +        rc = bdrv_truncate(vnvram->bds, needed_size);
>>>> +        if (rc != 0) {
>>>> +            DPRINTF("%s: VNVRAM drive too small\n", __func__);
>>>> +        }
>>>> +    }
>>>> +
>>>> +    return rc;
>>>> +}
>>>
>>> This function doesn't make a whole lot of sense. It truncates the file
>>> to size 0 if and only if bdrv_getlength() returns an error.
>>>
>>
>> There's a later patch that adds a "get size" function and changes
>> the initialization of needed_size to the actual size needed to store
>> VNVRAM data.  Anyway I should probably just include that change in
>> this patch.  I think I'll still need this function or part of it
>> with the new simplified approach that it looks like we're going to
>> take.
>
> Okay. But even then, do you really want to truncate on errors?
>
> Kevin
>
>
>

True, it'll need something to account for bdrv_getlength() failures and 
not truncate in that case.
diff mbox

Patch

diff --git a/Makefile.objs b/Makefile.objs
index 286ce06..4875a94 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -76,6 +76,8 @@  common-obj-$(CONFIG_SECCOMP) += qemu-seccomp.o
 
 common-obj-$(CONFIG_SMARTCARD_NSS) += $(libcacard-y)
 
+common-obj-y += vnvram.o
+
 ######################################################################
 # qapi
 
diff --git a/vnvram.c b/vnvram.c
new file mode 100644
index 0000000..e467198
--- /dev/null
+++ b/vnvram.c
@@ -0,0 +1,487 @@ 
+/*
+ * VNVRAM -- stores persistent data in image files
+ *
+ * Copyright (C) 2013 IBM Corporation
+ *
+ * Authors:
+ *  Stefan Berger    <stefanb@us.ibm.com>
+ *  Corey Bryant     <coreyb@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "vnvram.h"
+#include "block/block.h"
+
+/*
+#define VNVRAM_DEBUG
+*/
+
+#ifdef VNVRAM_DEBUG
+#define DPRINTF(fmt, ...) \
+    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+    do { } while (0)
+#endif
+
+#define VNVRAM_ENTRY_DATA                              \
+    VNVRAMEntryName name; /* name of entry */          \
+    uint64_t blob_offset; /* start of blob on drive */ \
+    uint32_t cur_size;    /* current size of blob */   \
+    uint32_t max_size;    /* max size of blob */
+
+/* The following VNVRAM information is stored in-memory */
+typedef struct VNVRAMEntry {
+    VNVRAM_ENTRY_DATA
+    QLIST_ENTRY(VNVRAMEntry) next;
+} VNVRAMEntry;
+
+struct VNVRAM {
+    char *drv_id;            /* corresponds to -drive id= on command line */
+    BlockDriverState *bds;   /* bds for the VNVRAM drive */
+    uint64_t end_offset;     /* offset on drive where next entry will go */
+    QLIST_HEAD(entries_head, VNVRAMEntry) entries_head; /* in-memory entries */
+    QLIST_ENTRY(VNVRAM) list;
+};
+
+/* There can be multiple VNVRAMS */
+static QLIST_HEAD(, VNVRAM) vnvrams = QLIST_HEAD_INITIALIZER(vnvrams);
+
+#define VNVRAM_VERSION_1        1
+#define VNVRAM_CURRENT_VERSION  VNVRAM_VERSION_1
+#define VNVRAM_MAGIC            0x4E56524D /* NVRM */
+
+/* VNVRAM drive data consists of a header followed by entries and their blobs.
+ * For example:
+ *   | header | entry 1 | entry 1's blob | entry 2 | entry 2's blob | ... |
+ */
+typedef struct VNVRAMDrvHdr {
+    uint16_t version;
+    uint32_t magic;
+    uint32_t num_entries;
+} QEMU_PACKED VNVRAMDrvHdr;
+
+typedef struct VNVRAMDrvEntry {
+    VNVRAM_ENTRY_DATA
+} QEMU_PACKED VNVRAMDrvEntry;
+
+static int vnvram_drv_entry_create(VNVRAM *, VNVRAMEntry *, uint64_t, uint32_t);
+static int vnvram_drv_entry_update(VNVRAM *, VNVRAMEntry *, uint64_t, uint32_t);
+
+/*
+ * Macros for finding entries and their drive offsets
+ */
+#define VNVRAM_FIRST_ENTRY(vnvram) \
+        QLIST_FIRST(&(vnvram)->entries_head)
+
+#define VNVRAM_NEXT_ENTRY(cur_entry) \
+    QLIST_NEXT(cur_entry, next)
+
+#define VNVRAM_FIRST_ENTRY_OFFSET() \
+    sizeof(VNVRAMDrvHdr)
+
+#define VNVRAM_NEXT_ENTRY_OFFSET(entry) \
+    ((entry)->blob_offset + (entry)->max_size)
+
+#define VNVRAM_NEXT_AVAIL_BLOB_OFFSET(vnvram) \
+    ((vnvram)->end_offset + sizeof(VNVRAMDrvEntry))
+
+#define VNVRAM_ENTRY_OFFSET_FROM_BLOB(blob_offset) \
+    (blob_offset - sizeof(VNVRAMDrvEntry))
+
+#define VNVRAM_BLOB_OFFSET_FROM_ENTRY(entry_offset) \
+    (entry_offset + sizeof(VNVRAMDrvEntry))
+
+/************************* VNVRAM drv ********************************/
+/* Low-level VNVRAM functions that work with the drive header and    */
+/* entries.                                                          */
+/*********************************************************************/
+
+/*
+ * Big-endian conversions
+ */
+static void vnvram_drv_hdr_cpu_to_be(VNVRAMDrvHdr *hdr)
+{
+    hdr->version = cpu_to_be16(hdr->version);
+    hdr->magic = cpu_to_be32(hdr->magic);
+    hdr->num_entries = cpu_to_be32(hdr->num_entries);
+}
+
+static void vnvram_drv_hdr_be_to_cpu(VNVRAMDrvHdr *hdr)
+{
+    hdr->version = be16_to_cpu(hdr->version);
+    hdr->magic = be32_to_cpu(hdr->magic);
+    hdr->num_entries = be32_to_cpu(hdr->num_entries);
+}
+
+static void vnvram_drv_entry_cpu_to_be(VNVRAMDrvEntry *drv_entry)
+{
+    drv_entry->blob_offset = cpu_to_be64(drv_entry->blob_offset);
+    drv_entry->cur_size = cpu_to_be32(drv_entry->cur_size);
+    drv_entry->max_size = cpu_to_be32(drv_entry->max_size);
+}
+
+static void vnvram_drv_entry_be_to_cpu(VNVRAMDrvEntry *drv_entry)
+{
+    drv_entry->blob_offset = be64_to_cpu(drv_entry->blob_offset);
+    drv_entry->cur_size = be32_to_cpu(drv_entry->cur_size);
+    drv_entry->max_size = be32_to_cpu(drv_entry->max_size);
+}
+
+/*
+ * Find the VNVRAM that corresponds to the specified drive ID string
+ */
+static VNVRAM *vnvram_drv_find_by_id(const char *drv_id)
+{
+    VNVRAM *vnvram;
+
+    QLIST_FOREACH(vnvram, &vnvrams, list) {
+        if (strcmp(vnvram->drv_id, drv_id) == 0) {
+            return vnvram;
+        }
+    }
+
+    return NULL;
+}
+
+/*
+ * Increase the drive size if it's too small to fit the VNVRAM data
+ */
+static int vnvram_drv_adjust_size(VNVRAM *vnvram)
+{
+    int rc = 0;
+    int64_t needed_size;
+
+    needed_size = 0;
+
+    if (bdrv_getlength(vnvram->bds) < needed_size) {
+        rc = bdrv_truncate(vnvram->bds, needed_size);
+        if (rc != 0) {
+            DPRINTF("%s: VNVRAM drive too small\n", __func__);
+        }
+    }
+
+    return rc;
+}
+
+/*
+ * Write a header to the drive with entry count of zero
+ */
+static int vnvram_drv_hdr_create_empty(VNVRAM *vnvram)
+{
+    VNVRAMDrvHdr hdr;
+
+    hdr.version = VNVRAM_CURRENT_VERSION;
+    hdr.magic = VNVRAM_MAGIC;
+    hdr.num_entries = 0;
+
+    vnvram_drv_hdr_cpu_to_be((&hdr));
+
+    if (bdrv_pwrite(vnvram->bds, 0, (&hdr), sizeof(hdr)) != sizeof(hdr)) {
+        DPRINTF("%s: Write of header to drive failed\n", __func__);
+        return -EIO;
+    }
+
+    vnvram->end_offset = sizeof(VNVRAMDrvHdr);
+
+    return 0;
+}
+
+/*
+ * Read the header from the drive
+ */
+static int vnvram_drv_hdr_read(VNVRAM *vnvram, VNVRAMDrvHdr *hdr)
+{
+    if (bdrv_pread(vnvram->bds, 0, hdr, sizeof(*hdr)) != sizeof(*hdr)) {
+        DPRINTF("%s: Read of header from drive failed\n", __func__);
+        return -EIO;
+    }
+
+    vnvram_drv_hdr_be_to_cpu(hdr);
+
+    return 0;
+}
+
+/*
+ * Write the header to the drive
+ */
+static int vnvram_drv_hdr_write(VNVRAM *vnvram, VNVRAMDrvHdr *hdr)
+{
+    vnvram_drv_hdr_cpu_to_be(hdr);
+
+    if (bdrv_pwrite(vnvram->bds, 0, hdr, sizeof(*hdr)) != sizeof(*hdr)) {
+        DPRINTF("%s: Write of header to drive failed\n", __func__);
+        return -EIO;
+    }
+
+    vnvram_drv_hdr_be_to_cpu(hdr);
+
+    return 0;
+}
+
+/*
+ * Read an entry from the drive (does not include blob)
+ */
+static int vnvram_drv_entry_read(VNVRAM *vnvram, uint64_t entry_offset,
+                                 VNVRAMDrvEntry *drv_entry)
+{
+    if (bdrv_pread(vnvram->bds, entry_offset, drv_entry, sizeof(*drv_entry))
+            != sizeof(*drv_entry)) {
+        DPRINTF("%s: VNVRAM error reading entry from drive\n", __func__);
+        return -EIO;
+    }
+
+    vnvram_drv_entry_be_to_cpu(drv_entry);
+
+    return 0;
+}
+
+/*
+ * Write an entry to the drive (does not include blob)
+ */
+static int vnvram_drv_entry_write(VNVRAM *vnvram, uint64_t entry_offset,
+                                  VNVRAMDrvEntry *drv_entry)
+{
+    vnvram_drv_entry_cpu_to_be(drv_entry);
+
+    if (bdrv_pwrite(vnvram->bds, entry_offset, drv_entry, sizeof(*drv_entry))
+            != sizeof(*drv_entry)) {
+        DPRINTF("%s: VNVRAM error writing entry to drive\n", __func__);
+        return -EIO;
+    }
+
+    vnvram_drv_entry_be_to_cpu(drv_entry);
+
+    return 0;
+}
+
+/*
+ * Read an entry's blob from the drive
+ */
+static int vnvram_drv_entry_read_blob(VNVRAM *vnvram, const VNVRAMEntry *entry,
+                                      char **blob, uint32_t *blob_size)
+{
+    int rc = 0;
+
+    *blob = NULL;
+    *blob_size = 0;
+
+    if (entry->cur_size == 0) {
+        DPRINTF("%s: VNVRAM entry not found\n", __func__);
+        rc = -ENOENT;
+        goto err_exit;
+    }
+
+    *blob = g_malloc(entry->cur_size);
+
+    DPRINTF("%s: VNVRAM read: name=%s, blob_offset=%"PRIu64", size=%"PRIu32"\n",
+            __func__, (char *)entry->name, entry->blob_offset, entry->cur_size);
+
+    if (bdrv_pread(vnvram->bds, entry->blob_offset, *blob, entry->cur_size)
+            != entry->cur_size) {
+        DPRINTF("%s: VNVRAM error reading blob from drive\n", __func__);
+        rc = -EIO;
+        goto err_exit;
+    }
+
+    *blob_size = entry->cur_size;
+
+    return rc;
+
+err_exit:
+    g_free(*blob);
+    *blob = NULL;
+
+    return rc;
+}
+
+/*
+ * Write an entry's blob to the drive
+ */
+static int vnvram_drv_entry_write_blob(VNVRAM *vnvram, VNVRAMEntry *entry,
+                                       char *blob, uint32_t blob_size)
+{
+    int rc;
+    uint64_t blob_offset;
+
+    if (blob_size == 0 || blob_size > entry->max_size) {
+        DPRINTF("%s: Blob size is not valid for entry\n", __func__);
+        rc = -EMSGSIZE;
+        goto err_exit;
+    }
+
+    rc = vnvram_drv_adjust_size(vnvram);
+    if (rc != 0) {
+        goto err_exit;
+    }
+
+    if (entry->blob_offset == 0) {
+        /* Entry doesn't exist on the drive yet */
+        blob_offset = VNVRAM_NEXT_AVAIL_BLOB_OFFSET(vnvram);
+    } else {
+        blob_offset = entry->blob_offset;
+    }
+
+    DPRINTF("%s: VNVRAM write: name=%s, blob_offset=%"PRIu64", "
+            "size=%"PRIu32"\n", __func__, (char *)entry->name,
+            blob_offset, blob_size);
+
+    if (bdrv_pwrite(vnvram->bds, blob_offset, blob, blob_size) != blob_size) {
+        DPRINTF("%s: VNVRAM error writing blob to drive\n", __func__);
+        rc = -EIO;
+        goto err_exit;
+    }
+
+    if (entry->blob_offset == 0) {
+        /* Entry doesn't exist on the drive yet */
+        rc = vnvram_drv_entry_create(vnvram, entry,
+                                     VNVRAM_ENTRY_OFFSET_FROM_BLOB(blob_offset),
+                                     blob_size);
+        if (rc != 0) {
+            DPRINTF("%s: Unable to create VNVRAM entry\n", __func__);
+            goto err_exit;
+        }
+    } else {
+        rc = vnvram_drv_entry_update(vnvram, entry,
+                                     VNVRAM_ENTRY_OFFSET_FROM_BLOB(blob_offset),
+                                     blob_size);
+        if (rc != 0) {
+            DPRINTF("%s: Unable to update VNVRAM entry\n", __func__);
+            goto err_exit;
+        }
+    }
+
+    entry->blob_offset = blob_offset;
+    entry->cur_size = blob_size;
+
+err_exit:
+    return rc;
+}
+
+/*
+ * Create an entry and write it to the drive (does not include blob)
+ */
+static int vnvram_drv_entry_create(VNVRAM *vnvram, VNVRAMEntry *entry,
+                                   uint64_t entry_offset, uint32_t blob_size)
+{
+    int rc;
+    VNVRAMDrvHdr hdr;
+    VNVRAMDrvEntry *drv_entry;
+
+    drv_entry = g_new0(VNVRAMDrvEntry, 1);
+
+    pstrcpy(drv_entry->name, sizeof(drv_entry->name), (char *)entry->name);
+    drv_entry->blob_offset = VNVRAM_BLOB_OFFSET_FROM_ENTRY(entry_offset);
+    drv_entry->cur_size = blob_size;
+    drv_entry->max_size = entry->max_size;
+
+    rc = vnvram_drv_entry_write(vnvram, entry_offset, drv_entry);
+    if (rc != 0) {
+        goto err_exit;
+    }
+
+    rc = vnvram_drv_hdr_read(vnvram, (&hdr));
+    if (rc != 0) {
+        goto err_exit;
+    }
+
+    hdr.num_entries++;
+
+    rc = vnvram_drv_hdr_write(vnvram, (&hdr));
+    if (rc != 0) {
+        goto err_exit;
+    }
+
+    vnvram->end_offset = drv_entry->blob_offset + drv_entry->max_size;
+
+err_exit:
+    g_free(drv_entry);
+
+    return rc;
+}
+
+/*
+ * Update an entry on the drive (does not include blob)
+ */
+static int vnvram_drv_entry_update(VNVRAM *vnvram, VNVRAMEntry *entry,
+                                   uint64_t entry_offset, uint32_t blob_size)
+{
+    int rc;
+    VNVRAMDrvEntry *drv_entry;
+
+    drv_entry = g_new0(VNVRAMDrvEntry, 1);
+
+    pstrcpy(drv_entry->name, sizeof(drv_entry->name), (char *)entry->name);
+    drv_entry->blob_offset = VNVRAM_BLOB_OFFSET_FROM_ENTRY(entry_offset);
+    drv_entry->cur_size = blob_size;
+    drv_entry->max_size = entry->max_size;
+
+    rc = vnvram_drv_entry_write(vnvram, entry_offset, drv_entry);
+
+    g_free(drv_entry);
+
+    return rc;
+}
+
+/*
+ * Get all entry data from the drive (does not get blob data)
+ */
+static int vnvram_drv_entries_get(VNVRAM *vnvram, VNVRAMDrvHdr *hdr,
+                                  VNVRAMDrvEntry **drv_entries,
+                                  int *num_entries)
+{
+    int i, rc;
+    uint64_t entry_offset;
+
+    *drv_entries = NULL;
+    *num_entries = 0;
+
+    *num_entries = hdr->num_entries;
+    if (*num_entries == 0) {
+        return 0;
+    }
+
+    *drv_entries = g_malloc_n(hdr->num_entries, sizeof(VNVRAMDrvEntry));
+
+    entry_offset = VNVRAM_FIRST_ENTRY_OFFSET();
+
+    for (i = 0; i < hdr->num_entries; i++) {
+        VNVRAMDrvEntry *drv_entry = &(*drv_entries)[i];
+
+        rc = vnvram_drv_entry_read(vnvram, entry_offset, drv_entry);
+        if (rc != 0) {
+            goto err_exit;
+        }
+
+        entry_offset = VNVRAM_NEXT_ENTRY_OFFSET(drv_entry);
+    }
+
+    return 0;
+
+err_exit:
+    g_free(*drv_entries);
+    *drv_entries = NULL;
+    *num_entries = 0;
+
+    return rc;
+}
+
+/*
+ * Check if the VNVRAM drive header is valid
+ */
+static bool vnvram_drv_hdr_is_valid(VNVRAM *vnvram, VNVRAMDrvHdr *hdr)
+{
+    if (hdr->version != VNVRAM_CURRENT_VERSION) {
+        DPRINTF("%s: VNVRAM drive version not valid\n", __func__);
+        return false;
+    }
+
+    if (hdr->magic != VNVRAM_MAGIC) {
+        DPRINTF("%s: VNVRAM drive magic not valid\n", __func__);
+        return false;
+    }
+
+    return true;
+}
diff --git a/vnvram.h b/vnvram.h
new file mode 100644
index 0000000..b6d7cd7
--- /dev/null
+++ b/vnvram.h
@@ -0,0 +1,22 @@ 
+/*
+ * VNVRAM -- stores persistent data in image files
+ *
+ * Copyright (C) 2013 IBM Corporation
+ *
+ * Authors:
+ *  Stefan Berger    <stefanb@us.ibm.com>
+ *  Corey Bryant     <coreyb@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef _QEMU_VNVRAM_H_
+#define _QEMU_VNVRAM_H_
+
+typedef struct VNVRAM VNVRAM;
+
+#define VNVRAM_ENTRY_NAME_LENGTH 16
+typedef char VNVRAMEntryName[VNVRAM_ENTRY_NAME_LENGTH];
+
+#endif