diff options
author | Avi Kivity <avi@qumranet.com> | 2007-10-01 15:49:46 +0200 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2007-10-01 18:14:24 +0200 |
commit | c087cad8039cf0d5a7128597396483352d4138dd (patch) | |
tree | e9bf7f2fd7efb8555dd2645ac6c9b77a69b762bd /block-vmdk.c | |
parent | Add missing break after -tdf option parsing (diff) | |
parent | Import qemu as of Mon Oct 1 10:51:47 IST 2007 (diff) | |
download | qemu-kvm-c087cad8039cf0d5a7128597396483352d4138dd.tar.gz qemu-kvm-c087cad8039cf0d5a7128597396483352d4138dd.tar.bz2 qemu-kvm-c087cad8039cf0d5a7128597396483352d4138dd.zip |
Merge branch 'qemu-vendor-drops' (qemu as of 2007-10-01)
Conflicts:
kernel/Kbuild
kernel/Makefile
qemu/.cvsignore
qemu/Changelog
qemu/Makefile
qemu/Makefile.target
qemu/arm-semi.c
qemu/audio/audio.c
qemu/audio/audio_template.h
qemu/audio/coreaudio.c
qemu/audio/wavaudio.c
qemu/audio/wavcapture.c
qemu/block-bochs.c
qemu/block-cow.c
qemu/block-qcow.c
qemu/block-qcow2.c
qemu/block-raw.c
qemu/block-vmdk.c
qemu/block-vpc.c
qemu/block-vvfat.c
qemu/block.c
qemu/block_int.h
qemu/configure
qemu/console.c
qemu/cpu-all.h
qemu/cpu-defs.h
qemu/cpu-exec.c
qemu/cutils.c
qemu/darwin-user/main.c
qemu/darwin-user/mmap.c
qemu/darwin-user/syscall.c
qemu/darwin-user/syscalls.h
qemu/dyngen-exec.h
qemu/dyngen.c
qemu/dyngen.h
qemu/elf.h
qemu/exec-all.h
qemu/exec.c
qemu/fpu/softfloat-native.c
qemu/fpu/softfloat.h
qemu/gdbstub.c
qemu/gdbstub.h
qemu/hw/acpi.c
qemu/hw/apb_pci.c
qemu/hw/apic.c
qemu/hw/arm_boot.c
qemu/hw/arm_gic.c
qemu/hw/arm_sysctl.c
qemu/hw/arm_timer.c
qemu/hw/cdrom.c
qemu/hw/cirrus_vga.c
qemu/hw/cs4231.c
qemu/hw/cuda.c
qemu/hw/esp.c
qemu/hw/fdc.c
qemu/hw/grackle_pci.c
qemu/hw/gt64xxx.c
qemu/hw/i8254.c
qemu/hw/i8259.c
qemu/hw/ide.c
qemu/hw/integratorcp.c
qemu/hw/iommu.c
qemu/hw/isa_mmio.c
qemu/hw/lsi53c895a.c
qemu/hw/m48t59.c
qemu/hw/mc146818rtc.c
qemu/hw/mips_int.c
qemu/hw/mips_malta.c
qemu/hw/mips_r4k.c
qemu/hw/mips_timer.c
qemu/hw/ne2000.c
qemu/hw/pc.c
qemu/hw/pci.c
qemu/hw/pci_host.h
qemu/hw/pcnet.c
qemu/hw/pflash_cfi02.c
qemu/hw/piix_pci.c
qemu/hw/pl011.c
qemu/hw/pl050.c
qemu/hw/pl080.c
qemu/hw/ppc.c
qemu/hw/ppc_chrp.c
qemu/hw/ppc_prep.c
qemu/hw/prep_pci.c
qemu/hw/realview.c
qemu/hw/rtl8139.c
qemu/hw/scsi-disk.c
qemu/hw/sh7750.c
qemu/hw/slavio_serial.c
qemu/hw/slavio_timer.c
qemu/hw/smbus.h
qemu/hw/smbus_eeprom.c
qemu/hw/sparc32_dma.c
qemu/hw/sun4m.c
qemu/hw/sun4u.c
qemu/hw/tcx.c
qemu/hw/unin_pci.c
qemu/hw/usb-hid.c
qemu/hw/usb-hub.c
qemu/hw/usb-msd.c
qemu/hw/usb-ohci.c
qemu/hw/usb-uhci.c
qemu/hw/usb.h
qemu/hw/versatile_pci.c
qemu/hw/versatilepb.c
qemu/hw/vga.c
qemu/hw/vga_int.h
qemu/hw/vga_template.h
qemu/kqemu.c
qemu/linux-user/arm/syscall_nr.h
qemu/linux-user/elfload.c
qemu/linux-user/flat.h
qemu/linux-user/flatload.c
qemu/linux-user/linuxload.c
qemu/linux-user/m68k-sim.c
qemu/linux-user/m68k/syscall_nr.h
qemu/linux-user/m68k/termbits.h
qemu/linux-user/main.c
qemu/linux-user/mmap.c
qemu/linux-user/qemu.h
qemu/linux-user/signal.c
qemu/linux-user/syscall.c
qemu/linux-user/syscall_defs.h
qemu/monitor.c
qemu/osdep.c
qemu/osdep.h
qemu/pc-bios/README
qemu/pc-bios/bios.bin
qemu/pc-bios/bios.diff
qemu/pc-bios/openbios-sparc32
qemu/pc-bios/vgabios-cirrus.bin
qemu/pc-bios/vgabios.bin
qemu/ppc.ld
qemu/qemu-doc.texi
qemu/qemu-img.c
qemu/sdl.c
qemu/slirp/tcp_subr.c
qemu/slirp/udp.c
qemu/target-arm/cpu.h
qemu/target-arm/helper.c
qemu/target-arm/translate.c
qemu/target-i386/cpu.h
qemu/target-i386/exec.h
qemu/target-i386/helper.c
qemu/target-i386/helper2.c
qemu/target-i386/translate.c
qemu/target-m68k/cpu.h
qemu/target-m68k/exec.h
qemu/target-m68k/helper.c
qemu/target-m68k/op-hacks.h
qemu/target-m68k/op.c
qemu/target-m68k/qregs.def
qemu/target-m68k/translate.c
qemu/target-mips/TODO
qemu/target-mips/cpu.h
qemu/target-mips/exec.h
qemu/target-mips/fop_template.c
qemu/target-mips/helper.c
qemu/target-mips/mips-defs.h
qemu/target-mips/op.c
qemu/target-mips/op_helper.c
qemu/target-mips/op_helper_mem.c
qemu/target-mips/op_mem.c
qemu/target-mips/op_template.c
qemu/target-mips/translate.c
qemu/target-ppc/cpu.h
qemu/target-ppc/helper.c
qemu/target-ppc/op.c
qemu/target-ppc/translate.c
qemu/target-ppc/translate_init.c
qemu/target-sh4/cpu.h
qemu/target-sh4/helper.c
qemu/target-sh4/op.c
qemu/target-sh4/translate.c
qemu/target-sparc/cpu.h
qemu/target-sparc/exec.h
qemu/target-sparc/helper.c
qemu/target-sparc/op.c
qemu/target-sparc/op_helper.c
qemu/target-sparc/translate.c
qemu/tests/Makefile
qemu/usb-linux.c
qemu/vl.c
qemu/vl.h
qemu/vnc.c
qemu/vnchextile.h
user/Makefile
Diffstat (limited to 'block-vmdk.c')
-rw-r--r-- | block-vmdk.c | 186 |
1 files changed, 131 insertions, 55 deletions
diff --git a/block-vmdk.c b/block-vmdk.c index be75e0dd8..1f3709ced 100644 --- a/block-vmdk.c +++ b/block-vmdk.c @@ -1,9 +1,9 @@ /* * Block driver for the VMDK format - * + * * Copyright (c) 2004 Fabrice Bellard * Copyright (c) 2005 Filip Navara - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -75,9 +75,25 @@ typedef struct BDRVVmdkState { unsigned int cluster_sectors; uint32_t parent_cid; + int is_parent; DiskIOStatistics io; } BDRVVmdkState; +typedef struct VmdkMetaData { + uint32_t offset; + unsigned int l1_index; + unsigned int l2_index; + unsigned int l2_offset; + int valid; +} VmdkMetaData; + +typedef struct ActiveBDRVState{ + BlockDriverState *hd; // active image handler + uint64_t cluster_offset; // current write offset +}ActiveBDRVState; + +static ActiveBDRVState activeBDRV; + DiskIOStatistics vmdk_io_statistics(BlockDriverState *bs) { BDRVVmdkState *s = bs->opaque; @@ -101,16 +117,16 @@ static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename) #define CHECK_CID 1 -#define SECTOR_SIZE 512 +#define SECTOR_SIZE 512 #define DESC_SIZE 20*SECTOR_SIZE // 20 sectors of 512 bytes each -#define HEADER_SIZE 512 // first sector of 512 bytes +#define HEADER_SIZE 512 // first sector of 512 bytes static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent) { BDRVVmdkState *s = bs->opaque; char desc[DESC_SIZE]; uint32_t cid; - char *p_name, *cid_str; + char *p_name, *cid_str; size_t cid_str_size; /* the descriptor offset = 0x200 */ @@ -178,7 +194,7 @@ static int vmdk_snapshot_create(const char *filename, const char *backing_file) { int snp_fd, p_fd; uint32_t p_cid; - char *p_name, *gd_buf, *rgd_buf; + char *p_name, *gd_buf, *rgd_buf; const char *real_filename, *temp_str; VMDK4Header header; uint32_t gde_entries, gd_size; @@ -262,7 +278,7 @@ static int vmdk_snapshot_create(const char *filename, const char *backing_file) gt_size = (int64_t)header.num_gtes_per_gte * header.granularity * SECTOR_SIZE; if (!gt_size) goto fail; - gde_entries = (uint32_t)(capacity / gt_size); // number of gde/rgde + gde_entries = (uint32_t)(capacity / gt_size); // number of gde/rgde gd_size = gde_entries * sizeof(uint32_t); /* write RGD */ @@ -299,7 +315,7 @@ static int vmdk_snapshot_create(const char *filename, const char *backing_file) fail_gd: qemu_free(gd_buf); - fail_rgd: + fail_rgd: qemu_free(rgd_buf); fail: close(p_fd); @@ -313,11 +329,11 @@ static void vmdk_parent_close(BlockDriverState *bs) bdrv_close(bs->backing_hd); } - +int parent_open = 0; static int vmdk_parent_open(BlockDriverState *bs, const char * filename) { BDRVVmdkState *s = bs->opaque; - char *p_name; + char *p_name; char desc[DESC_SIZE]; char parent_img_name[1024]; @@ -332,7 +348,7 @@ static int vmdk_parent_open(BlockDriverState *bs, const char * filename) p_name += sizeof("parentFileNameHint") + 1; if ((end_name = strchr(p_name,'\"')) == 0) return -1; - + strncpy(s->hd->backing_file, p_name, end_name - p_name); if (stat(s->hd->backing_file, &file_buf) != 0) { path_combine(parent_img_name, sizeof(parent_img_name), @@ -347,8 +363,10 @@ static int vmdk_parent_open(BlockDriverState *bs, const char * filename) bdrv_close(s->hd); return -1; } - if (bdrv_open(s->hd->backing_hd, parent_img_name, 0) < 0) + parent_open = 1; + if (bdrv_open(s->hd->backing_hd, parent_img_name, BDRV_O_RDONLY) < 0) goto failure; + parent_open = 0; } return 0; @@ -360,6 +378,11 @@ static int vmdk_open(BlockDriverState *bs, const char *filename, int flags) uint32_t magic; int l1_size, i, ret; + if (parent_open) + // Parent must be opened as RO. + flags = BDRV_O_RDONLY; + fprintf(stderr, "(VMDK) image open: flags=0x%x filename=%s\n", flags, bs->filename); + ret = bdrv_file_open(&s->hd, filename, flags); if (ret < 0) return ret; @@ -390,11 +413,16 @@ static int vmdk_open(BlockDriverState *bs, const char *filename, int flags) s->l1_entry_sectors = s->l2_size * s->cluster_sectors; if (s->l1_entry_sectors <= 0) goto fail; - s->l1_size = (bs->total_sectors + s->l1_entry_sectors - 1) + s->l1_size = (bs->total_sectors + s->l1_entry_sectors - 1) / s->l1_entry_sectors; s->l1_table_offset = le64_to_cpu(header.rgd_offset) << 9; s->l1_backup_table_offset = le64_to_cpu(header.gd_offset) << 9; + if (parent_open) + s->is_parent = 1; + else + s->is_parent = 0; + // try to open parent images, if exist if (vmdk_parent_open(bs, filename) != 0) goto fail; @@ -438,7 +466,8 @@ static int vmdk_open(BlockDriverState *bs, const char *filename, int flags) return -1; } -static uint64_t get_cluster_offset(BlockDriverState *bs, uint64_t offset, int allocate); +static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data, + uint64_t offset, int allocate); static int get_whole_cluster(BlockDriverState *bs, uint64_t cluster_offset, uint64_t offset, int allocate) @@ -454,27 +483,54 @@ static int get_whole_cluster(BlockDriverState *bs, uint64_t cluster_offset, if (!vmdk_is_cid_valid(bs)) return -1; - parent_cluster_offset = get_cluster_offset(s->hd->backing_hd, offset, allocate); - if (bdrv_pread(ps->hd, parent_cluster_offset, whole_grain, ps->cluster_sectors*512) != - ps->cluster_sectors*512) - return -1; - if (bdrv_pwrite(s->hd, cluster_offset << 9, whole_grain, sizeof(whole_grain)) != - sizeof(whole_grain)) + parent_cluster_offset = get_cluster_offset(s->hd->backing_hd, NULL, offset, allocate); + + if (parent_cluster_offset) { + BDRVVmdkState *act_s = activeBDRV.hd->opaque; + + if (bdrv_pread(ps->hd, parent_cluster_offset, whole_grain, ps->cluster_sectors*512) != ps->cluster_sectors*512) + return -1; + + //Write grain only into the active image + if (bdrv_pwrite(act_s->hd, activeBDRV.cluster_offset << 9, whole_grain, sizeof(whole_grain)) != sizeof(whole_grain)) + return -1; + } + } + return 0; +} + +static int vmdk_L2update(BlockDriverState *bs, VmdkMetaData *m_data) +{ + BDRVVmdkState *s = bs->opaque; + + /* update L2 table */ + if (bdrv_pwrite(s->hd, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)), + &(m_data->offset), sizeof(m_data->offset)) != sizeof(m_data->offset)) + return -1; + /* update backup L2 table */ + if (s->l1_backup_table_offset != 0) { + m_data->l2_offset = s->l1_backup_table[m_data->l1_index]; + if (bdrv_pwrite(s->hd, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)), + &(m_data->offset), sizeof(m_data->offset)) != sizeof(m_data->offset)) return -1; } + return 0; } -static uint64_t get_cluster_offset(BlockDriverState *bs, +static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data, uint64_t offset, int allocate) { BDRVVmdkState *s = bs->opaque; unsigned int l1_index, l2_offset, l2_index; int min_index, i, j; - uint32_t min_count, *l2_table, tmp; + uint32_t min_count, *l2_table, tmp = 0; uint64_t cluster_offset; - + + if (m_data) + m_data->valid = 0; + l1_index = (offset >> 9) / s->l1_entry_sectors; if (l1_index >= s->l1_size) return 0; @@ -503,7 +559,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, } } l2_table = s->l2_cache + (min_index * s->l2_size); - if (bdrv_pread(s->hd, (int64_t)l2_offset * 512, l2_table, s->l2_size * sizeof(uint32_t)) != + if (bdrv_pread(s->hd, (int64_t)l2_offset * 512, l2_table, s->l2_size * sizeof(uint32_t)) != s->l2_size * sizeof(uint32_t)) return 0; @@ -512,45 +568,50 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, found: l2_index = ((offset >> 9) / s->cluster_sectors) % s->l2_size; cluster_offset = le32_to_cpu(l2_table[l2_index]); - if (!cluster_offset) { - struct stat file_buf; + if (!cluster_offset) { if (!allocate) return 0; - stat(s->hd->filename, &file_buf); - cluster_offset = file_buf.st_size; - bdrv_truncate(s->hd, cluster_offset + (s->cluster_sectors << 9)); - - cluster_offset >>= 9; - /* update L2 table */ - tmp = cpu_to_le32(cluster_offset); - l2_table[l2_index] = tmp; - if (bdrv_pwrite(s->hd, ((int64_t)l2_offset * 512) + (l2_index * sizeof(tmp)), - &tmp, sizeof(tmp)) != sizeof(tmp)) - return 0; - /* update backup L2 table */ - if (s->l1_backup_table_offset != 0) { - l2_offset = s->l1_backup_table[l1_index]; - if (bdrv_pwrite(s->hd, ((int64_t)l2_offset * 512) + (l2_index * sizeof(tmp)), - &tmp, sizeof(tmp)) != sizeof(tmp)) - return 0; + // Avoid the L2 tables update for the images that have snapshots. + if (!s->is_parent) { + cluster_offset = bdrv_getlength(s->hd); + bdrv_truncate(s->hd, cluster_offset + (s->cluster_sectors << 9)); + + cluster_offset >>= 9; + tmp = cpu_to_le32(cluster_offset); + l2_table[l2_index] = tmp; + // Save the active image state + activeBDRV.cluster_offset = cluster_offset; + activeBDRV.hd = bs; } - + /* First of all we write grain itself, to avoid race condition + * that may to corrupt the image. + * This problem may occur because of insufficient space on host disk + * or inappropriate VM shutdown. + */ if (get_whole_cluster(bs, cluster_offset, offset, allocate) == -1) return 0; + + if (m_data) { + m_data->offset = tmp; + m_data->l1_index = l1_index; + m_data->l2_index = l2_index; + m_data->l2_offset = l2_offset; + m_data->valid = 1; + } } cluster_offset <<= 9; return cluster_offset; } -static int vmdk_is_allocated(BlockDriverState *bs, int64_t sector_num, +static int vmdk_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum) { BDRVVmdkState *s = bs->opaque; int index_in_cluster, n; uint64_t cluster_offset; - cluster_offset = get_cluster_offset(bs, sector_num << 9, 0); + cluster_offset = get_cluster_offset(bs, NULL, sector_num << 9, 0); index_in_cluster = sector_num % s->cluster_sectors; n = s->cluster_sectors - index_in_cluster; if (n > nb_sectors) @@ -559,7 +620,7 @@ static int vmdk_is_allocated(BlockDriverState *bs, int64_t sector_num, return (cluster_offset != 0); } -static int vmdk_read(BlockDriverState *bs, int64_t sector_num, +static int vmdk_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors) { BDRVVmdkState *s = bs->opaque; @@ -567,7 +628,7 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num, uint64_t cluster_offset; while (nb_sectors > 0) { - cluster_offset = get_cluster_offset(bs, sector_num << 9, 0); + cluster_offset = get_cluster_offset(bs, NULL, sector_num << 9, 0); index_in_cluster = sector_num % s->cluster_sectors; n = s->cluster_sectors - index_in_cluster; if (n > nb_sectors) @@ -595,24 +656,39 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num, return 0; } -static int vmdk_write(BlockDriverState *bs, int64_t sector_num, +static int vmdk_write(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors) { BDRVVmdkState *s = bs->opaque; + VmdkMetaData m_data; int index_in_cluster, n; uint64_t cluster_offset; static int cid_update = 0; + if (sector_num > bs->total_sectors) { + fprintf(stderr, + "(VMDK) Wrong offset: sector_num=0x%" PRIx64 + " total_sectors=0x%" PRIx64 "\n", + sector_num, bs->total_sectors); + return -1; + } + while (nb_sectors > 0) { index_in_cluster = sector_num & (s->cluster_sectors - 1); n = s->cluster_sectors - index_in_cluster; if (n > nb_sectors) n = nb_sectors; - cluster_offset = get_cluster_offset(bs, sector_num << 9, 1); + cluster_offset = get_cluster_offset(bs, &m_data, sector_num << 9, 1); if (!cluster_offset) return -1; + if (bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512) return -1; + if (m_data.valid) { + /* update L2 tables */ + if (vmdk_L2update(bs, &m_data) == -1) + return -1; + } nb_sectors -= n; sector_num += n; buf += n * 512; @@ -646,7 +722,7 @@ static int vmdk_create(const char *filename, int64_t total_size, "# The Disk Data Base \n" "#DDB\n" "\n" - "ddb.virtualHWVersion = \"4\"\n" + "ddb.virtualHWVersion = \"%d\"\n" "ddb.geometry.cylinders = \"%lu\"\n" "ddb.geometry.heads = \"16\"\n" "ddb.geometry.sectors = \"63\"\n" @@ -695,8 +771,8 @@ static int vmdk_create(const char *filename, int64_t total_size, header.check_bytes[1] = 0x20; header.check_bytes[2] = 0xd; header.check_bytes[3] = 0xa; - - /* write all the data */ + + /* write all the data */ write(fd, &magic, sizeof(magic)); write(fd, &header, sizeof(header)); @@ -707,7 +783,7 @@ static int vmdk_create(const char *filename, int64_t total_size, for (i = 0, tmp = header.rgd_offset + gd_size; i < gt_count; i++, tmp += gt_size) write(fd, &tmp, sizeof(tmp)); - + /* write backup grain directory */ lseek(fd, le64_to_cpu(header.gd_offset) << 9, SEEK_SET); for (i = 0, tmp = header.gd_offset + gd_size; @@ -723,7 +799,7 @@ static int vmdk_create(const char *filename, int64_t total_size, if ((temp_str = strrchr(real_filename, ':')) != NULL) real_filename = temp_str + 1; sprintf(desc, desc_template, time(NULL), (unsigned long)total_size, - real_filename, total_size / (63 * 16)); + real_filename, (flags & BLOCK_FLAG_COMPAT6 ? 6 : 4), total_size / (63 * 16)); /* write the descriptor */ lseek(fd, le64_to_cpu(header.desc_offset) << 9, SEEK_SET); |