Block patches
The following changes since commit b55c952aea6de024bf1a06357b49367fba045443:
Merge remote-tracking branch 'aneesh/for-upstream' into staging (2012-02-27 11:19:27 -0600)
are available in the git repository at:
git://repo.or.cz/qemu/kevin.git for-anthony
Hervé Poussineau (10):
fdc: take side count into account
fdc: set busy bit when starting a command
fdc: most control commands do not generate interrupts
fdc: handle read-only floppies (abort early on write commands)
fdc: add CCR (Configuration Control Register) write register
block: add a transfer rate for floppy types
fdc: add a 'check media rate' property. Not used yet
fdc: check if media rate is correct before doing any transfer
fdc: fix seek command, which shouldn't check tracks
fdc: DIR (Digital Input Register) should return status of current drive...
Jeff Cody (2):
qapi: Introduce blockdev-group-snapshot-sync command
QMP: Add qmp command for blockdev-group-snapshot-sync
Kevin Wolf (6):
qcow2: Fix build with DEBUG_EXT enabled
qcow2: Fix offset in qcow2_read_extensions
qcow2: Reject too large header extensions
qemu-iotests: Filter out DOS line endings
qemu-iotests: 026: Reduce output changes for cache=none qcow2
qemu-iotests: Test rebase with short backing file
Paolo Bonzini (3):
ide: fail I/O to empty disk
block: remove unused fields in BlockDriverState
block: drop aio_multiwrite in BlockDriver
Stefan Hajnoczi (4):
qemu-iotests: export TEST_DIR for non-bash tests
qemu-iotests: add iotests Python module
test: add image streaming tests
qemu-tool: revert cpu_get_clock() abort(3)
Zhi Yong Wu (2):
qemu-io: fix segment fault when the image format is qed
qemu-img: fix segment fault when the image format is qed
block.c | 178 ++++++++++++++++++++++++++------------ block.h | 11 ++- block/qcow2.c | 11 ++- block_int.h | 17 ++--- blockdev.c | 131 ++++++++++++++++++++++++++++ hw/fdc.c | 142 ++++++++++++++++++++++++------ hw/ide/core.c | 24 ++++- hw/pc.c | 3 +- hw/pc_piix.c | 28 ++++++ qapi-schema.json | 38 ++++++++ qemu-img.c | 2 + qemu-io.c | 2 + qemu-tool.c | 2 +- qmp-commands.hx | 39 ++++++++ tests/qemu-iotests/026 | 6 ++ tests/qemu-iotests/028 | 5 + tests/qemu-iotests/028.out | 1 + tests/qemu-iotests/030 | 151 ++++++++++++++++++++++++++++++++ tests/qemu-iotests/030.out | 5 + tests/qemu-iotests/check | 4 +- tests/qemu-iotests/common.config | 2 + tests/qemu-iotests/common.filter | 8 ++- tests/qemu-iotests/group | 1 + tests/qemu-iotests/iotests.py | 164 +++++++++++++++++++++++++++++++++++ 24 files changed, 868 insertions(+), 107 deletions(-) create mode 100755 tests/qemu-iotests/030 create mode 100644 tests/qemu-iotests/030.out create mode 100644 tests/qemu-iotests/iotests.py
PATCH 1/27 fdc: take side count into account
From: Hervé Poussineau <[email protected]>
Floppies can be simple or double-sided. However, current code was only taking the common case into account (ie 2 sides).
This repairs single-sided floppies, which where totally broken before this patch : for track > 0, wrong sector number was calculated, and data was read/written at wrong place on underlying device.
Fortunately, only some 360 kB floppies are single-sided, so this bug was probably not seen much.
--- hw/fdc.c | 17 +++++++++++------ 1 files changed, 11 insertions(+), 6 deletions(-)
hw/fdc.c +11 -6
@@ -95,16 +95,19 @@ static void fd_init(FDrive *drv) drv->max_track =0 ; } +#define NUM_SIDES (drv) ((drv)->flags & FDISK_DBL_SIDES ? 2 : 1) +static int fd_sector_calc (uint8_t head,uint8_t track,uint8_t sect, -uint8_t last_sect) +uint8_t last_sect,uint8_t num_sides) { -return (((track *2 ) + head) * last_sect) + sect -1 ; +return (((track * num_sides) + head) * last_sect) + sect -1 ; }/* Returns current position, in sectors, for given drive */ static int fd_sector (FDrive *drv) { -return fd_sector_calc (drv->head, drv->track, drv->sect, drv->last_sect); +return fd_sector_calc (drv->head, drv->track, drv->sect, drv->last_sect, +NUM_SIDES (drv)); }/* Seek to a new position:
@@ -135,7 +138,7 @@ static int fd_seek(FDrive *drv, uint8_t head, uint8_t track, uint8_t sect, drv->max_track, drv->last_sect);return 3 ; } - sector =fd_sector_calc (head, track, sect, drv->last_sect); + sector =fd_sector_calc (head, track, sect, drv->last_sect,NUM_SIDES (drv)); ret =0 ;if (sector !=fd_sector (drv)) {#if 0
@@ -1019,7 +1022,8 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction) ks = fdctrl->fifo[4 ];FLOPPY_DPRINTF ("Start transfer at %d %d %02x %02x (%d)\n" ,GET_CUR_DRV (fdctrl), kh, kt, ks, -fd_sector_calc (kh, kt, ks, cur_drv->last_sect)); +fd_sector_calc (kh, kt, ks, cur_drv->last_sect, +NUM_SIDES (cur_drv)));switch (fd_seek (cur_drv, kh, kt, ks, fdctrl->config &FD_CONFIG_EIS )) {case 2 :/* sect too big */
@@ -1289,7 +1293,8 @@ static void fdctrl_format_sector(FDCtrl *fdctrl) ks = fdctrl->fifo[8 ];FLOPPY_DPRINTF ("format sector at %d %d %02x %02x (%d)\n" ,GET_CUR_DRV (fdctrl), kh, kt, ks, -fd_sector_calc (kh, kt, ks, cur_drv->last_sect)); +fd_sector_calc (kh, kt, ks, cur_drv->last_sect, +NUM_SIDES (cur_drv)));switch (fd_seek (cur_drv, kh, kt, ks, fdctrl->config &FD_CONFIG_EIS )) {case 2 :/* sect too big */
Signature · 1 line
1.7.6.5
PATCH 2/27 fdc: set busy bit when starting a command
In reply to Kevin WolfFrom: Hervé Poussineau <[email protected]>
This bit must be active while a command is currently executed.
--- hw/fdc.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
hw/fdc.c +1 -1
@@ -1446,7 +1446,6 @@ static void fdctrl_handle_readid(FDCtrl *fdctrl, int direction) {FDrive *cur_drv =get_cur_drv (fdctrl); -/* XXX: should set main status register to busy */ cur_drv->head = (fdctrl->fifo[1 ] >>2 ) &1 ;qemu_mod_timer (fdctrl->result_timer,qemu_get_clock_ns (vm_clock) + (get_ticks_per_sec () /50 ));
@@ -1734,6 +1733,7 @@ static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value) pos = command_to_handler[value &0xff ];FLOPPY_DPRINTF ("%s command\n" , handlers[pos].name); fdctrl->data_len = handlers[pos].parameters +1 ; + fdctrl->msr |=FD_MSR_CMDBUSY ; }FLOPPY_DPRINTF ("%s: %02x\n" , __func__, value);
Signature · 1 line
1.7.6.5
PATCH 3/27 fdc: most control commands do not generate interrupts
In reply to Kevin WolfFrom: Hervé Poussineau <[email protected]>
In fact, only three control commands generate an interrupt:read_id, recalibrate and seek
--- hw/fdc.c | 12 ++++++------ 1 files changed, 6 insertions(+), 6 deletions(-)
hw/fdc.c +6 -6
@@ -1348,7 +1348,7 @@ static void fdctrl_handle_lock(FDCtrl *fdctrl, int direction) { fdctrl->lock = (fdctrl->fifo[0 ] &0x80 ) ?1 :0 ; fdctrl->fifo[0 ] = fdctrl->lock <<4 ; -fdctrl_set_fifo (fdctrl,1 , fdctrl->lock); +fdctrl_set_fifo (fdctrl,1 ,0 ); }static void fdctrl_handle_dumpreg (FDCtrl *fdctrl,int direction)
@@ -1380,7 +1380,7 @@ static void fdctrl_handle_version(FDCtrl *fdctrl, int direction) {/* Controller's version */ fdctrl->fifo[0 ] = fdctrl->version; -fdctrl_set_fifo (fdctrl,1 ,1 ); +fdctrl_set_fifo (fdctrl,1 ,0 ); }static void fdctrl_handle_partid (FDCtrl *fdctrl,int direction)
@@ -1439,7 +1439,7 @@ static void fdctrl_handle_save(FDCtrl *fdctrl, int direction) fdctrl->fifo[12 ] = fdctrl->pwrd; fdctrl->fifo[13 ] =0 ; fdctrl->fifo[14 ] =0 ; -fdctrl_set_fifo (fdctrl,15 ,1 ); +fdctrl_set_fifo (fdctrl,15 ,0 ); }static void fdctrl_handle_readid (FDCtrl *fdctrl,int direction)
@@ -1580,7 +1580,7 @@ static void fdctrl_handle_powerdown_mode(FDCtrl *fdctrl, int direction) { fdctrl->pwrd = fdctrl->fifo[1 ]; fdctrl->fifo[0 ] = fdctrl->fifo[1 ]; -fdctrl_set_fifo (fdctrl,1 ,1 ); +fdctrl_set_fifo (fdctrl,1 ,0 ); }static void fdctrl_handle_option (FDCtrl *fdctrl,int direction)
@@ -1599,7 +1599,7 @@ static void fdctrl_handle_drive_specification_command(FDCtrl *fdctrl, int direct fdctrl->fifo[0 ] = fdctrl->fifo[1 ]; fdctrl->fifo[2 ] =0 ; fdctrl->fifo[3 ] =0 ; -fdctrl_set_fifo (fdctrl,4 ,1 ); +fdctrl_set_fifo (fdctrl,4 ,0 ); }else {fdctrl_reset_fifo (fdctrl); }
@@ -1607,7 +1607,7 @@ static void fdctrl_handle_drive_specification_command(FDCtrl *fdctrl, int direct/* ERROR */ fdctrl->fifo[0 ] =0x80 | (cur_drv->head <<2 ) |GET_CUR_DRV (fdctrl); -fdctrl_set_fifo (fdctrl,1 ,1 ); +fdctrl_set_fifo (fdctrl,1 ,0 ); } }
Signature · 1 line
1.7.6.5
PATCH 4/27 fdc: handle read-only floppies (abort early on write commands)
In reply to Kevin WolfFrom: Hervé Poussineau <[email protected]>
A real floppy doesn't attempt to write to read-only media either.
--- hw/fdc.c | 11 +++++++++++ 1 files changed, 11 insertions(+), 0 deletions(-)
hw/fdc.c +11 -0
@@ -300,6 +300,7 @@ enum { };enum { +FD_SR1_NW =0x02 ,/* Not writable */ FD_SR1_EC =0x80 ,/* End of cylinder */ };
@@ -1179,6 +1180,16 @@ static int fdctrl_transfer_handler (void *opaque, int nchan,break ;case FD_DIR_WRITE :/* WRITE commands */ +if (cur_drv->ro) { +/* Handle readonly medium early, no need to do DMA, touch the +* LED or attempt any writes. A real floppy doesn't attempt +* to write to readonly media either. */ +fdctrl_stop_transfer (fdctrl, +FD_SR0_ABNTERM |FD_SR0_SEEK ,FD_SR1_NW , +0x00 ); + goto transfer_error; + } +DMA_read_memory (nchan, fdctrl->fifo + rel_pos, fdctrl->data_pos, len); if (bdrv_write(cur_drv->bs, fd_sector(cur_drv),
Signature · 1 line
1.7.6.5
PATCH 5/27 fdc: add CCR (Configuration Control Register) write register
In reply to Kevin WolfFrom: Hervé Poussineau <[email protected]>
DIR and CCR registers share the same address ; DIR is read-only while CCR is write-only
CCR register is used to change media transfer rate, which will be checked in following changes.
--- hw/fdc.c | 22 ++++++++++++++++++++++ 1 files changed, 22 insertions(+), 0 deletions(-)
hw/fdc.c +22 -0
@@ -224,6 +224,7 @@ static void fdctrl_write_rate(FDCtrl *fdctrl, uint32_t value);static uint32_t fdctrl_read_data (FDCtrl *fdctrl);static void fdctrl_write_data (FDCtrl *fdctrl,uint32_t value);static uint32_t fdctrl_read_dir (FDCtrl *fdctrl); +static void fdctrl_write_ccr (FDCtrl *fdctrl,uint32_t value);enum {FD_DIR_WRITE =0 ,
@@ -248,6 +249,7 @@ enum {FD_REG_DSR =0x04 ,FD_REG_FIFO =0x05 ,FD_REG_DIR =0x07 , + FD_REG_CCR = 0x07, }; enum {
@@ -491,6 +493,9 @@ static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value)case FD_REG_FIFO :fdctrl_write_data (fdctrl, value);break ; +case FD_REG_CCR : +fdctrl_write_ccr (fdctrl, value); +break ;default :break ; }
@@ -881,6 +886,23 @@ static void fdctrl_write_rate(FDCtrl *fdctrl, uint32_t value) fdctrl->dsr = value; } +/* Configuration control register: 0x07 (write) */ +static void fdctrl_write_ccr (FDCtrl *fdctrl,uint32_t value) +{ +/* Reset mode */ +if (!(fdctrl->dor & FD_DOR_nRESET)) { +FLOPPY_DPRINTF ("Floppy controller in RESET state !\n" ); +return ; + } +FLOPPY_DPRINTF ("configuration control register set to 0x%02x\n" , value); + +/* Only the rate selection bits used in AT mode, and we +* store those in the DSR. +*/ + fdctrl->dsr = (fdctrl->dsr & ~FD_DSR_DRATEMASK ) | + (value &FD_DSR_DRATEMASK ); +} +static int fdctrl_media_changed (FDrive *drv) {int ret;
Signature · 1 line
1.7.6.5
PATCH 6/27 block: add a transfer rate for floppy types
In reply to Kevin WolfFrom: Hervé Poussineau <[email protected]>
Floppies must be read at a specific transfer rate, depending of its own format. Update floppy description table to include required transfer rate.
--- block.c | 74 ++++++++++++++++++++++++++++++++----------------------------- block.h | 10 +++++++- hw/fdc.c | 3 +- hw/pc.c | 3 +- 4 files changed, 52 insertions(+), 38 deletions(-)
block.c +39 -35
@@ -2013,58 +2013,60 @@ typedef struct FDFormat {uint8_t last_sect;uint8_t max_track;uint8_t max_head; +FDriveRate rate; } FDFormat;static const FDFormat fd_formats[] = {/* First entry is default format */ /* 1.44 MB 3"1/2 floppy disks */ - {FDRIVE_DRV_144 ,18 ,80 ,1 , }, - {FDRIVE_DRV_144 ,20 ,80 ,1 , }, - {FDRIVE_DRV_144 ,21 ,80 ,1 , }, - {FDRIVE_DRV_144 ,21 ,82 ,1 , }, - {FDRIVE_DRV_144 ,21 ,83 ,1 , }, - {FDRIVE_DRV_144 ,22 ,80 ,1 , }, - {FDRIVE_DRV_144 ,23 ,80 ,1 , }, - {FDRIVE_DRV_144 ,24 ,80 ,1 , }, + {FDRIVE_DRV_144 ,18 ,80 ,1 ,FDRIVE_RATE_500K , }, + {FDRIVE_DRV_144 ,20 ,80 ,1 ,FDRIVE_RATE_500K , }, + {FDRIVE_DRV_144 ,21 ,80 ,1 ,FDRIVE_RATE_500K , }, + {FDRIVE_DRV_144 ,21 ,82 ,1 ,FDRIVE_RATE_500K , }, + {FDRIVE_DRV_144 ,21 ,83 ,1 ,FDRIVE_RATE_500K , }, + {FDRIVE_DRV_144 ,22 ,80 ,1 ,FDRIVE_RATE_500K , }, + {FDRIVE_DRV_144 ,23 ,80 ,1 ,FDRIVE_RATE_500K , }, + {FDRIVE_DRV_144 ,24 ,80 ,1 ,FDRIVE_RATE_500K , },/* 2.88 MB 3"1/2 floppy disks */ - {FDRIVE_DRV_288 ,36 ,80 ,1 , }, - {FDRIVE_DRV_288 ,39 ,80 ,1 , }, - {FDRIVE_DRV_288 ,40 ,80 ,1 , }, - {FDRIVE_DRV_288 ,44 ,80 ,1 , }, - {FDRIVE_DRV_288 ,48 ,80 ,1 , }, + {FDRIVE_DRV_288 ,36 ,80 ,1 ,FDRIVE_RATE_1M , }, + {FDRIVE_DRV_288 ,39 ,80 ,1 ,FDRIVE_RATE_1M , }, + {FDRIVE_DRV_288 ,40 ,80 ,1 ,FDRIVE_RATE_1M , }, + {FDRIVE_DRV_288 ,44 ,80 ,1 ,FDRIVE_RATE_1M , }, + {FDRIVE_DRV_288 ,48 ,80 ,1 ,FDRIVE_RATE_1M , },/* 720 kB 3"1/2 floppy disks */ - {FDRIVE_DRV_144 ,9 ,80 ,1 , }, - {FDRIVE_DRV_144 ,10 ,80 ,1 , }, - {FDRIVE_DRV_144 ,10 ,82 ,1 , }, - {FDRIVE_DRV_144 ,10 ,83 ,1 , }, - {FDRIVE_DRV_144 ,13 ,80 ,1 , }, - {FDRIVE_DRV_144 ,14 ,80 ,1 , }, + {FDRIVE_DRV_144 ,9 ,80 ,1 ,FDRIVE_RATE_250K , }, + {FDRIVE_DRV_144 ,10 ,80 ,1 ,FDRIVE_RATE_250K , }, + {FDRIVE_DRV_144 ,10 ,82 ,1 ,FDRIVE_RATE_250K , }, + {FDRIVE_DRV_144 ,10 ,83 ,1 ,FDRIVE_RATE_250K , }, + {FDRIVE_DRV_144 ,13 ,80 ,1 ,FDRIVE_RATE_250K , }, + {FDRIVE_DRV_144 ,14 ,80 ,1 ,FDRIVE_RATE_250K , },/* 1.2 MB 5"1/4 floppy disks */ - {FDRIVE_DRV_120 ,15 ,80 ,1 , }, - {FDRIVE_DRV_120 ,18 ,80 ,1 , }, - {FDRIVE_DRV_120 ,18 ,82 ,1 , }, - {FDRIVE_DRV_120 ,18 ,83 ,1 , }, - {FDRIVE_DRV_120 ,20 ,80 ,1 , }, + {FDRIVE_DRV_120 ,15 ,80 ,1 ,FDRIVE_RATE_500K , }, + {FDRIVE_DRV_120 ,18 ,80 ,1 ,FDRIVE_RATE_500K , }, + {FDRIVE_DRV_120 ,18 ,82 ,1 ,FDRIVE_RATE_500K , }, + {FDRIVE_DRV_120 ,18 ,83 ,1 ,FDRIVE_RATE_500K , }, + {FDRIVE_DRV_120 ,20 ,80 ,1 ,FDRIVE_RATE_500K , },/* 720 kB 5"1/4 floppy disks */ - {FDRIVE_DRV_120 ,9 ,80 ,1 , }, - {FDRIVE_DRV_120 ,11 ,80 ,1 , }, + {FDRIVE_DRV_120 ,9 ,80 ,1 ,FDRIVE_RATE_250K , }, + {FDRIVE_DRV_120 ,11 ,80 ,1 ,FDRIVE_RATE_250K , },/* 360 kB 5"1/4 floppy disks */ - {FDRIVE_DRV_120 ,9 ,40 ,1 , }, - {FDRIVE_DRV_120 ,9 ,40 ,0 , }, - {FDRIVE_DRV_120 ,10 ,41 ,1 , }, - {FDRIVE_DRV_120 ,10 ,42 ,1 , }, + {FDRIVE_DRV_120 ,9 ,40 ,1 ,FDRIVE_RATE_300K , }, + {FDRIVE_DRV_120 ,9 ,40 ,0 ,FDRIVE_RATE_300K , }, + {FDRIVE_DRV_120 ,10 ,41 ,1 ,FDRIVE_RATE_300K , }, + {FDRIVE_DRV_120 ,10 ,42 ,1 ,FDRIVE_RATE_300K , },/* 320 kB 5"1/4 floppy disks */ - {FDRIVE_DRV_120 ,8 ,40 ,1 , }, - {FDRIVE_DRV_120 ,8 ,40 ,0 , }, + {FDRIVE_DRV_120 ,8 ,40 ,1 ,FDRIVE_RATE_250K , }, + {FDRIVE_DRV_120 ,8 ,40 ,0 ,FDRIVE_RATE_250K , },/* 360 kB must match 5"1/4 better than 3"1/2... */ - {FDRIVE_DRV_144 ,9 ,80 ,0 , }, + {FDRIVE_DRV_144 ,9 ,80 ,0 ,FDRIVE_RATE_250K , },/* end */ - {FDRIVE_DRV_NONE ,-1 ,-1 ,0 , }, + {FDRIVE_DRV_NONE ,-1 ,-1 ,0 ,0 , }, };void bdrv_get_floppy_geometry_hint (BlockDriverState *bs,int *nb_heads,int *max_track,int *last_sect, -FDriveType drive_in,FDriveType *drive) +FDriveType drive_in,FDriveType *drive, +FDriveRate *rate) {const FDFormat *parse;uint64_t nb_sectors, size;
@@ -2073,6 +2075,7 @@ void bdrv_get_floppy_geometry_hint(BlockDriverState *bs, int *nb_heads,bdrv_get_geometry_hint (bs, nb_heads, max_track, last_sect);if (*nb_heads !=0 && *max_track !=0 && *last_sect !=0 ) {/* User defined disk */ + *rate =FDRIVE_RATE_500K ; }else {bdrv_get_geometry (bs, &nb_sectors); match =-1 ;
@@ -2107,6 +2110,7 @@ void bdrv_get_floppy_geometry_hint(BlockDriverState *bs, int *nb_heads, *max_track = parse->max_track; *last_sect = parse->last_sect; *drive = parse->drive; + *rate = parse->rate; } }
block.h +9 -1
@@ -252,9 +252,17 @@ typedef enum FDriveType {FDRIVE_DRV_NONE =0x03 ,/* No drive connected */ } FDriveType; +typedef enum FDriveRate { +FDRIVE_RATE_500K =0x00 ,/* 500 Kbps */ +FDRIVE_RATE_300K =0x01 ,/* 300 Kbps */ +FDRIVE_RATE_250K =0x02 ,/* 250 Kbps */ +FDRIVE_RATE_1M =0x03 ,/* 1 Mbps */ +}FDriveRate ; +void bdrv_get_floppy_geometry_hint (BlockDriverState *bs,int *nb_heads,int *max_track,int *last_sect, -FDriveType drive_in,FDriveType *drive); +FDriveType drive_in,FDriveType *drive, +FDriveRate *rate);int bdrv_get_translation_hint (BlockDriverState *bs);void bdrv_set_on_error (BlockDriverState *bs,BlockErrorAction on_read_error,BlockErrorAction on_write_error);
hw/fdc.c +2 -1
@@ -172,12 +172,13 @@ static void fd_revalidate(FDrive *drv) {int nb_heads, max_track, last_sect, ro;FDriveType drive; +FDriveRate rate;FLOPPY_DPRINTF ("revalidate\n" );if (drv->bs !=NULL &&bdrv_is_inserted (drv->bs)) { ro =bdrv_is_read_only (drv->bs);bdrv_get_floppy_geometry_hint (drv->bs, &nb_heads, &max_track, - &last_sect, drv->drive, &drive); + &last_sect, drv->drive, &drive, &rate);if (nb_heads !=0 && max_track !=0 && last_sect !=0 ) {FLOPPY_DPRINTF ("User defined disk (%d %d %d)" , nb_heads -1 , max_track, last_sect);
hw/pc.c +2 -1
@@ -335,6 +335,7 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size, {int val, nb, nb_heads, max_track, last_sect, i;FDriveType fd_type[2 ] = {FDRIVE_DRV_NONE ,FDRIVE_DRV_NONE }; +FDriveRate rate;BlockDriverState *fd[MAX_FD ];static pc_cmos_init_late_arg arg;
@@ -383,7 +384,7 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,if (fd[i] &&bdrv_is_inserted (fd[i])) {bdrv_get_floppy_geometry_hint (fd[i], &nb_heads, &max_track, &last_sect,FDRIVE_DRV_NONE , - &fd_type[i]); + &fd_type[i], &rate); } } }
Signature · 1 line
1.7.6.5
PATCH 7/27 fdc: add a 'check media rate' property. Not used yet
In reply to Kevin WolfFrom: Hervé Poussineau <[email protected]>
Set it to true for current Qemu versions, and false for previous ones
--- hw/fdc.c | 3 +++ hw/pc_piix.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 0 deletions(-)
hw/fdc.c +3 -0
@@ -420,6 +420,7 @@ struct FDCtrl {int sun4m;FDrive drives[MAX_FD ];int reset_sensei; +uint32_t check_media_rate;/* Timers state */ uint8_t timer0;uint8_t timer1;
@@ -2003,6 +2004,8 @@ static Property isa_fdc_properties[] = {DEFINE_PROP_DRIVE ("driveB" , FDCtrlISABus, state.drives[1 ].bs),DEFINE_PROP_INT32 ("bootindexA" , FDCtrlISABus, bootindexA,-1 ),DEFINE_PROP_INT32 ("bootindexB" , FDCtrlISABus, bootindexB,-1 ), +DEFINE_PROP_BIT ("check_media_rate" , FDCtrlISABus, state.check_media_rate, +0 , true), DEFINE_PROP_END_OF_LIST(), };
hw/pc_piix.c +28 -0
@@ -384,6 +384,10 @@ static QEMUMachine pc_machine_v1_0 = { .driver = "pc-sysfw", .property = "rom_only", .value = stringify(1), + }, { + .driver = "isa-fdc", + .property = "check_media_rate", + .value = "off", }, {/* end of list */ } },
@@ -399,6 +403,10 @@ static QEMUMachine pc_machine_v0_15 = { .driver = "pc-sysfw", .property = "rom_only", .value = stringify(1), + }, { + .driver = "isa-fdc", + .property = "check_media_rate", + .value = "off", }, {/* end of list */ } },
@@ -434,6 +442,10 @@ static QEMUMachine pc_machine_v0_14 = { .driver = "virtio-balloon-pci", .property = "event_idx", .value = "off", + },{ + .driver = "isa-fdc", + .property = "check_media_rate", + .value = "off", }, { .driver = "pc-sysfw",
@@ -486,6 +498,10 @@ static QEMUMachine pc_machine_v0_13 = { .driver = "AC97", .property = "use_broken_id", .value = stringify(1), + },{ + .driver = "isa-fdc", + .property = "check_media_rate", + .value = "off", }, { .driver = "pc-sysfw",
@@ -542,6 +558,10 @@ static QEMUMachine pc_machine_v0_12 = { .driver = "AC97", .property = "use_broken_id", .value = stringify(1), + },{ + .driver = "isa-fdc", + .property = "check_media_rate", + .value = "off", }, { .driver = "pc-sysfw",
@@ -606,6 +626,10 @@ static QEMUMachine pc_machine_v0_11 = { .driver = "AC97", .property = "use_broken_id", .value = stringify(1), + },{ + .driver = "isa-fdc", + .property = "check_media_rate", + .value = "off", }, { .driver = "pc-sysfw",
@@ -682,6 +706,10 @@ static QEMUMachine pc_machine_v0_10 = { .driver = "AC97", .property = "use_broken_id", .value = stringify(1), + },{ + .driver = "isa-fdc", + .property = "check_media_rate", + .value = "off", }, { .driver = "pc-sysfw",
Signature · 1 line
1.7.6.5
PATCH 8/27 fdc: check if media rate is correct before doing any transfer
In reply to Kevin WolfFrom: Hervé Poussineau <[email protected]>
The programmed rate has to be the same as the required rate for the floppy format ; if that's not the case, the transfer should abort. This check can be disabled by using the 'check_media_rate' property.
Save media rate value only if media rate check is enabled.
--- hw/fdc.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 files changed, 50 insertions(+), 3 deletions(-)
hw/fdc.c +50 -3
@@ -62,12 +62,15 @@#define FD_SECTOR_SC 2/* Sector size code */ #define FD_RESET_SENSEI_COUNT 4/* Number of sense interrupts on RESET */ +typedef struct FDCtrl FDCtrl ; +/* Floppy disk drive emulation */ typedef enum FDiskFlags {FDISK_DBL_SIDES =0x01 , }FDiskFlags ; typedef struct FDrive { + FDCtrl *fdctrl; BlockDriverState *bs; /* Drive status */ FDriveType drive;
@@ -83,6 +86,7 @@ typedef struct FDrive {uint16_t bps;/* Bytes per sector */ uint8_t ro;/* Is read-only */ uint8_t media_changed;/* Is media changed */ +uint8_t media_rate;/* Data rate of medium */ } FDrive;static void fd_init (FDrive *drv)
@@ -195,6 +199,7 @@ static void fd_revalidate(FDrive *drv) drv->last_sect = last_sect; drv->ro = ro; drv->drive = drive; + drv->media_rate = rate; }else {FLOPPY_DPRINTF ("No disk in drive\n" ); drv->last_sect =0 ;
@@ -206,8 +211,6 @@ static void fd_revalidate(FDrive *drv)/********************************************************/ /* Intel 82078 floppy disk controller emulation */ -typedef struct FDCtrl FDCtrl ; -static void fdctrl_reset (FDCtrl *fdctrl,int do_irq);static void fdctrl_reset_fifo (FDCtrl *fdctrl); static int fdctrl_transfer_handler (void *opaque, int nchan,
@@ -303,6 +306,7 @@ enum { };enum { +FD_SR1_MA =0x01 ,/* Missing address mark */ FD_SR1_NW =0x02 ,/* Not writable */ FD_SR1_EC =0x80 ,/* End of cylinder */ };
@@ -549,6 +553,24 @@ static const VMStateDescription vmstate_fdrive_media_changed = { } }; +static bool fdrive_media_rate_needed (void *opaque) +{ +FDrive *drive = opaque; + +return drive->fdctrl->check_media_rate; +} + +static const VMStateDescription vmstate_fdrive_media_rate = { + .name ="fdrive/media_rate" , + .version_id =1 , + .minimum_version_id =1 , + .minimum_version_id_old =1 , + .fields = (VMStateField []) { +VMSTATE_UINT8 (media_rate, FDrive), +VMSTATE_END_OF_LIST () + } +}; +static const VMStateDescription vmstate_fdrive = { .name ="fdrive" , .version_id =1 ,
@@ -565,6 +587,9 @@ static const VMStateDescription vmstate_fdrive = { .vmsd = &vmstate_fdrive_media_changed, .needed = &fdrive_media_changed_needed, } , { + .vmsd = &vmstate_fdrive_media_rate, + .needed = &fdrive_media_rate_needed, + } , {/* empty */ } }
@@ -1078,6 +1103,19 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction)break ; } +/* Check the data rate. If the programmed data rate does not match +* the currently inserted medium, the operation has to fail. */ +if (fdctrl->check_media_rate && + (fdctrl->dsr &FD_DSR_DRATEMASK ) != cur_drv->media_rate) { +FLOPPY_DPRINTF ("data rate mismatch (fdc=%d, media=%d)\n" , + fdctrl->dsr &FD_DSR_DRATEMASK , cur_drv->media_rate); +fdctrl_stop_transfer (fdctrl,FD_SR0_ABNTERM ,FD_SR1_MA ,0x00 ); + fdctrl->fifo[3 ] = kt; + fdctrl->fifo[4 ] = kh; + fdctrl->fifo[5 ] = ks; +return ; + } +/* Set the FIFO state */ fdctrl->data_dir = direction; fdctrl->data_pos =0 ;
@@ -1800,7 +1838,15 @@ static void fdctrl_result_timer(void *opaque)if (cur_drv->last_sect !=0 ) { cur_drv->sect = (cur_drv->sect % cur_drv->last_sect) +1 ; } -fdctrl_stop_transfer (fdctrl,0x00 ,0x00 ,0x00 ); +/* READ_ID can't automatically succeed! */ +if (fdctrl->check_media_rate && + (fdctrl->dsr &FD_DSR_DRATEMASK ) != cur_drv->media_rate) { +FLOPPY_DPRINTF ("read id rate mismatch (fdc=%d, media=%d)\n" , + fdctrl->dsr &FD_DSR_DRATEMASK , cur_drv->media_rate); +fdctrl_stop_transfer (fdctrl,FD_SR0_ABNTERM ,FD_SR1_MA ,0x00 ); + }else { +fdctrl_stop_transfer (fdctrl,0x00 ,0x00 ,0x00 ); + } }static void fdctrl_change_cb (void *opaque,bool load)
@@ -1822,6 +1868,7 @@ static int fdctrl_connect_drives(FDCtrl *fdctrl)for (i =0 ; i <MAX_FD ; i++) { drive = &fdctrl->drives[i]; + drive->fdctrl = fdctrl;if (drive->bs) {if (bdrv_get_on_error (drive->bs,0 ) !=BLOCK_ERR_STOP_ENOSPC ) {
Signature · 1 line
1.7.6.5
PATCH 9/27 fdc: fix seek command, which shouldn't check tracks
In reply to Kevin WolfFrom: Hervé Poussineau <[email protected]>
The seek command just sends step pulses to the drive and doesn't care if there is a medium inserted of if it is banging the head against the drive.
--- hw/fdc.c | 9 ++++++--- 1 files changed, 6 insertions(+), 3 deletions(-)
hw/fdc.c +6 -3
@@ -1622,13 +1622,16 @@ static void fdctrl_handle_seek(FDCtrl *fdctrl, int direction)SET_CUR_DRV (fdctrl, fdctrl->fifo[1 ] &FD_DOR_SELMASK ); cur_drv =get_cur_drv (fdctrl);fdctrl_reset_fifo (fdctrl); +/* The seek command just sends step pulses to the drive and doesn't care if +* there is a medium inserted of if it's banging the head against the drive. +*/ if (fdctrl->fifo[2 ] > cur_drv->max_track) { -fdctrl_raise_irq (fdctrl,FD_SR0_ABNTERM |FD_SR0_SEEK ); + cur_drv->track = cur_drv->max_track; }else { cur_drv->track = fdctrl->fifo[2 ]; -/* Raise Interrupt */ -fdctrl_raise_irq (fdctrl,FD_SR0_SEEK ); } +/* Raise Interrupt */ +fdctrl_raise_irq (fdctrl,FD_SR0_SEEK ); }static void fdctrl_handle_perpendicular_mode (FDCtrl *fdctrl,int direction)
Signature · 1 line
1.7.6.5
PATCH 10/27 fdc: DIR (Digital Input Register) should return status of current drive...
In reply to Kevin WolfFrom: Hervé Poussineau <[email protected]>
--- hw/fdc.c | 10 +++------- 1 files changed, 3 insertions(+), 7 deletions(-)
hw/fdc.c +3 -7
@@ -216,6 +216,7 @@ static void fdctrl_reset_fifo(FDCtrl *fdctrl);static int fdctrl_transfer_handler (void *opaque,int nchan,int dma_pos,int dma_len);static void fdctrl_raise_irq (FDCtrl *fdctrl,uint8_t status0); +static FDrive *get_cur_drv (FDCtrl *fdctrl);static uint32_t fdctrl_read_statusA (FDCtrl *fdctrl);static uint32_t fdctrl_read_statusB (FDCtrl *fdctrl);
@@ -956,14 +957,9 @@ static uint32_t fdctrl_read_dir(FDCtrl *fdctrl) {uint32_t retval =0 ; -if (fdctrl_media_changed (drv0 (fdctrl)) - ||fdctrl_media_changed (drv1 (fdctrl)) -#if MAX_FD == 4 - ||fdctrl_media_changed (drv2 (fdctrl)) - ||fdctrl_media_changed (drv3 (fdctrl)) -#endif - ) +if (fdctrl_media_changed (get_cur_drv (fdctrl))) { retval |=FD_DIR_DSKCHG ; + }if (retval !=0 ) {FLOPPY_DPRINTF ("Floppy digital input register: 0x%02x\n" , retval); }
Signature · 1 line
1.7.6.5
PATCH 11/27 ide: fail I/O to empty disk
In reply to Kevin WolfFrom: Paolo Bonzini <[email protected]>
Requesting a read or a write operation on an empty disk can lead to QEMU dumping core.
Also fix a few braces here and there.
--- hw/ide/core.c | 24 ++++++++++++++++++++---- 1 files changed, 20 insertions(+), 4 deletions(-)
hw/ide/core.c +20 -4
@@ -1068,6 +1068,9 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)ide_set_signature (s);/* odd, but ATA4 8.27.5.2 requires it */ goto abort_cmd; } +if (!s->bs) { + goto abort_cmd; + }ide_cmd_lba48_transform (s, lba48); s->req_nb_sectors =1 ;ide_sector_read (s);
@@ -1078,6 +1081,9 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)case WIN_WRITE_ONCE :case CFA_WRITE_SECT_WO_ERASE :case WIN_WRITE_VERIFY : +if (!s->bs) { + goto abort_cmd; + }ide_cmd_lba48_transform (s, lba48); s->error =0 ; s->status =SEEK_STAT |READY_STAT ;
@@ -1088,8 +1094,12 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)case WIN_MULTREAD_EXT : lba48 =1 ;case WIN_MULTREAD : -if (!s->mult_sectors) +if (!s->bs) { goto abort_cmd; + } +if (!s->mult_sectors) { + goto abort_cmd; + }ide_cmd_lba48_transform (s, lba48); s->req_nb_sectors = s->mult_sectors;ide_sector_read (s);
@@ -1098,8 +1108,12 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) lba48 =1 ;case WIN_MULTWRITE :case CFA_WRITE_MULTI_WO_ERASE : -if (!s->mult_sectors) +if (!s->bs) { goto abort_cmd; + } +if (!s->mult_sectors) { + goto abort_cmd; + }ide_cmd_lba48_transform (s, lba48); s->error =0 ; s->status =SEEK_STAT |READY_STAT ;
@@ -1114,8 +1128,9 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) lba48 =1 ;case WIN_READDMA :case WIN_READDMA_ONCE : -if (!s->bs) +if (!s->bs) { goto abort_cmd; + }ide_cmd_lba48_transform (s, lba48);ide_sector_start_dma (s,IDE_DMA_READ );break ;
@@ -1123,8 +1138,9 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) lba48 =1 ;case WIN_WRITEDMA :case WIN_WRITEDMA_ONCE : -if (!s->bs) +if (!s->bs) { goto abort_cmd; + }ide_cmd_lba48_transform (s, lba48);ide_sector_start_dma (s,IDE_DMA_WRITE ); s->media_changed =1 ;
Signature · 1 line
1.7.6.5
PATCH 12/27 qcow2: Fix build with DEBUG_EXT enabled
In reply to Kevin Wolf--- block/qcow2.c | 1 - 1 files changed, 0 insertions(+), 1 deletions(-)
block/qcow2.c +0 -1
@@ -89,7 +89,6 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,while (offset < end_offset) {#ifdef DEBUG_EXT -BDRVQcowState *s = bs->opaque;/* Sanity check */ if (offset > s->cluster_size)printf ("qcow2_read_extension: suspicious offset %lu\n" , offset);
Signature · 1 line
1.7.6.5
PATCH 13/27 block: remove unused fields in BlockDriverState
In reply to Kevin WolfFrom: Paolo Bonzini <[email protected]>
sync_aiocb is unused since commit ce1a14d (Dynamically allocate AIO Completion Blocks., 2006-08-07).
private is unused since commit 56a1493 (drive cleanup fixes., 2009-09-25).
--- block_int.h | 5 ----- 1 files changed, 0 insertions(+), 5 deletions(-)
block_int.h +0 -5
@@ -259,10 +259,6 @@ struct BlockDriverState {/* number of in-flight copy-on-read requests */ unsigned int copy_on_read_in_flight; -/* async read/write emulation */ - -void *sync_aiocb; -/* the time for latest disk I/O */ int64_t slice_time;int64_t slice_start;
@@ -299,7 +295,6 @@ struct BlockDriverState {int64_t dirty_count;int in_use;/* users other than guest access, eg. block migration */ QTAILQ_ENTRY (BlockDriverState) list; -void *private; QLIST_HEAD(, BdrvTrackedRequest) tracked_requests;
Signature · 1 line
1.7.6.5
PATCH 14/27 block: drop aio_multiwrite in BlockDriver
In reply to Kevin WolfFrom: Paolo Bonzini <[email protected]>
These were never used.
--- block.c | 23 +++-------------------- block_int.h | 6 ------ 2 files changed, 3 insertions(+), 26 deletions(-)
block.c +3 -20
@@ -2791,7 +2791,6 @@ typedef struct MultiwriteCB {BlockDriverCompletionFunc *cb;void *opaque;QEMUIOVector *free_qiov; -void *free_buf; } callbacks[]; } MultiwriteCB;
@@ -2805,7 +2804,6 @@ static void multiwrite_user_cb(MultiwriteCB *mcb)qemu_iovec_destroy (mcb->callbacks[i].free_qiov); }g_free (mcb->callbacks[i].free_qiov); -qemu_vfree (mcb->callbacks[i].free_buf); } }
@@ -2862,20 +2860,11 @@ static int multiwrite_merge(BlockDriverState *bs, BlockRequest *reqs,int merge =0 ;int64_t oldreq_last = reqs[outidx].sector + reqs[outidx].nb_sectors; -// This handles the cases that are valid for all block drivers, namely -// exactly sequential writes and overlapping writes. +// Handle exactly sequential writes and overlapping writes. if (reqs[i].sector <= oldreq_last) { merge =1 ; } -// The block driver may decide that it makes sense to combine requests -// even if there is a gap of some sectors between them. In this case, -// the gap is filled with zeros (therefore only applicable for yet -// unused space in format like qcow2). -if (!merge && bs->drv->bdrv_merge_requests) { - merge = bs->drv->bdrv_merge_requests (bs, &reqs[outidx], &reqs[i]); - } -if (reqs[outidx].qiov->niov + reqs[i].qiov->niov +1 >IOV_MAX ) { merge =0 ; }
@@ -2891,14 +2880,8 @@ static int multiwrite_merge(BlockDriverState *bs, BlockRequest *reqs, size = (reqs[i].sector - reqs[outidx].sector) <<9 ;qemu_iovec_concat (qiov, reqs[outidx].qiov, size); -// We might need to add some zeros between the two requests -if (reqs[i].sector > oldreq_last) { -size_t zero_bytes = (reqs[i].sector - oldreq_last) <<9 ; -uint8_t *buf =qemu_blockalign (bs, zero_bytes); -memset (buf,0 , zero_bytes); -qemu_iovec_add (qiov, buf, zero_bytes); - mcb->callbacks[i].free_buf = buf; - } +// We should need to add any zeros between the two requests +assert (reqs[i].sector <= oldreq_last);// Add the second request qemu_iovec_concat (qiov, reqs[i].qiov, reqs[i].qiov->size);
block_int.h +0 -6
@@ -162,12 +162,6 @@ struct BlockDriver {*/ int coroutine_fn (*bdrv_co_flush_to_os)(BlockDriverState *bs); -int (*bdrv_aio_multiwrite)(BlockDriverState *bs,BlockRequest *reqs, -int num_reqs); -int (*bdrv_merge_requests)(BlockDriverState *bs,BlockRequest * a, -BlockRequest *b); - -const char *protocol_name;int (*bdrv_truncate)(BlockDriverState *bs,int64_t offset);int64_t (*bdrv_getlength)(BlockDriverState *bs);
Signature · 1 line
1.7.6.5
PATCH 15/27 qcow2: Fix offset in qcow2_read_extensions
In reply to Kevin WolfThe spec says that the length of extensions is padded to 8 bytes, not the offset. Currently this is the same because the header size is a multiple of 8, so this is only about compatibility with future changes to the header size.
While touching it, move the calculation to a common place instead of duplicating it for each header extension type.
--- block/qcow2.c | 5 ++--- 1 files changed, 2 insertions(+), 3 deletions(-)
block/qcow2.c +2 -3
@@ -126,7 +126,6 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,#ifdef DEBUG_EXT printf ("Qcow2: Got format extension %s\n" , bs->backing_format);#endif - offset = ((offset + ext.len +7 ) & ~7 );break ;default :
@@ -143,11 +142,11 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,if (ret <0 ) {return ret; } - - offset = ((offset + ext.len +7 ) & ~7 ); }break ; } + + offset += ((ext.len +7 ) & ~7 ); }return 0 ;
Signature · 1 line
1.7.6.5
PATCH 16/27 qcow2: Reject too large header extensions
In reply to Kevin WolfImage files that make qemu-img info read several gigabytes into the unknown header extensions list are bad. Just fail opening the image if an extension claims to be larger than the header extension area.
--- block/qcow2.c | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-)
block/qcow2.c +5 -0
@@ -108,6 +108,11 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,#ifdef DEBUG_EXT printf ("ext.magic = 0x%x\n" , ext.magic);#endif +if (ext.len > end_offset - offset) { +error_report ("Header extension too large" ); +return -EINVAL ; + } +switch (ext.magic) {case QCOW2_EXT_MAGIC_END :return 0 ;
Signature · 1 line
1.7.6.5
PATCH 17/27 qapi: Introduce blockdev-group-snapshot-sync command
In reply to Kevin WolfFrom: Jeff Cody <[email protected]>
This is a QAPI/QMP only command to take a snapshot of a group of devices. This is similar to the blockdev-snapshot-sync command, except blockdev-group-snapshot-sync accepts a list devices, filenames, and formats.
It is attempted to keep the snapshot of the group atomic; if the creation or open of any of the new snapshots fails, then all of the new snapshots are abandoned, and the name of the snapshot image that failed is returned. The failure case should not interrupt any operations.
Rather than use bdrv_close() along with a subsequent bdrv_open() to perform the pivot, the original image is never closed and the new image is placed 'in front' of the original image via manipulation of the BlockDriverState fields. Thus, once the new snapshot image has been successfully created, there are no more failure points before pivoting to the new snapshot.
This allows the group of disks to remain consistent with each other, even across snapshot failures.
--- block.c | 81 +++++++++++++++++++++++++++++++++ block.h | 1 + block_int.h | 6 +++ blockdev.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ qapi-schema.json | 38 ++++++++++++++++ 5 files changed, 257 insertions(+), 0 deletions(-)
block.c +81 -0
@@ -882,6 +882,87 @@ void bdrv_make_anon(BlockDriverState *bs) bs->device_name[0 ] ='\0' ; } +/* +* Add new bs contents at the top of an image chain while the chain is +* live, while keeping required fields on the top layer. +* +* This will modify the BlockDriverState fields, and swap contents +* between bs_new and bs_top. Both bs_new and bs_top are modified. +* +* This function does not create any image files. +*/ +void bdrv_append (BlockDriverState *bs_new,BlockDriverState *bs_top) +{ +BlockDriverState tmp; + +/* the new bs must not be in bdrv_states */ +bdrv_make_anon (bs_new); + + tmp = *bs_new; + +/* there are some fields that need to stay on the top layer: */ + +/* dev info */ + tmp.dev_ops = bs_top->dev_ops; + tmp.dev_opaque = bs_top->dev_opaque; + tmp.dev = bs_top->dev; + tmp.buffer_alignment = bs_top->buffer_alignment; + tmp.copy_on_read = bs_top->copy_on_read; + +/* i/o timing parameters */ + tmp.slice_time = bs_top->slice_time; + tmp.slice_start = bs_top->slice_start; + tmp.slice_end = bs_top->slice_end; + tmp.io_limits = bs_top->io_limits; + tmp.io_base = bs_top->io_base; + tmp.throttled_reqs = bs_top->throttled_reqs; + tmp.block_timer = bs_top->block_timer; + tmp.io_limits_enabled = bs_top->io_limits_enabled; + +/* geometry */ + tmp.cyls = bs_top->cyls; + tmp.heads = bs_top->heads; + tmp.secs = bs_top->secs; + tmp.translation = bs_top->translation; + +/* r/w error */ + tmp.on_read_error = bs_top->on_read_error; + tmp.on_write_error = bs_top->on_write_error; + +/* i/o status */ + tmp.iostatus_enabled = bs_top->iostatus_enabled; + tmp.iostatus = bs_top->iostatus; + +/* keep the same entry in bdrv_states */ +pstrcpy (tmp.device_name,sizeof (tmp.device_name), bs_top->device_name); + tmp.list = bs_top->list; + +/* The contents of 'tmp' will become bs_top, as we are +* swapping bs_new and bs_top contents. */ + tmp.backing_hd = bs_new; +pstrcpy (tmp.backing_file,sizeof (tmp.backing_file), bs_top->filename); + +/* swap contents of the fixed new bs and the current top */ + *bs_new = *bs_top; + *bs_top = tmp; + +/* clear the copied fields in the new backing file */ +bdrv_detach_dev (bs_new, bs_new->dev); + +qemu_co_queue_init (&bs_new->throttled_reqs); +memset (&bs_new->io_base,0 ,sizeof (bs_new->io_base)); +memset (&bs_new->io_limits,0 ,sizeof (bs_new->io_limits)); +bdrv_iostatus_disable (bs_new); + +/* we don't use bdrv_io_limits_disable() for this, because we don't want +* to affect or delete the block_timer, as it has been moved to bs_top */ + bs_new->io_limits_enabled = false; + bs_new->block_timer =NULL ; + bs_new->slice_time =0 ; + bs_new->slice_start =0 ; + bs_new->slice_end =0 ; +} +void bdrv_delete (BlockDriverState *bs) {assert (!bs->dev);
block.h +1 -0
@@ -114,6 +114,7 @@ int bdrv_create(BlockDriver *drv, const char* filename,int bdrv_create_file (const char * filename,QEMUOptionParameter *options);BlockDriverState *bdrv_new (const char *device_name);void bdrv_make_anon (BlockDriverState *bs); +void bdrv_append (BlockDriverState *bs_new,BlockDriverState *bs_top);void bdrv_delete (BlockDriverState *bs);int bdrv_parse_cache_flags (const char *mode,int *flags);int bdrv_file_open (BlockDriverState **pbs,const char *filename,int flags);
block_int.h +6 -0
@@ -221,6 +221,12 @@ struct BlockDriver {QLIST_ENTRY (BlockDriver) list; }; +/* +* Note: the function bdrv_append() copies and swaps contents of +* BlockDriverStates, so if you add new fields to this struct, please +* inspect bdrv_append() to determine if the new fields need to be +* copied as well. +*/ struct BlockDriverState {int64_t total_sectors;/* if we are reading a disk image, give its size in sectors */
blockdev.c +131 -0
137 lines not on this page · raw message
qapi-schema.json +38 -0
@@ -1118,6 +1118,44 @@ { 'command': 'block_resize', 'data': { 'device': 'str', 'size': 'int' }} ## +# @SnapshotDev +# +# @device: the name of the device to generate the snapshot from. +# +# @snapshot-file: the target of the new image. A new file will be created. +# +# @format: #optional the format of the snapshot image, default is 'qcow2'. +## +{ 'type': 'SnapshotDev', + 'data': {'device': 'str', 'snapshot-file': 'str', '*format': 'str' } } + +## +# @blockdev-group-snapshot-sync +# +# Generates a synchronous snapshot of a group of one or more block devices, +# as atomically as possible. If the snapshot of any device in the group +# fails, then the entire group snapshot will be abandoned and the +# appropriate error returned. +# +# List of: +# @SnapshotDev: information needed for the device snapshot +# +# Returns: nothing on success +# If @device is not a valid block device, DeviceNotFound +# If @device is busy, DeviceInUse will be returned +# If @snapshot-file can't be created, OpenFileFailed +# If @snapshot-file can't be opened, OpenFileFailed +# If @format is invalid, InvalidBlockFormat +# +# Note: The group snapshot attempt returns failure on the first snapshot +# device failure. Therefore, there will be only one device or snapshot file +# returned in an error condition, and subsequent devices will not have been +# attempted. +## +{ 'command': 'blockdev-group-snapshot-sync', + 'data': { 'devlist': [ 'SnapshotDev' ] } } + +## # @blockdev-snapshot-sync # # Generates a synchronous snapshot of a block device.
Signature · 1 line
1.7.6.5
PATCH 18/27 QMP: Add qmp command for blockdev-group-snapshot-sync
In reply to Kevin WolfFrom: Jeff Cody <[email protected]>
This adds the QMP command for blockdev-group-snapshot-sync. It takes an array in as the input, for the argument devlist. The array consists of the following elements:
+ device: device to snapshot. e.g. "ide-hd0", "virtio0"
+ snapshot-file: path & file for the snapshot image. e.g. "/tmp/file.img"
+ format: snapshot format. e.g., "qcow2". Optional
There is no HMP equivalent for the command.
--- qmp-commands.hx | 39 +++++++++++++++++++++++++++++++++++++++ 1 files changed, 39 insertions(+), 0 deletions(-)
qmp-commands.hx +39 -0
@@ -686,6 +686,45 @@ EQMP .args_type = "device:B", .mhandler.cmd_new = qmp_marshal_input_block_job_cancel, }, + { + .name = "blockdev-group-snapshot-sync", + .args_type = "devlist:O", + .params = "device:B,snapshot-file:s,format:s?", + .mhandler.cmd_new = qmp_marshal_input_blockdev_group_snapshot_sync, + }, + +SQMP +blockdev-group-snapshot-sync +---------------------- + +Synchronous snapshot of one or more block devices. A list array input +is accepted, that contains the device and snapshot file information for +each device in group. The default format, if not specified, is qcow2. + +If there is any failure creating or opening a new snapshot, all snapshots +for the group are abandoned, and the original disks pre-snapshot attempt +are used. + + +Arguments: + +devlist array: + - "device": device name to snapshot (json-string) + - "snapshot-file": name of new image file (json-string) + - "format": format of new image (json-string, optional) + +Example: + +-> { "execute": "blockdev-group-snapshot-sync", "arguments": + { "devlist": [{ "device": "ide-hd0", + "snapshot-file": "/some/place/my-image", + "format": "qcow2" }, + { "device": "ide-hd1", + "snapshot-file": "/some/place/my-image2", + "format": "qcow2" }] } } +<- { "return": {} } + +EQMP { .name = "blockdev-snapshot-sync",
Signature · 1 line
1.7.6.5
PATCH 19/27 qemu-iotests: export TEST_DIR for non-bash tests
In reply to Kevin WolfFrom: Stefan Hajnoczi <[email protected]>
Since qemu-iotests may need to create large image files it is possible to specify the test directory. The TEST_DIR variable needs to be exported so non-bash tests can make use of it.
--- tests/qemu-iotests/common.config | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
tests/qemu-iotests/common.config +2 -0
@@ -121,6 +121,8 @@ if [ ! -d "$TEST_DIR" ]; then exit 1 fi +export TEST_DIR + _readlink() { if [ $# -ne 1 ]; then
Signature · 1 line
1.7.6.5
PATCH 20/27 qemu-iotests: add iotests Python module
In reply to Kevin WolfFrom: Stefan Hajnoczi <[email protected]>
Block layer tests that involve QMP commands rather than qemu-img or qemu-io are not well-suited for shell scripting. This patch adds a Python module which allows tests to be written in Python instead.
The basic API is:
VM - class for launching and interacting with a VM
QMPTestCase - abstract base class for tests that use QMP
qemu_img() - wrapper function for invoking qemu-img qemu_io() - wrapper function for invoking qemu-io imgfmt - the image format under test (e.g. qcow2, qed) test_dir - scratch directory path for temporary files main() - entry point for running tests
--- tests/qemu-iotests/iotests.py | 164 +++++++++++++++++++++++++++++++++++++++++ 1 files changed, 164 insertions(+), 0 deletions(-) create mode 100644 tests/qemu-iotests/iotests.py
tests/qemu-iotests/iotests.py new file +164 -0
@@ -0,0 +1,164 @@ +# Common utilities and Python wrappers for qemu-iotests +# +# Copyright (C) 2012 IBM Corp. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +import os +import re +import subprocess +import unittest +import sys; sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'QMP')) +import qmp + +__all__ = ['imgfmt', 'imgproto', 'test_dir' 'qemu_img', 'qemu_io', + 'VM', 'QMPTestCase', 'notrun', 'main'] + +# This will not work if arguments or path contain spaces but is necessary if we +# want to support the override options that ./check supports. +qemu_img_args = os.environ.get('QEMU_IMG', 'qemu-img').split(' ') +qemu_io_args = os.environ.get('QEMU_IO', 'qemu-io').split(' ') +qemu_args = os.environ.get('QEMU', 'qemu').split(' ') + +imgfmt = os.environ.get('IMGFMT', 'raw') +imgproto = os.environ.get('IMGPROTO', 'file') +test_dir = os.environ.get('TEST_DIR', '/var/tmp') + +def qemu_img(*args): + '''Run qemu-img and return the exit code''' + devnull = open('/dev/null', 'r+') + return subprocess.call(qemu_img_args + list(args), stdin=devnull, stdout=devnull) + +def qemu_io(*args): + '''Run qemu-io and return the stdout data''' + args = qemu_io_args + list(args) + return subprocess.Popen(args, stdout=subprocess.PIPE).communicate()[0] + +class VM(object): + '''A QEMU VM''' + + def __init__(self): + self._monitor_path = os.path.join(test_dir, 'qemu-mon.%d' % os.getpid()) + self._qemu_log_path = os.path.join(test_dir, 'qemu-log.%d' % os.getpid()) + self._args = qemu_args + ['-chardev', + 'socket,id=mon,path=' + self._monitor_path, + '-mon', 'chardev=mon,mode=control', '-nographic'] + self._num_drives = 0 + + def add_drive(self, path, opts=''): + '''Add a virtio-blk drive to the VM''' + options = ['if=virtio', + 'format=%s' % imgfmt, + 'cache=none', + 'file=%s' % path, + 'id=drive%d' % self._num_drives] + if opts: + options.append(opts) + + self._args.append('-drive') + self._args.append(','.join(options)) + self._num_drives += 1 + return self + + def launch(self): + '''Launch the VM and establish a QMP connection''' + devnull = open('/dev/null', 'rb') + qemulog = open(self._qemu_log_path, 'wb') + try: + self._qmp = qmp.QEMUMonitorProtocol(self._monitor_path, server=True) + self._popen = subprocess.Popen(self._args, stdin=devnull, stdout=qemulog, + stderr=subprocess.STDOUT) + self._qmp.accept() + except: + os.remove(self._monitor_path) + raise + + def shutdown(self): + '''Terminate the VM and clean up''' + self._qmp.cmd('quit') + self._popen.wait() + os.remove(self._monitor_path) + os.remove(self._qemu_log_path) + + def qmp(self, cmd, **args): + '''Invoke a QMP command and return the result dict''' + return self._qmp.cmd(cmd, args=args) + + def get_qmp_events(self, wait=False): + '''Poll for queued QMP events and return a list of dicts''' + events = self._qmp.get_events(wait=wait) + self._qmp.clear_events() + return events + +index_re = re.compile(r'([^\[]+)\[([^\]]+)\]') + +class QMPTestCase(unittest.TestCase): + '''Abstract base class for QMP test cases''' + + def dictpath(self, d, path): + '''Traverse a path in a nested dict''' + for component in path.split('/'): + m = index_re.match(component) + if m: + component, idx = m.groups() + idx = int(idx) + + if not isinstance(d, dict) or component not in d: + self.fail('failed path traversal for "%s" in "%s"' % (path, str(d))) + d = d[component] + + if m: + if not isinstance(d, list): + self.fail('path component "%s" in "%s" is not a list in "%s"' % (component, path, str(d))) + try: + d = d[idx] + except IndexError: + self.fail('invalid index "%s" in path "%s" in "%s"' % (idx, path, str(d))) + return d + + def assert_qmp(self, d, path, value): + '''Assert that the value for a specific path in a QMP dict matches''' + result = self.dictpath(d, path) + self.assertEqual(result, value, 'values not equal "%s" and "%s"' % (str(result), str(value))) + +def notrun(reason): + '''Skip this test suite''' + # Each test in qemu-iotests has a number ("seq") + seq = os.path.basename(sys.argv[0]) + + open('%s.notrun' % seq, 'wb').write(reason + '\n') + print '%s not run: %s' % (seq, reason) + sys.exit(0) + +def main(supported_fmts=[]): + '''Run tests''' + + if supported_fmts and (imgfmt not in supported_fmts): + notrun('not suitable for this image format: %s' % imgfmt) + + # We need to filter out the time taken from the output so that qemu-iotest + # can reliably diff the results against master output. + import StringIO + output = StringIO.StringIO() + + class MyTestRunner(unittest.TextTestRunner): + def __init__(self, stream=output, descriptions=True, verbosity=1): + unittest.TextTestRunner.__init__(self, stream, descriptions, verbosity) + + # unittest.main() will use sys.exit() so expect a SystemExit exception + try: + unittest.main(testRunner=MyTestRunner) + finally: + sys.stderr.write(re.sub(r'Ran (\d+) test[s] in [\d.]+s', r'Ran \1 tests', output.getvalue()))
Signature · 1 line
1.7.6.5
PATCH 21/27 test: add image streaming tests
In reply to Kevin WolfFrom: Stefan Hajnoczi <[email protected]>
This patch adds a test suite for the image streaming feature. It exercises the 'block_stream', 'block_job_cancel', 'block_job_set_speed', and 'query-block-jobs' QMP commands.
--- tests/qemu-iotests/030 | 151 ++++++++++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/030.out | 5 ++ tests/qemu-iotests/group | 1 + 3 files changed, 157 insertions(+), 0 deletions(-) create mode 100755 tests/qemu-iotests/030 create mode 100644 tests/qemu-iotests/030.out
tests/qemu-iotests/030 new file +151 -0
@@ -0,0 +1,151 @@ +#!/usr/bin/env python +# +# Tests for image streaming. +# +# Copyright (C) 2012 IBM Corp. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +import os +import iotests +from iotests import qemu_img, qemu_io + +backing_img = os.path.join(iotests.test_dir, 'backing.img') +test_img = os.path.join(iotests.test_dir, 'test.img') + +class ImageStreamingTestCase(iotests.QMPTestCase): + '''Abstract base class for image streaming test cases''' + + def assert_no_active_streams(self): + result = self.vm.qmp('query-block-jobs') + self.assert_qmp(result, 'return', []) + +class TestSingleDrive(ImageStreamingTestCase): + image_len = 1 * 1024 * 1024 # MB + + def setUp(self): + qemu_img('create', backing_img, str(TestSingleDrive.image_len)) + qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) + self.vm = iotests.VM().add_drive(test_img) + self.vm.launch() + + def tearDown(self): + self.vm.shutdown() + os.remove(test_img) + os.remove(backing_img) + + def test_stream(self): + self.assert_no_active_streams() + + result = self.vm.qmp('block_stream', device='drive0') + self.assert_qmp(result, 'return', {}) + + completed = False + while not completed: + for event in self.vm.get_qmp_events(wait=True): + if event['event'] == 'BLOCK_JOB_COMPLETED': + self.assert_qmp(event, 'data/type', 'stream') + self.assert_qmp(event, 'data/device', 'drive0') + self.assert_qmp(event, 'data/offset', self.image_len) + self.assert_qmp(event, 'data/len', self.image_len) + completed = True + + self.assert_no_active_streams() + + self.assertFalse('sectors not allocated' in qemu_io('-c', 'map', test_img), + 'image file not fully populated after streaming') + + def test_device_not_found(self): + result = self.vm.qmp('block_stream', device='nonexistent') + self.assert_qmp(result, 'error/class', 'DeviceNotFound') + +class TestStreamStop(ImageStreamingTestCase): + image_len = 8 * 1024 * 1024 * 1024 # GB + + def setUp(self): + qemu_img('create', backing_img, str(TestStreamStop.image_len)) + qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) + self.vm = iotests.VM().add_drive(test_img) + self.vm.launch() + + def tearDown(self): + self.vm.shutdown() + os.remove(test_img) + os.remove(backing_img) + + def test_stream_stop(self): + import time + + self.assert_no_active_streams() + + result = self.vm.qmp('block_stream', device='drive0') + self.assert_qmp(result, 'return', {}) + + time.sleep(1) + events = self.vm.get_qmp_events(wait=False) + self.assertEqual(events, [], 'unexpected QMP event: %s' % events) + + self.vm.qmp('block_job_cancel', device='drive0') + self.assert_qmp(result, 'return', {}) + + cancelled = False + while not cancelled: + for event in self.vm.get_qmp_events(wait=True): + if event['event'] == 'BLOCK_JOB_CANCELLED': + self.assert_qmp(event, 'data/type', 'stream') + self.assert_qmp(event, 'data/device', 'drive0') + cancelled = True + + self.assert_no_active_streams() + +# This is a short performance test which is not run by default. +# Invoke "IMGFMT=qed ./030 TestSetSpeed.perf_test_set_speed" +class TestSetSpeed(ImageStreamingTestCase): + image_len = 80 * 1024 * 1024 # MB + + def setUp(self): + qemu_img('create', backing_img, str(TestSetSpeed.image_len)) + qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) + self.vm = iotests.VM().add_drive(test_img) + self.vm.launch() + + def tearDown(self): + self.vm.shutdown() + os.remove(test_img) + os.remove(backing_img) + + def perf_test_set_speed(self): + self.assert_no_active_streams() + + result = self.vm.qmp('block_stream', device='drive0') + self.assert_qmp(result, 'return', {}) + + result = self.vm.qmp('block_job_set_speed', device='drive0', value=8 * 1024 * 1024) + self.assert_qmp(result, 'return', {}) + + completed = False + while not completed: + for event in self.vm.get_qmp_events(wait=True): + if event['event'] == 'BLOCK_JOB_COMPLETED': + self.assert_qmp(event, 'data/type', 'stream') + self.assert_qmp(event, 'data/device', 'drive0') + self.assert_qmp(event, 'data/offset', self.image_len) + self.assert_qmp(event, 'data/len', self.image_len) + completed = True + + self.assert_no_active_streams() + +if __name__ == '__main__': + iotests.main(supported_fmts=['qcow2', 'qed'])
tests/qemu-iotests/030.out new file +5 -0
@@ -0,0 +1,5 @@ +... +---------------------------------------------------------------------- +Ran 3 tests + +OK
tests/qemu-iotests/group +1 -0
@@ -36,3 +36,4 @@ 027 rw auto 028 rw backing auto 029 rw auto +030 rw auto
Signature · 1 line
1.7.6.5
PATCH 22/27 qemu-iotests: Filter out DOS line endings
In reply to Kevin WolfThis one makes it possible to run qemu-iotests on a Windows build using Wine and get somewhat meaningful results.
--- tests/qemu-iotests/common.filter | 8 +++++++- 1 files changed, 7 insertions(+), 1 deletions(-)
tests/qemu-iotests/common.filter +7 -1
@@ -140,10 +140,16 @@ _filter_imgfmt() sed -e "s#$IMGFMT#IMGFMT#g" } +# Removes \r from messages +_filter_win32() +{ + sed -e 's/\r//g' +} + # sanitize qemu-io output _filter_qemu_io() { - sed -e "s/[0-9]* ops\; [0-9/:. sec]* ([0-9/.inf]* [EPTGMKiBbytes]*\/sec and [0-9/.inf]* ops\/sec)/X ops\; XX:XX:XX.X (XXX YYY\/sec and XXX ops\/sec)/" + _filter_win32 | sed -e "s/[0-9]* ops\; [0-9/:. sec]* ([0-9/.inf]* [EPTGMKiBbytes]*\/sec and [0-9/.inf]* ops\/sec)/X ops\; XX:XX:XX.X (XXX YYY\/sec and XXX ops\/sec)/" } # make sure this script returns success
Signature · 1 line
1.7.6.5
PATCH 23/27 qemu-iotests: 026: Reduce output changes for cache=none qcow2
In reply to Kevin Wolfqemu-iotests supports the -nocache option which makes the tests run with cache=none. For blkdebug tests with qcow2 this means that we may see test results that differ from cache=writethrough. This patch makes the diff a bit smaller and therefore easier to review.
--- tests/qemu-iotests/026 | 6 ++++++ tests/qemu-iotests/check | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-)
tests/qemu-iotests/026 +6 -0
@@ -87,6 +87,12 @@ _make_test_img 1G echo echo "Event: $event; errno: $errno; imm: $imm; once: $once; write $vmstate" + +# We want to catch a simple L2 update, not the allocation of the first L2 table +if [ "$event" == "l2_update" ]; then + $QEMU_IO -c "write $vmstate 0 512" $TEST_IMG > /dev/null 2>&1 +fi + $QEMU_IO -c "write $vmstate 0 128k " $BLKDBG_TEST_IMG | _filter_qemu_io # l2_load is not called on allocation, so issue a second write
tests/qemu-iotests/check +2 -2
@@ -243,7 +243,7 @@ do echo " - no qualified output" err=true else - if diff $seq.out $tmp.out >/dev/null 2>&1 + if diff -w $seq.out $tmp.out >/dev/null 2>&1 then echo "" if $err
@@ -255,7 +255,7 @@ do else echo " - output mismatch (see $seq.out.bad)" mv $tmp.out $seq.out.bad - $diff $seq.out $seq.out.bad + $diff -w $seq.out $seq.out.bad err=true fi fi
Signature · 1 line
1.7.6.5
PATCH 24/27 qemu-iotests: Test rebase with short backing file
In reply to Kevin WolfThis tests that qemu-img rebase doesn't assume that the backing file has the same size as the image, but considers that it can be smaller.
--- tests/qemu-iotests/028 | 5 +++++ tests/qemu-iotests/028.out | 1 + 2 files changed, 6 insertions(+), 0 deletions(-)
tests/qemu-iotests/028 +5 -0
@@ -96,6 +96,11 @@ io_zero readv $(( offset + 32 * 1024 )) 512 1024 32 _check_test_img +# Rebase it on top of its base image +$QEMU_IMG rebase -b $TEST_IMG.base $TEST_IMG + +_check_test_img + # success, all done echo "*** done" rm -f $seq.full
tests/qemu-iotests/028.out +1 -0
@@ -465,4 +465,5 @@ qemu-io> read 512/512 bytes at offset 3221257728 qemu-io> read 512/512 bytes at offset 3221258752 512.000000 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) qemu-io> No errors were found on the image. +No errors were found on the image. *** done
Signature · 1 line
1.7.6.5
PATCH 25/27 qemu-tool: revert cpu_get_clock() abort(3)
In reply to Kevin WolfFrom: Stefan Hajnoczi <[email protected]>
Despite the fact that the qemu-tool environment has no guest running and vm_clock therefore does not make sense, there is code that gets the vm_clock time even in qemu-tool. Therefore, revert the abort(3) call and just return 0 like we used to. This unbreaks qemu-img/qemu-io with QED and Kevin has also expressed interest in this for qcow2.
--- qemu-tool.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
qemu-tool.c +1 -1
@@ -61,7 +61,7 @@ void monitor_protocol_event(MonitorEvent event, QObject *data)int64_t cpu_get_clock (void ) { -abort (); +return 0 ; }int64_t cpu_get_icount (void )
Signature · 1 line
1.7.6.5
PATCH 26/27 qemu-io: fix segment fault when the image format is qed
In reply to Kevin WolfFrom: Zhi Yong Wu <[email protected]>
[root@f15 qemu]# qemu-io -c info /home/zwu/work/misc/rh6.img format name: qed
cluster size: 64 KiB
vm state offset: 0.000000 bytes
Segmentation fault (core dumped)
This reason is same as the former patch
--- qemu-io.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
qemu-io.c +2 -0
@@ -1856,6 +1856,8 @@ int main(int argc, char **argv)bdrv_init (); +qemu_init_main_loop (); +/* initialize commands */ quit_init ();help_init ();
Signature · 1 line
1.7.6.5
PATCH 27/27 qemu-img: fix segment fault when the image format is qed
In reply to Kevin WolfFrom: Zhi Yong Wu <[email protected]>
[root@f15 qemu]# qemu-img info /home/zwu/work/misc/rh6.img
image: /home/zwu/work/misc/rh6.img
file format: qed
virtual size: 4.0G (4294967296 bytes)
disk size: 1.2Gcluster_size: 65536
Segmentation fault (core dumped)
Today when i were fixing another issue, i found this issue; After simple investigation, i found that the required clock vm_clock is not created for qemu tool.
--- qemu-img.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
qemu-img.c +2 -0
@@ -1655,6 +1655,8 @@ int main(int argc, char **argv) cmdname = argv[1 ]; argc--; argv++; +qemu_init_main_loop (); +/* find the command */ for (cmd = img_cmds; cmd->name !=NULL ; cmd++) {if (!strcmp (cmdname, cmd->name)) {
Signature · 1 line
1.7.6.5
Quoted 7 lines · Kevin Wolf
The following changes since commit
b55c952aea6de024bf1a06357b49367fba045443:Merge remote-tracking branch 'aneesh/for-upstream' into staging (2012-02-27 11:19:27 -0600)are available in the git repository at:
git://repo.or.cz/qemu/kevin.gitfor-anthony
Pulled. Thanks.
Regards,
Anthony Liguori
Quoted 70 lines
Hervé Poussineau (10):
fdc: take side count into account
fdc: set busy bit when starting a command
fdc: most control commands do not generate interrupts
fdc: handle read-only floppies (abort early on write commands)
fdc: add CCR (Configuration Control Register) write register
block: add a transfer rate for floppy types
fdc: add a 'check media rate' property. Not used yet
fdc: check if media rate is correct before doing any transfer
fdc: fix seek command, which shouldn't check tracks
fdc: DIR (Digital Input Register) should return status of current drive...Jeff Cody (2):
qapi: Introduce blockdev-group-snapshot-sync command
QMP: Add qmp command for blockdev-group-snapshot-syncKevin Wolf (6):
qcow2: Fix build withDEBUG_EXTenabled
qcow2: Fix offset inqcow2_read_extensions
qcow2: Reject too large header extensions
qemu-iotests: Filter out DOS line endings
qemu-iotests: 026: Reduce output changes for cache=none qcow2
qemu-iotests: Test rebase with short backing filePaolo Bonzini (3):
ide: fail I/O to empty disk
block: remove unused fields in BlockDriverState
block: dropaio_multiwritein BlockDriverStefan Hajnoczi (4):
qemu-iotests: exportTEST_DIRfor non-bash tests
qemu-iotests: add iotests Python module
test: add image streaming tests
qemu-tool: revertcpu_get_clock()abort(3)Zhi Yong Wu (2):
qemu-io: fix segment fault when the image format is qed
qemu-img: fix segment fault when the image format is qedblock.c | 178 ++++++++++++++++++++++++++------------ block.h | 11 ++- block/qcow2.c | 11 ++- block_int.h | 17 ++--- blockdev.c | 131 ++++++++++++++++++++++++++++ hw/fdc.c | 142 ++++++++++++++++++++++++------ hw/ide/core.c | 24 ++++- hw/pc.c | 3 +- hw/pc_piix.c | 28 ++++++ qapi-schema.json | 38 ++++++++ qemu-img.c | 2 + qemu-io.c | 2 + qemu-tool.c | 2 +- qmp-commands.hx | 39 ++++++++ tests/qemu-iotests/026 | 6 ++ tests/qemu-iotests/028 | 5 + tests/qemu-iotests/028.out | 1 + tests/qemu-iotests/030 | 151 ++++++++++++++++++++++++++++++++ tests/qemu-iotests/030.out | 5 + tests/qemu-iotests/check | 4 +- tests/qemu-iotests/common.config | 2 + tests/qemu-iotests/common.filter | 8 ++- tests/qemu-iotests/group | 1 + tests/qemu-iotests/iotests.py | 164 +++++++++++++++++++++++++++++++++++ 24 files changed, 868 insertions(+), 107 deletions(-)create mode 100755 tests/qemu-iotests/030 create mode 100644 tests/qemu-iotests/030.out create mode 100644
tests/qemu-iotests/iotests.py