All of lore.kernel.org
 help / color / mirror / Atom feed
From: Kevin Wolf <kwolf@redhat.com>
To: Jeff Cody <jcody@redhat.com>
Cc: famz@redhat.com, qemu-devel@nongnu.org, stefanha@redhat.com
Subject: Re: [Qemu-devel] [PATCH v2 2/9] block: vhdx - add header update capability.
Date: Mon, 5 Aug 2013 16:45:02 +0200	[thread overview]
Message-ID: <20130805144502.GJ2654@dhcp-200-207.str.redhat.com> (raw)
In-Reply-To: <595d71cf1cd25ac9deff521bceb82b8c3da888d0.1375325971.git.jcody@redhat.com>

Am 01.08.2013 um 05:23 hat Jeff Cody geschrieben:
> This adds the ability to update the headers in a VHDX image, including
> generating a new MS-compatible GUID.
> 
> As VHDX depends on uuid.h, VHDX is now a configurable build option.  If
> VHDX support is enabled, that will also enable uuid as well.  The
> default is to have VHDX enabled.
> 
> To enable/disable VHDX:  --enable-vhdx, --disable-vhdx
> 
> Signed-off-by: Jeff Cody <jcody@redhat.com>
> ---
>  block/Makefile.objs |   2 +-
>  block/vhdx.c        | 157 +++++++++++++++++++++++++++++++++++++++++++++++++++-
>  block/vhdx.h        |  12 +++-
>  configure           |  13 +++++
>  4 files changed, 180 insertions(+), 4 deletions(-)
> 
> diff --git a/block/Makefile.objs b/block/Makefile.objs
> index 4cf9aa4..e5e54e6 100644
> --- a/block/Makefile.objs
> +++ b/block/Makefile.objs
> @@ -2,7 +2,7 @@ block-obj-y += raw.o cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat
>  block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o
>  block-obj-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o
>  block-obj-y += qed-check.o
> -block-obj-y += vhdx.o
> +block-obj-$(CONFIG_VHDX) += vhdx.o
>  block-obj-y += parallels.o blkdebug.o blkverify.o
>  block-obj-y += snapshot.o qapi.o
>  block-obj-$(CONFIG_WIN32) += raw-win32.o win32-aio.o
> diff --git a/block/vhdx.c b/block/vhdx.c
> index 56bc88e..9b50442 100644
> --- a/block/vhdx.c
> +++ b/block/vhdx.c
> @@ -21,6 +21,7 @@
>  #include "qemu/crc32c.h"
>  #include "block/vhdx.h"
>  
> +#include <uuid/uuid.h>
>  
>  /* Several metadata and region table data entries are identified by
>   * guids in  a MS-specific GUID format. */
> @@ -156,11 +157,40 @@ typedef struct BDRVVHDXState {
>      VHDXBatEntry *bat;
>      uint64_t bat_offset;
>  
> +    MSGUID session_guid;
> +
> +
>      VHDXParentLocatorHeader parent_header;
>      VHDXParentLocatorEntry *parent_entries;
>  
>  } BDRVVHDXState;
>  
> +/* Calculates new checksum.
> + *
> + * Zero is substituted during crc calculation for the original crc field
> + * crc_offset: byte offset in buf of the buffer crc
> + * buf: buffer pointer
> + * size: size of buffer (must be > crc_offset+4)
> + *
> + * Note: The resulting checksum is in the CPU endianness, not necessarily
> + *       in the file format endianness (LE).  Any header export to disk should
> + *       make sure that vhdx_header_le_export() is used to convert to the
> + *       correct endianness
> + */
> +uint32_t vhdx_update_checksum(uint8_t *buf, size_t size, int crc_offset)
> +{
> +    uint32_t crc;
> +
> +    assert(buf != NULL);
> +    assert(size > (crc_offset + 4));

sizeof(crc) for consistency.

> +
> +    memset(buf + crc_offset, 0, sizeof(crc));
> +    crc =  crc32c(0xffffffff, buf, size);
> +    memcpy(buf + crc_offset, &crc, sizeof(crc));
> +
> +    return crc;
> +}
> +
>  uint32_t vhdx_checksum_calc(uint32_t crc, uint8_t *buf, size_t size,
>                              int crc_offset)
>  {
> @@ -212,6 +242,24 @@ bool vhdx_checksum_is_valid(uint8_t *buf, size_t size, int crc_offset)
>  
>  
>  /*
> + * This generates a UUID that is compliant with the MS GUIDs used
> + * in the VHDX spec (and elsewhere).
> + *
> + * We can do this with uuid_generate if uuid.h is present,
> + * however not all systems have uuid and the generation is
> + * pretty straightforward for the DCE + random usage case
> + *
> + */
> +void vhdx_guid_generate(MSGUID *guid)
> +{
> +    uuid_t uuid;
> +    assert(guid != NULL);
> +
> +    uuid_generate(uuid);
> +    memcpy(guid, uuid, 16);
> +}

Should MSGUID be QEMU_PACKED to make sure that this works? Also
sizeof(guid) instead of 16?

> +
> +/*
>   * Per the MS VHDX Specification, for every VHDX file:
>   *      - The header section is fixed size - 1 MB
>   *      - The header section is always the first "object"
> @@ -249,6 +297,107 @@ static void vhdx_header_le_import(VHDXHeader *h)
>      le64_to_cpus(&h->log_offset);
>  }
>  
> +/* All VHDX structures on disk are little endian */
> +static void vhdx_header_le_export(VHDXHeader *orig_h, VHDXHeader *new_h)
> +{
> +    assert(orig_h != NULL);
> +    assert(new_h != NULL);
> +
> +    new_h->signature       = cpu_to_le32(orig_h->signature);
> +    new_h->checksum        = cpu_to_le32(orig_h->checksum);
> +    new_h->sequence_number = cpu_to_le64(orig_h->sequence_number);
> +
> +    memcpy(&new_h->file_write_guid, &orig_h->file_write_guid, sizeof(MSGUID));
> +    memcpy(&new_h->data_write_guid, &orig_h->data_write_guid, sizeof(MSGUID));
> +    memcpy(&new_h->log_guid,        &orig_h->log_guid,        sizeof(MSGUID));

Can we avoid memcpy? I think this should work:

new_h->file_write_guid = orig_h->file_write_guid;
new_h->data_write_guid = orig_h->data_write_guid;
new_h->log_guid        = orig_h->log_guid;

> +
> +    cpu_to_leguids(&new_h->file_write_guid);
> +    cpu_to_leguids(&new_h->data_write_guid);
> +    cpu_to_leguids(&new_h->log_guid);
> +
> +    new_h->log_version     = cpu_to_le16(orig_h->log_version);
> +    new_h->version         = cpu_to_le16(orig_h->version);
> +    new_h->log_length      = cpu_to_le32(orig_h->log_length);
> +    new_h->log_offset      = cpu_to_le64(orig_h->log_offset);
> +}
> +
> +/* Update the VHDX headers
> + *
> + * This follows the VHDX spec procedures for header updates.
> + *
> + *  - non-current header is updated with largest sequence number
> + */
> +static int vhdx_update_header(BlockDriverState *bs, BDRVVHDXState *s, bool rw)
> +{
> +    int ret = 0;
> +    int hdr_idx = 0;
> +    uint64_t header_offset = VHDX_HEADER1_OFFSET;
> +
> +    VHDXHeader *active_header;
> +    VHDXHeader *inactive_header;
> +    VHDXHeader header_le;
> +    uint8_t *buffer;
> +
> +    /* operate on the non-current header */
> +    if (s->curr_header == 0) {
> +        hdr_idx = 1;
> +        header_offset = VHDX_HEADER2_OFFSET;
> +    }
> +
> +    active_header   = s->headers[s->curr_header];
> +    inactive_header = s->headers[hdr_idx];
> +
> +    inactive_header->sequence_number = active_header->sequence_number + 1;
> +
> +    /* a new file guid must be generate before any file write, including
> +     * headers */
> +    memcpy(&inactive_header->file_write_guid, &s->session_guid,
> +           sizeof(MSGUID));

Here a simple assignment should do as well.

> +
> +    /* a new data guid only needs to be generate before any guest-visible
> +     * writes, so update it if the image is opened r/w. */
> +    if (rw) {
> +        vhdx_guid_generate(&inactive_header->data_write_guid);
> +    }
> +
> +    /* the header checksum is not over just the packed size of VHDXHeader,
> +     * but rather over the entire 'reserved' range for the header, which is
> +     * 4KB (VHDX_HEADER_SIZE). */
> +
> +    buffer = qemu_blockalign(bs, VHDX_HEADER_SIZE);
> +    /* we can't assume the extra reserved bytes are 0 */
> +    ret = bdrv_pread(bs->file, header_offset, buffer, VHDX_HEADER_SIZE);
> +    if (ret < 0) {
> +        goto exit;
> +    }
> +    /* overwrite the actual VHDXHeader portion */
> +    memcpy(buffer, inactive_header, sizeof(VHDXHeader));
> +    inactive_header->checksum = vhdx_update_checksum(buffer,
> +                                                     VHDX_HEADER_SIZE, 4);
> +    vhdx_header_le_export(inactive_header, &header_le);
> +    bdrv_pwrite_sync(bs->file, header_offset, &header_le, sizeof(VHDXHeader));
> +    s->curr_header = hdr_idx;
> +
> +exit:
> +    qemu_vfree(buffer);
> +    return ret;
> +}

Kevin

  parent reply	other threads:[~2013-08-05 14:45 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-08-01  3:23 [Qemu-devel] [PATCH v2 0/9] VHDX log replay and write support Jeff Cody
2013-08-01  3:23 ` [Qemu-devel] [PATCH v2 1/9] block: vhdx - minor comments and typo correction Jeff Cody
2013-08-01  3:23 ` [Qemu-devel] [PATCH v2 2/9] block: vhdx - add header update capability Jeff Cody
2013-08-01 13:44   ` Stefan Hajnoczi
2013-08-01 14:09     ` Jeff Cody
2013-08-07 14:42     ` Jeff Cody
2013-08-05 11:42   ` Kevin Wolf
2013-08-05 14:43     ` Jeff Cody
2013-08-05 14:45   ` Kevin Wolf [this message]
2013-08-05 14:57     ` Jeff Cody
2013-08-05 15:05   ` Kevin Wolf
2013-08-05 15:09     ` Jeff Cody
2013-08-06  8:34       ` Kevin Wolf
2013-08-01  3:23 ` [Qemu-devel] [PATCH v2 3/9] block: vhdx code movement - VHDXMetadataEntries and BDRVVHDXState to header Jeff Cody
2013-08-01  3:23 ` [Qemu-devel] [PATCH v2 4/9] block: vhdx - log support struct and defines Jeff Cody
2013-08-01 15:00   ` Stefan Hajnoczi
2013-08-01 15:51     ` Jeff Cody
2013-08-07 15:22   ` Kevin Wolf
2013-08-07 17:18     ` Jeff Cody
2013-08-01  3:23 ` [Qemu-devel] [PATCH v2 5/9] block: vhdx - break endian translation functions out Jeff Cody
2013-08-01 15:03   ` Stefan Hajnoczi
2013-08-01 15:14     ` Jeff Cody
2013-08-07 15:29   ` Kevin Wolf
2013-08-07 17:21     ` Jeff Cody
2013-08-01  3:23 ` [Qemu-devel] [PATCH v2 6/9] block: vhdx - update log guid in header, and first write tracker Jeff Cody
2013-08-01 15:09   ` Stefan Hajnoczi
2013-08-01  3:23 ` [Qemu-devel] [PATCH v2 7/9] block: vhdx - log parsing, replay, and flush support Jeff Cody
2013-08-01  3:23 ` [Qemu-devel] [PATCH v2 8/9] block: vhdx - add log write support Jeff Cody
2013-08-01  3:23 ` [Qemu-devel] [PATCH v2 9/9] block: vhdx " Jeff Cody

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20130805144502.GJ2654@dhcp-200-207.str.redhat.com \
    --to=kwolf@redhat.com \
    --cc=famz@redhat.com \
    --cc=jcody@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.