[libvirt] [PATCH 4/4] Support for probing qed image metadata

2010-11-19 Thread Adam Litke
Implement getBackingStore() for QED images.  The header format is defined in
the QED spec: http://wiki.qemu.org/Features/QED .

Signed-off-by: Adam Litke 
Cc: Stefan Hajnoczi 
Cc: Anthony Liguori 
---
 src/util/storage_file.c |   78 ++-
 1 files changed, 77 insertions(+), 1 deletions(-)

diff --git a/src/util/storage_file.c b/src/util/storage_file.c
index b656557..b195ef7 100644
--- a/src/util/storage_file.c
+++ b/src/util/storage_file.c
@@ -89,6 +89,8 @@ static int qcow2GetBackingStore(char **, int *,
 const unsigned char *, size_t);
 static int vmdk4GetBackingStore(char **, int *,
 const unsigned char *, size_t);
+static int
+qedGetBackingStore(char **, int *, const unsigned char *, size_t);
 
 #define QCOWX_HDR_VERSION (4)
 #define QCOWX_HDR_BACKING_FILE_OFFSET (QCOWX_HDR_VERSION+4)
@@ -105,6 +107,11 @@ static int vmdk4GetBackingStore(char **, int *,
 #define QCOW2_HDR_EXTENSION_BACKING_FORMAT 0xE2792ACA
 
 #define QED_HDR_IMAGE_SIZE 40
+#define QED_HDR_FEATURES_OFFSET 16
+#define QED_HDR_BACKING_FILE_OFFSET 56
+#define QED_HDR_BACKING_FILE_SIZE 60
+#define QED_F_BACKING_FILE 0x01
+#define QED_F_BACKING_FORMAT_NO_PROBE 0x04
 
 /* VMDK needs at least this to find backing store,
  * other formats need less */
@@ -156,7 +163,7 @@ static struct FileTypeInfo const fileTypeInfo[] = {
 [VIR_STORAGE_FILE_QED] = {
 "QED\0", NULL,
 LV_LITTLE_ENDIAN, -1, -1,
-QED_HDR_IMAGE_SIZE, 8, 1, -1, NULL,
+QED_HDR_IMAGE_SIZE, 8, 1, -1, qedGetBackingStore,
 },
 [VIR_STORAGE_FILE_VMDK] = {
 "KDMV", NULL,
@@ -416,6 +423,75 @@ cleanup:
 return ret;
 }
 
+static unsigned long
+qedGetHeaderUL(const unsigned char *loc)
+{
+return ( ((unsigned long)loc[3] << 24)
+   | ((unsigned long)loc[2] << 16)
+   | ((unsigned long)loc[1] << 8)
+   | ((unsigned long)loc[0] << 0));
+}
+
+static unsigned long long
+qedGetHeaderULL(const unsigned char *loc)
+{
+return ( ((unsigned long)loc[7] << 56)
+   | ((unsigned long)loc[6] << 48)
+   | ((unsigned long)loc[5] << 40)
+   | ((unsigned long)loc[4] << 32)
+   | ((unsigned long)loc[3] << 24)
+   | ((unsigned long)loc[2] << 16)
+   | ((unsigned long)loc[1] << 8)
+   | ((unsigned long)loc[0] << 0));
+}
+
+static int
+qedGetBackingStore(char **res,
+   int *format,
+   const unsigned char *buf,
+   size_t buf_size)
+{
+unsigned long long flags;
+unsigned long offset, size;
+
+*res = NULL;
+/* Check if this image has a backing file */
+if (buf_size < QED_HDR_FEATURES_OFFSET+8)
+return BACKING_STORE_INVALID;
+flags = qedGetHeaderULL(buf + QED_HDR_FEATURES_OFFSET);
+if (!(flags & QED_F_BACKING_FILE))
+return BACKING_STORE_OK;
+
+/* Parse the backing file */
+if (buf_size < QED_HDR_BACKING_FILE_OFFSET+8)
+return BACKING_STORE_INVALID;
+offset = qedGetHeaderUL(buf + QED_HDR_BACKING_FILE_OFFSET);
+if (offset > buf_size)
+return BACKING_STORE_INVALID;
+size = qedGetHeaderUL(buf + QED_HDR_BACKING_FILE_SIZE);
+if (size == 0)
+return BACKING_STORE_OK;
+if (offset + size > buf_size || offset + size < offset)
+return BACKING_STORE_INVALID;
+if (size + 1 == 0)
+return BACKING_STORE_INVALID;
+if (VIR_ALLOC_N(*res, size + 1) < 0) {
+virReportOOMError();
+return BACKING_STORE_ERROR;
+}
+memcpy(*res, buf + offset, size);
+(*res)[size] = '\0';
+
+if (format) {
+if (flags & QED_F_BACKING_FORMAT_NO_PROBE)
+*format = virStorageFileFormatTypeFromString("raw");
+else
+*format = VIR_STORAGE_FILE_AUTO_SAFE;
+}
+
+return BACKING_STORE_OK;
+}
+
 /**
  * Return an absolute path corresponding to PATH, which is absolute or relative
  * to the directory containing BASE_FILE, or NULL on error
-- 
1.7.3.2.164.g6f10c

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 4/4] Support for probing qed image metadata

2010-11-22 Thread Adam Litke
Implement getBackingStore() for QED images.  The header format is defined in
the QED spec: http://wiki.qemu.org/Features/QED .

Signed-off-by: Adam Litke 
Acked-by: Eric Blake 
Cc: Stefan Hajnoczi 
Cc: Anthony Liguori 
---
 src/util/storage_file.c |   78 +-
 1 files changed, 76 insertions(+), 2 deletions(-)

diff --git a/src/util/storage_file.c b/src/util/storage_file.c
index 89c2cbe..9d97066 100644
--- a/src/util/storage_file.c
+++ b/src/util/storage_file.c
@@ -89,6 +89,8 @@ static int qcow2GetBackingStore(char **, int *,
 const unsigned char *, size_t);
 static int vmdk4GetBackingStore(char **, int *,
 const unsigned char *, size_t);
+static int
+qedGetBackingStore(char **, int *, const unsigned char *, size_t);
 
 #define QCOWX_HDR_VERSION (4)
 #define QCOWX_HDR_BACKING_FILE_OFFSET (QCOWX_HDR_VERSION+4)
@@ -104,7 +106,12 @@ static int vmdk4GetBackingStore(char **, int *,
 #define QCOW2_HDR_EXTENSION_END 0
 #define QCOW2_HDR_EXTENSION_BACKING_FORMAT 0xE2792ACA
 
-#define QED_HDR_IMAGE_SIZE (4+4+4+4+8+8+8)
+#define QED_HDR_FEATURES_OFFSET (4+4+4+4)
+#define QED_HDR_IMAGE_SIZE (QED_HDR_FEATURES_OFFSET+8+8+8+8)
+#define QED_HDR_BACKING_FILE_OFFSET (QED_HDR_IMAGE_SIZE+8)
+#define QED_HDR_BACKING_FILE_SIZE (QED_HDR_BACKING_FILE_OFFSET+4)
+#define QED_F_BACKING_FILE 0x01
+#define QED_F_BACKING_FORMAT_NO_PROBE 0x04
 
 /* VMDK needs at least this to find backing store,
  * other formats need less */
@@ -157,7 +164,7 @@ static struct FileTypeInfo const fileTypeInfo[] = {
 /* http://wiki.qemu.org/Features/QED */
 "QED\0", NULL,
 LV_LITTLE_ENDIAN, -1, -1,
-QED_HDR_IMAGE_SIZE, 8, 1, -1, NULL,
+QED_HDR_IMAGE_SIZE, 8, 1, -1, qedGetBackingStore,
 },
 [VIR_STORAGE_FILE_VMDK] = {
 "KDMV", NULL,
@@ -417,6 +424,73 @@ cleanup:
 return ret;
 }
 
+static unsigned long
+qedGetHeaderUL(const unsigned char *loc)
+{
+return ( ((unsigned long)loc[3] << 24)
+   | ((unsigned long)loc[2] << 16)
+   | ((unsigned long)loc[1] << 8)
+   | ((unsigned long)loc[0] << 0));
+}
+
+static unsigned long long
+qedGetHeaderULL(const unsigned char *loc)
+{
+return ( ((unsigned long)loc[7] << 56)
+   | ((unsigned long)loc[6] << 48)
+   | ((unsigned long)loc[5] << 40)
+   | ((unsigned long)loc[4] << 32)
+   | ((unsigned long)loc[3] << 24)
+   | ((unsigned long)loc[2] << 16)
+   | ((unsigned long)loc[1] << 8)
+   | ((unsigned long)loc[0] << 0));
+}
+
+static int
+qedGetBackingStore(char **res,
+   int *format,
+   const unsigned char *buf,
+   size_t buf_size)
+{
+unsigned long long flags;
+unsigned long offset, size;
+
+*res = NULL;
+/* Check if this image has a backing file */
+if (buf_size < QED_HDR_FEATURES_OFFSET+8)
+return BACKING_STORE_INVALID;
+flags = qedGetHeaderULL(buf + QED_HDR_FEATURES_OFFSET);
+if (!(flags & QED_F_BACKING_FILE))
+return BACKING_STORE_OK;
+
+/* Parse the backing file */
+if (buf_size < QED_HDR_BACKING_FILE_OFFSET+8)
+return BACKING_STORE_INVALID;
+offset = qedGetHeaderUL(buf + QED_HDR_BACKING_FILE_OFFSET);
+if (offset > buf_size)
+return BACKING_STORE_INVALID;
+size = qedGetHeaderUL(buf + QED_HDR_BACKING_FILE_SIZE);
+if (size == 0)
+return BACKING_STORE_OK;
+if (offset + size > buf_size || offset + size < offset)
+return BACKING_STORE_INVALID;
+if (VIR_ALLOC_N(*res, size + 1) < 0) {
+virReportOOMError();
+return BACKING_STORE_ERROR;
+}
+memcpy(*res, buf + offset, size);
+(*res)[size] = '\0';
+
+if (format) {
+if (flags & QED_F_BACKING_FORMAT_NO_PROBE)
+*format = VIR_STORAGE_FILE_RAW;
+else
+*format = VIR_STORAGE_FILE_AUTO_SAFE;
+}
+
+return BACKING_STORE_OK;
+}
+
 /**
  * Return an absolute path corresponding to PATH, which is absolute or relative
  * to the directory containing BASE_FILE, or NULL on error
-- 
1.7.3.2.164.g6f10c

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


Re: [libvirt] [PATCH 4/4] Support for probing qed image metadata

2010-11-19 Thread Eric Blake
On 11/19/2010 09:18 AM, Adam Litke wrote:
> Implement getBackingStore() for QED images.  The header format is defined in
> the QED spec: http://wiki.qemu.org/Features/QED .
> 
> Signed-off-by: Adam Litke 
> Cc: Stefan Hajnoczi 
> Cc: Anthony Liguori 
> ---
>  src/util/storage_file.c |   78 
> ++-
>  1 files changed, 77 insertions(+), 1 deletions(-)

Aha - I should have read this before commenting on patch 2.

> @@ -105,6 +107,11 @@ static int vmdk4GetBackingStore(char **, int *,
>  #define QCOW2_HDR_EXTENSION_BACKING_FORMAT 0xE2792ACA
>  
>  #define QED_HDR_IMAGE_SIZE 40
> +#define QED_HDR_FEATURES_OFFSET 16
> +#define QED_HDR_BACKING_FILE_OFFSET 56
> +#define QED_HDR_BACKING_FILE_SIZE 60
> +#define QED_F_BACKING_FILE 0x01
> +#define QED_F_BACKING_FORMAT_NO_PROBE 0x04

Again, I'll break the offsets into pieces.  See below.

>  
> +static unsigned long
> +qedGetHeaderUL(const unsigned char *loc)
> +{
> +return ( ((unsigned long)loc[3] << 24)
> +   | ((unsigned long)loc[2] << 16)
> +   | ((unsigned long)loc[1] << 8)
> +   | ((unsigned long)loc[0] << 0));
> +}
> +
> +static unsigned long long
> +qedGetHeaderULL(const unsigned char *loc)
> +{
> +return ( ((unsigned long)loc[7] << 56)
> +   | ((unsigned long)loc[6] << 48)
> +   | ((unsigned long)loc[5] << 40)
> +   | ((unsigned long)loc[4] << 32)
> +   | ((unsigned long)loc[3] << 24)
> +   | ((unsigned long)loc[2] << 16)
> +   | ((unsigned long)loc[1] << 8)
> +   | ((unsigned long)loc[0] << 0));
> +}

These two routines are independently useful for other little-endian
parsers in the same file.  Should we (as a separate patch) rename them
and put them to wider use, as well as adding big-endian counterparts for
the remaining file formats to share?  It would cut down on the number of
open-coded integer constructions elsewhere in the file.

> +
> +static int
> +qedGetBackingStore(char **res,
> +   int *format,
> +   const unsigned char *buf,
> +   size_t buf_size)
> +{
> +unsigned long long flags;
> +unsigned long offset, size;
> +
> +*res = NULL;
> +/* Check if this image has a backing file */
> +if (buf_size < QED_HDR_FEATURES_OFFSET+8)
> +return BACKING_STORE_INVALID;
> +flags = qedGetHeaderULL(buf + QED_HDR_FEATURES_OFFSET);
> +if (!(flags & QED_F_BACKING_FILE))
> +return BACKING_STORE_OK;
> +
> +/* Parse the backing file */
> +if (buf_size < QED_HDR_BACKING_FILE_OFFSET+8)
> +return BACKING_STORE_INVALID;
> +offset = qedGetHeaderUL(buf + QED_HDR_BACKING_FILE_OFFSET);
> +if (offset > buf_size)
> +return BACKING_STORE_INVALID;
> +size = qedGetHeaderUL(buf + QED_HDR_BACKING_FILE_SIZE);
> +if (size == 0)
> +return BACKING_STORE_OK;
> +if (offset + size > buf_size || offset + size < offset)
> +return BACKING_STORE_INVALID;
> +if (size + 1 == 0)
> +return BACKING_STORE_INVALID;

This clause is redundant; you already rejected offset + size < offset,
and size + 1 == 0 implies size == -1, which would have failed that
earlier check.

ACK, with this squashed in.  I've pushed your series.

gdiff --git i/src/util/storage_file.c w/src/util/storage_file.c
index d7b4073..aa117e7 100644
--- i/src/util/storage_file.c
+++ w/src/util/storage_file.c
@@ -107,10 +107,10 @@ qedGetBackingStore(char **, int *, const unsigned
char *, size_t);
 #define QCOW2_HDR_EXTENSION_END 0
 #define QCOW2_HDR_EXTENSION_BACKING_FORMAT 0xE2792ACA

-#define QED_HDR_IMAGE_SIZE (4+4+4+4+8+8+8)
-#define QED_HDR_FEATURES_OFFSET 16
-#define QED_HDR_BACKING_FILE_OFFSET 56
-#define QED_HDR_BACKING_FILE_SIZE 60
+#define QED_HDR_FEATURES_OFFSET (4+4+4+4)
+#define QED_HDR_IMAGE_SIZE (QED_HDR_FEATURES_OFFSET+8+8+8)
+#define QED_HDR_BACKING_FILE_OFFSET (QED_HDR_IMAGE_SIZE+8+8)
+#define QED_HDR_BACKING_FILE_SIZE (QED_HDR_BACKING_FILE_OFFSET+4)
 #define QED_F_BACKING_FILE 0x01
 #define QED_F_BACKING_FORMAT_NO_PROBE 0x04

@@ -475,8 +475,6 @@ qedGetBackingStore(char **res,
 return BACKING_STORE_OK;
 if (offset + size > buf_size || offset + size < offset)
 return BACKING_STORE_INVALID;
-if (size + 1 == 0)
-return BACKING_STORE_INVALID;
 if (VIR_ALLOC_N(*res, size + 1) < 0) {
 virReportOOMError();
 return BACKING_STORE_ERROR;

-- 
Eric Blake   ebl...@redhat.com+1-801-349-2682
Libvirt virtualization library http://libvirt.org



signature.asc
Description: OpenPGP digital signature
--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Re: [libvirt] [PATCH 4/4] Support for probing qed image metadata

2010-11-19 Thread Eric Blake
On 11/19/2010 09:18 AM, Adam Litke wrote:
> Implement getBackingStore() for QED images.  The header format is defined in
> the QED spec: http://wiki.qemu.org/Features/QED .
> 

> +if (offset + size > buf_size || offset + size < offset)
> +return BACKING_STORE_INVALID;

As currently coded, buf_size is at most STORAGE_MAX_HEAD (20*512).
QED does not appear to have any maximum header size (other than the fact
that header size is a multiple of cluster size), and permits a cluster
size of 2**26.

I don't see anything on the QED file format that requires the
backing_filename to occur within the header clusters (that is, shouldn't
QED add a file format restriction that
backing_filename_offset+backing_filename_size must be less than the
start of the first regular cluster?).

More worrying, I don't see anything in QED that requires the filename to
occur within the first 10K bytes.  Do we need to add another enum value
to libvirt's backing store callback routine, to be used when the header
requests data that lies beyond buf_size but is still feasibly valid, for
the case where QED designates a backing store location that is beyond
10k but still before the start of the first cluster, rather than the
current approach of just treating it as BACKING_STORE_INVALID?

-- 
Eric Blake   ebl...@redhat.com+1-801-349-2682
Libvirt virtualization library http://libvirt.org



signature.asc
Description: OpenPGP digital signature
--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Re: [libvirt] [PATCH 4/4] Support for probing qed image metadata

2010-11-23 Thread Stefan Hajnoczi
On Fri, Nov 19, 2010 at 11:54 PM, Eric Blake  wrote:
> On 11/19/2010 09:18 AM, Adam Litke wrote:
>> Implement getBackingStore() for QED images.  The header format is defined in
>> the QED spec: http://wiki.qemu.org/Features/QED .
>>
>
>> +    if (offset + size > buf_size || offset + size < offset)
>> +        return BACKING_STORE_INVALID;
>
> As currently coded, buf_size is at most STORAGE_MAX_HEAD (20*512).
> QED does not appear to have any maximum header size (other than the fact
> that header size is a multiple of cluster size), and permits a cluster
> size of 2**26.
>
> I don't see anything on the QED file format that requires the
> backing_filename to occur within the header clusters (that is, shouldn't
> QED add a file format restriction that
> backing_filename_offset+backing_filename_size must be less than the
> start of the first regular cluster?).
>
> More worrying, I don't see anything in QED that requires the filename to
> occur within the first 10K bytes.  Do we need to add another enum value
> to libvirt's backing store callback routine, to be used when the header
> requests data that lies beyond buf_size but is still feasibly valid, for
> the case where QED designates a backing store location that is beyond
> 10k but still before the start of the first cluster, rather than the
> current approach of just treating it as BACKING_STORE_INVALID?

QED doesn't explicitly restrict
backing_filename_offset/backing_filename_size to just the header
cluster(s).  I think it makes sense to say backing_filename_offset +
backing_filename_size <= header_size * cluster_size and will add it to
the QED spec.

But that doesn't guarantee backing_filename_offset < 10 KB.  The space
after struct QEDHeader is explicitly unstructured so extensions can
put arbitrary data there in a backwards compatible way.

Stefan

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


Re: [libvirt] [PATCH 4/4] Support for probing qed image metadata

2010-11-23 Thread Eric Blake
On 11/23/2010 06:26 AM, Stefan Hajnoczi wrote:
>> More worrying, I don't see anything in QED that requires the filename to
>> occur within the first 10K bytes.  Do we need to add another enum value
>> to libvirt's backing store callback routine, to be used when the header
>> requests data that lies beyond buf_size but is still feasibly valid, for
>> the case where QED designates a backing store location that is beyond
>> 10k but still before the start of the first cluster, rather than the
>> current approach of just treating it as BACKING_STORE_INVALID?
> 
> QED doesn't explicitly restrict
> backing_filename_offset/backing_filename_size to just the header
> cluster(s).  I think it makes sense to say backing_filename_offset +
> backing_filename_size <= header_size * cluster_size and will add it to
> the QED spec.

Thanks.  Do you also want to require that backing_filename_offset >
sizeof(backing_filename_size)+offsetof(header,backing_filename_size)?
That is, it doesn't make sense for the backing filename to overlap with
existing header elements.

> 
> But that doesn't guarantee backing_filename_offset < 10 KB.  The space
> after struct QEDHeader is explicitly unstructured so extensions can
> put arbitrary data there in a backwards compatible way.

I agree that QED should not have to arbitrarily restrict things because
of libvirt.  Rather, libvirt should be patched to be able to find a
backing filename that lies beyond 10K but still within the header clusters.

-- 
Eric Blake   ebl...@redhat.com+1-801-349-2682
Libvirt virtualization library http://libvirt.org



signature.asc
Description: OpenPGP digital signature
--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Re: [libvirt] [PATCH 4/4] Support for probing qed image metadata

2010-11-23 Thread Stefan Hajnoczi
On Tue, Nov 23, 2010 at 3:10 PM, Eric Blake  wrote:
> On 11/23/2010 06:26 AM, Stefan Hajnoczi wrote:
>>> More worrying, I don't see anything in QED that requires the filename to
>>> occur within the first 10K bytes.  Do we need to add another enum value
>>> to libvirt's backing store callback routine, to be used when the header
>>> requests data that lies beyond buf_size but is still feasibly valid, for
>>> the case where QED designates a backing store location that is beyond
>>> 10k but still before the start of the first cluster, rather than the
>>> current approach of just treating it as BACKING_STORE_INVALID?
>>
>> QED doesn't explicitly restrict
>> backing_filename_offset/backing_filename_size to just the header
>> cluster(s).  I think it makes sense to say backing_filename_offset +
>> backing_filename_size <= header_size * cluster_size and will add it to
>> the QED spec.
>
> Thanks.  Do you also want to require that backing_filename_offset >
> sizeof(backing_filename_size)+offsetof(header,backing_filename_size)?
> That is, it doesn't make sense for the backing filename to overlap with
> existing header elements.

Although I agree that it doesn't make sense to overlap the backing
filename with the header fields it isn't possible to check this fully.
 A backwards compatible QED image could have feature bits enabled for
new header fields that an old programs don't know about.  At that
point the "header structure size" is just an arbitrary number and we
can't really guard where the backing filename should be stored.

Stefan

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list