ia64/xen-unstable

changeset 17341:17e30b91b9e2

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@suse.de>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Mar 27 17:13:37 2008 +0000 (2008-03-27)
parents a819cf758b8c
children 892a20f824a7
files tools/blktap/drivers/block-qcow.c
line diff
     1.1 --- a/tools/blktap/drivers/block-qcow.c	Thu Mar 27 16:20:25 2008 +0000
     1.2 +++ b/tools/blktap/drivers/block-qcow.c	Thu Mar 27 17:13:37 2008 +0000
     1.3 @@ -76,6 +76,7 @@
     1.4  
     1.5  #define QCOW_OFLAG_COMPRESSED (1LL << 63)
     1.6  #define SPARSE_FILE 0x01
     1.7 +#define EXTHDR_L1_BIG_ENDIAN 0x02
     1.8  
     1.9  #ifndef O_BINARY
    1.10  #define O_BINARY 0
    1.11 @@ -147,19 +148,30 @@ static int decompress_cluster(struct tdq
    1.12  
    1.13  static uint32_t gen_cksum(char *ptr, int len)
    1.14  {
    1.15 +	int i;
    1.16  	unsigned char *md;
    1.17  	uint32_t ret;
    1.18  
    1.19  	md = malloc(MD5_DIGEST_LENGTH);
    1.20  
    1.21  	if(!md) return 0;
    1.22 -
    1.23 -	if (MD5((unsigned char *)ptr, len, md) != md) {
    1.24 -		free(md);
    1.25 -		return 0;
    1.26 +	
    1.27 +	/* Convert L1 table to big endian */
    1.28 +	for(i = 0; i < len / sizeof(uint64_t); i++) {
    1.29 +		cpu_to_be64s(&((uint64_t*) ptr)[i]);
    1.30  	}
    1.31  
    1.32 -	memcpy(&ret, md, sizeof(uint32_t));
    1.33 +	/* Generate checksum */
    1.34 +	if (MD5((unsigned char *)ptr, len, md) != md)
    1.35 +		ret = 0;
    1.36 +	else
    1.37 +		memcpy(&ret, md, sizeof(uint32_t));
    1.38 +
    1.39 +	/* Convert L1 table back to native endianess */
    1.40 +	for(i = 0; i < len / sizeof(uint64_t); i++) {
    1.41 +		be64_to_cpus(&((uint64_t*) ptr)[i]);
    1.42 +	}
    1.43 +
    1.44  	free(md);
    1.45  	return ret;
    1.46  }
    1.47 @@ -354,7 +366,8 @@ static uint64_t get_cluster_offset(struc
    1.48                                     int n_start, int n_end)
    1.49  {
    1.50  	int min_index, i, j, l1_index, l2_index, l2_sector, l1_sector;
    1.51 -	char *tmp_ptr, *tmp_ptr2, *l2_ptr, *l1_ptr;
    1.52 +	char *tmp_ptr2, *l2_ptr, *l1_ptr;
    1.53 +	uint64_t *tmp_ptr;
    1.54  	uint64_t l2_offset, *l2_table, cluster_offset, tmp;
    1.55  	uint32_t min_count;
    1.56  	int new_l2_table;
    1.57 @@ -401,6 +414,11 @@ static uint64_t get_cluster_offset(struc
    1.58  		}
    1.59  		memcpy(tmp_ptr, l1_ptr, 4096);
    1.60  
    1.61 +		/* Convert block to write to big endian */
    1.62 +		for(i = 0; i < 4096 / sizeof(uint64_t); i++) {
    1.63 +			cpu_to_be64s(&tmp_ptr[i]);
    1.64 +		}
    1.65 +
    1.66  		/*
    1.67  		 * Issue non-asynchronous L1 write.
    1.68  		 * For safety, we must ensure that
    1.69 @@ -777,7 +795,7 @@ int tdqcow_open (struct disk_driver *dd,
    1.70  		goto fail;
    1.71  
    1.72  	for(i = 0; i < s->l1_size; i++) {
    1.73 -		//be64_to_cpus(&s->l1_table[i]);
    1.74 +		be64_to_cpus(&s->l1_table[i]);
    1.75  		//DPRINTF("L1[%d] => %llu\n", i, s->l1_table[i]);
    1.76  		if (s->l1_table[i] > final_cluster)
    1.77  			final_cluster = s->l1_table[i];
    1.78 @@ -810,6 +828,38 @@ int tdqcow_open (struct disk_driver *dd,
    1.79  		be32_to_cpus(&exthdr->xmagic);
    1.80  		if(exthdr->xmagic != XEN_MAGIC) 
    1.81  			goto end_xenhdr;
    1.82 +    
    1.83 +		/* Try to detect old tapdisk images. They have to be fixed because 
    1.84 +		 * they don't use big endian but native endianess for the L1 table */
    1.85 +		if ((exthdr->flags & EXTHDR_L1_BIG_ENDIAN) == 0) {
    1.86 +
    1.87 +			/* 
    1.88 +			   The image is broken. Fix it. The L1 table has already been 
    1.89 +			   byte-swapped, so we can write it to the image file as it is
    1.90 +			   currently in memory. Then swap it back to native endianess
    1.91 +			   for operation.
    1.92 +			 */
    1.93 +
    1.94 +			DPRINTF("qcow: Converting image to big endian L1 table\n");
    1.95 +
    1.96 +			lseek(fd, s->l1_table_offset, SEEK_SET);
    1.97 +			if (write(fd, s->l1_table, l1_table_size) != l1_table_size) {
    1.98 +				DPRINTF("qcow: Failed to write new L1 table\n");
    1.99 +				goto fail;
   1.100 +			}
   1.101 +
   1.102 +			for(i = 0;i < s->l1_size; i++) {
   1.103 +				cpu_to_be64s(&s->l1_table[i]);
   1.104 +			}
   1.105 +
   1.106 +			/* Write the big endian flag to the extended header */
   1.107 +			exthdr->flags |= EXTHDR_L1_BIG_ENDIAN;
   1.108 +
   1.109 +			if (write(fd, buf, 512) != 512) {
   1.110 +				DPRINTF("qcow: Failed to write extended header\n");
   1.111 +				goto fail;
   1.112 +			}
   1.113 +		}
   1.114  
   1.115  		/*Finally check the L1 table cksum*/
   1.116  		be32_to_cpus(&exthdr->cksum);