[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] tapdisk: Fix L1 table endianess of qcow images



# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1206638017 0
# Node ID 17e30b91b9e2a6607d7b2a7db011ac2a4f11d1d1
# Parent  a819cf758b8cf5624214ba59bc0c13172b3c7f05
tapdisk: Fix L1 table endianess of qcow images

Fix tapdisk to use big endian L1 tables as used by qemu/ioemu. Old
tapdisk images with native endianess are automagically converted to
big endian when the image file is opened for the first time.

Signed-off-by: Kevin Wolf <kwolf@xxxxxxx>
---
 tools/blktap/drivers/block-qcow.c |   68 ++++++++++++++++++++++++++++++++------
 1 files changed, 59 insertions(+), 9 deletions(-)

diff -r a819cf758b8c -r 17e30b91b9e2 tools/blktap/drivers/block-qcow.c
--- a/tools/blktap/drivers/block-qcow.c Thu Mar 27 16:20:25 2008 +0000
+++ b/tools/blktap/drivers/block-qcow.c Thu Mar 27 17:13:37 2008 +0000
@@ -76,6 +76,7 @@
 
 #define QCOW_OFLAG_COMPRESSED (1LL << 63)
 #define SPARSE_FILE 0x01
+#define EXTHDR_L1_BIG_ENDIAN 0x02
 
 #ifndef O_BINARY
 #define O_BINARY 0
@@ -147,19 +148,30 @@ static int decompress_cluster(struct tdq
 
 static uint32_t gen_cksum(char *ptr, int len)
 {
+       int i;
        unsigned char *md;
        uint32_t ret;
 
        md = malloc(MD5_DIGEST_LENGTH);
 
        if(!md) return 0;
-
-       if (MD5((unsigned char *)ptr, len, md) != md) {
-               free(md);
-               return 0;
-       }
-
-       memcpy(&ret, md, sizeof(uint32_t));
+       
+       /* Convert L1 table to big endian */
+       for(i = 0; i < len / sizeof(uint64_t); i++) {
+               cpu_to_be64s(&((uint64_t*) ptr)[i]);
+       }
+
+       /* Generate checksum */
+       if (MD5((unsigned char *)ptr, len, md) != md)
+               ret = 0;
+       else
+               memcpy(&ret, md, sizeof(uint32_t));
+
+       /* Convert L1 table back to native endianess */
+       for(i = 0; i < len / sizeof(uint64_t); i++) {
+               be64_to_cpus(&((uint64_t*) ptr)[i]);
+       }
+
        free(md);
        return ret;
 }
@@ -354,7 +366,8 @@ static uint64_t get_cluster_offset(struc
                                    int n_start, int n_end)
 {
        int min_index, i, j, l1_index, l2_index, l2_sector, l1_sector;
-       char *tmp_ptr, *tmp_ptr2, *l2_ptr, *l1_ptr;
+       char *tmp_ptr2, *l2_ptr, *l1_ptr;
+       uint64_t *tmp_ptr;
        uint64_t l2_offset, *l2_table, cluster_offset, tmp;
        uint32_t min_count;
        int new_l2_table;
@@ -400,6 +413,11 @@ static uint64_t get_cluster_offset(struc
                        DPRINTF("ERROR allocating memory for L1 table\n");
                }
                memcpy(tmp_ptr, l1_ptr, 4096);
+
+               /* Convert block to write to big endian */
+               for(i = 0; i < 4096 / sizeof(uint64_t); i++) {
+                       cpu_to_be64s(&tmp_ptr[i]);
+               }
 
                /*
                 * Issue non-asynchronous L1 write.
@@ -777,7 +795,7 @@ int tdqcow_open (struct disk_driver *dd,
                goto fail;
 
        for(i = 0; i < s->l1_size; i++) {
-               //be64_to_cpus(&s->l1_table[i]);
+               be64_to_cpus(&s->l1_table[i]);
                //DPRINTF("L1[%d] => %llu\n", i, s->l1_table[i]);
                if (s->l1_table[i] > final_cluster)
                        final_cluster = s->l1_table[i];
@@ -810,6 +828,38 @@ int tdqcow_open (struct disk_driver *dd,
                be32_to_cpus(&exthdr->xmagic);
                if(exthdr->xmagic != XEN_MAGIC) 
                        goto end_xenhdr;
+    
+               /* Try to detect old tapdisk images. They have to be fixed 
because 
+                * they don't use big endian but native endianess for the L1 
table */
+               if ((exthdr->flags & EXTHDR_L1_BIG_ENDIAN) == 0) {
+
+                       /* 
+                          The image is broken. Fix it. The L1 table has 
already been 
+                          byte-swapped, so we can write it to the image file 
as it is
+                          currently in memory. Then swap it back to native 
endianess
+                          for operation.
+                        */
+
+                       DPRINTF("qcow: Converting image to big endian L1 
table\n");
+
+                       lseek(fd, s->l1_table_offset, SEEK_SET);
+                       if (write(fd, s->l1_table, l1_table_size) != 
l1_table_size) {
+                               DPRINTF("qcow: Failed to write new L1 table\n");
+                               goto fail;
+                       }
+
+                       for(i = 0;i < s->l1_size; i++) {
+                               cpu_to_be64s(&s->l1_table[i]);
+                       }
+
+                       /* Write the big endian flag to the extended header */
+                       exthdr->flags |= EXTHDR_L1_BIG_ENDIAN;
+
+                       if (write(fd, buf, 512) != 512) {
+                               DPRINTF("qcow: Failed to write extended 
header\n");
+                               goto fail;
+                       }
+               }
 
                /*Finally check the L1 table cksum*/
                be32_to_cpus(&exthdr->cksum);

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.