From: Kevin Wolf <kwolf@redhat.com>
To: qemu-devel@nongnu.org
Cc: kwolf@redhat.com, stefanha@gmail.com
Subject: [Qemu-devel] [PATCH 2/2] qcow2: Keep unknown header extension when rewriting header
Date: Tue, 7 Feb 2012 16:05:40 +0100 [thread overview]
Message-ID: <1328627140-9923-3-git-send-email-kwolf@redhat.com> (raw)
In-Reply-To: <1328627140-9923-1-git-send-email-kwolf@redhat.com>
If we want header extensions to work as compatible extensions, we can't
destroy yet unknown header extensions when rewriting the header (e.g.
for changing the backing file). Save all unknown header extensions in a
list of blobs and include them in a new header.
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
block/qcow2.c | 44 ++++++++++++++++++++++++++++++++++++++++++--
block/qcow2.h | 8 ++++++++
2 files changed, 50 insertions(+), 2 deletions(-)
diff --git a/block/qcow2.c b/block/qcow2.c
index 9f8c2de..3692b45 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -77,8 +77,10 @@ static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename)
static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
uint64_t end_offset)
{
+ BDRVQcowState *s = bs->opaque;
QCowExtension ext;
uint64_t offset;
+ int ret;
#ifdef DEBUG_EXT
printf("qcow2_read_extensions: start=%ld end=%ld\n", start_offset, end_offset);
@@ -129,8 +131,22 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
break;
default:
- /* unknown magic -- just skip it */
- offset = ((offset + ext.len + 7) & ~7);
+ /* unknown magic - save it in case we need to rewrite the header */
+ {
+ Qcow2UnknownHeaderExtension *uext;
+
+ uext = g_malloc0(sizeof(*uext) + ext.len);
+ uext->magic = ext.magic;
+ uext->len = ext.len;
+ QLIST_INSERT_HEAD(&s->unknown_header_ext, uext, next);
+
+ ret = bdrv_pread(bs->file, offset , uext->data, uext->len);
+ if (ret < 0) {
+ return ret;
+ }
+
+ offset = ((offset + ext.len + 7) & ~7);
+ }
break;
}
}
@@ -138,6 +154,16 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
return 0;
}
+static void cleanup_unknown_header_ext(BlockDriverState *bs)
+{
+ BDRVQcowState *s = bs->opaque;
+ Qcow2UnknownHeaderExtension *uext, *next;
+
+ QLIST_FOREACH_SAFE(uext, &s->unknown_header_ext, next, next) {
+ QLIST_REMOVE(uext, next);
+ g_free(uext);
+ }
+}
static int qcow2_open(BlockDriverState *bs, int flags)
{
@@ -291,6 +317,7 @@ static int qcow2_open(BlockDriverState *bs, int flags)
return ret;
fail:
+ cleanup_unknown_header_ext(bs);
qcow2_free_snapshots(bs);
qcow2_refcount_close(bs);
g_free(s->l1_table);
@@ -632,6 +659,7 @@ static void qcow2_close(BlockDriverState *bs)
qcow2_cache_destroy(bs, s->l2_table_cache);
qcow2_cache_destroy(bs, s->refcount_block_cache);
+ cleanup_unknown_header_ext(bs);
g_free(s->cluster_cache);
qemu_vfree(s->cluster_data);
qcow2_refcount_close(bs);
@@ -705,6 +733,7 @@ int qcow2_update_header(BlockDriverState *bs)
int ret;
uint64_t total_size;
uint32_t refcount_table_clusters;
+ Qcow2UnknownHeaderExtension *uext;
buf = qemu_blockalign(bs, buflen);
memset(buf, 0, s->cluster_size);
@@ -752,6 +781,17 @@ int qcow2_update_header(BlockDriverState *bs)
buflen -= ret;
}
+ /* Keep unknown header extensions */
+ QLIST_FOREACH(uext, &s->unknown_header_ext, next) {
+ ret = header_ext_add(buf, uext->magic, uext->data, uext->len, buflen);
+ if (ret < 0) {
+ goto fail;
+ }
+
+ buf += ret;
+ buflen -= ret;
+ }
+
/* End of header extensions */
ret = header_ext_add(buf, QCOW2_EXT_MAGIC_END, NULL, 0, buflen);
if (ret < 0) {
diff --git a/block/qcow2.h b/block/qcow2.h
index aae5f89..fc35838 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -87,6 +87,13 @@ typedef struct QCowSnapshot {
struct Qcow2Cache;
typedef struct Qcow2Cache Qcow2Cache;
+typedef struct Qcow2UnknownHeaderExtension {
+ uint32_t magic;
+ uint32_t len;
+ QLIST_ENTRY(Qcow2UnknownHeaderExtension) next;
+ uint8_t data[];
+} Qcow2UnknownHeaderExtension;
+
typedef struct BDRVQcowState {
int cluster_bits;
int cluster_size;
@@ -127,6 +134,7 @@ typedef struct BDRVQcowState {
QCowSnapshot *snapshots;
int flags;
+ QLIST_HEAD(, Qcow2UnknownHeaderExtension) unknown_header_ext;
} BDRVQcowState;
/* XXX: use std qcow open function ? */
--
1.7.6.5
prev parent reply other threads:[~2012-02-07 15:02 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-02-07 15:05 [Qemu-devel] [PATCH 0/2] qcow2: Rework header updates Kevin Wolf
2012-02-07 15:05 ` [Qemu-devel] [PATCH 1/2] qcow2: Update whole header at once Kevin Wolf
2012-02-07 15:05 ` Kevin Wolf [this message]
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=1328627140-9923-3-git-send-email-kwolf@redhat.com \
--to=kwolf@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=stefanha@gmail.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).