Merge remote branch 'kwolf/for-anthony' into staging

This commit is contained in:
Anthony Liguori 2010-08-09 08:25:12 -05:00
commit f040236cd5
9 changed files with 115 additions and 77 deletions

View File

@ -346,7 +346,7 @@ static int mig_save_device_dirty(Monitor *mon, QEMUFile *f,
blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE; blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE;
qemu_iovec_init_external(&blk->qiov, &blk->iov, 1); qemu_iovec_init_external(&blk->qiov, &blk->iov, 1);
blk->time = qemu_get_clock_ns(rt_clock); blk->time = qemu_get_clock_ns(rt_clock);
blk->aiocb = bdrv_aio_readv(bmds->bs, sector, &blk->qiov, blk->aiocb = bdrv_aio_readv(bmds->bs, sector, &blk->qiov,
nr_sectors, blk_mig_read_cb, blk); nr_sectors, blk_mig_read_cb, blk);
@ -449,13 +449,13 @@ static int is_stage2_completed(void)
if (block_mig_state.bulk_completed == 1) { if (block_mig_state.bulk_completed == 1) {
remaining_dirty = get_remaining_dirty(); remaining_dirty = get_remaining_dirty();
if (remaining_dirty == 0) { if (remaining_dirty == 0) {
return 1; return 1;
} }
bwidth = compute_read_bwidth(); bwidth = compute_read_bwidth();
if ((remaining_dirty / bwidth) <= if ((remaining_dirty / bwidth) <=
migrate_max_downtime()) { migrate_max_downtime()) {
/* finish stage2 because we think that we can finish remaing work /* finish stage2 because we think that we can finish remaing work
below max_downtime */ below max_downtime */

50
block.c
View File

@ -739,14 +739,16 @@ int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res)
return bs->drv->bdrv_check(bs, res); return bs->drv->bdrv_check(bs, res);
} }
#define COMMIT_BUF_SECTORS 2048
/* commit COW file into the raw image */ /* commit COW file into the raw image */
int bdrv_commit(BlockDriverState *bs) int bdrv_commit(BlockDriverState *bs)
{ {
BlockDriver *drv = bs->drv; BlockDriver *drv = bs->drv;
int64_t i, total_sectors; int64_t sector, total_sectors;
int n, j, ro, open_flags; int n, ro, open_flags;
int ret = 0, rw_ret = 0; int ret = 0, rw_ret = 0;
unsigned char sector[BDRV_SECTOR_SIZE]; uint8_t *buf;
char filename[1024]; char filename[1024];
BlockDriverState *bs_rw, *bs_ro; BlockDriverState *bs_rw, *bs_ro;
@ -789,22 +791,20 @@ int bdrv_commit(BlockDriverState *bs)
} }
total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS; total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
for (i = 0; i < total_sectors;) { buf = qemu_malloc(COMMIT_BUF_SECTORS * BDRV_SECTOR_SIZE);
if (drv->bdrv_is_allocated(bs, i, 65536, &n)) {
for(j = 0; j < n; j++) {
if (bdrv_read(bs, i, sector, 1) != 0) {
ret = -EIO;
goto ro_cleanup;
}
if (bdrv_write(bs->backing_hd, i, sector, 1) != 0) { for (sector = 0; sector < total_sectors; sector += n) {
ret = -EIO; if (drv->bdrv_is_allocated(bs, sector, COMMIT_BUF_SECTORS, &n)) {
goto ro_cleanup;
} if (bdrv_read(bs, sector, buf, n) != 0) {
i++; ret = -EIO;
} goto ro_cleanup;
} else { }
i += n;
if (bdrv_write(bs->backing_hd, sector, buf, n) != 0) {
ret = -EIO;
goto ro_cleanup;
}
} }
} }
@ -821,6 +821,7 @@ int bdrv_commit(BlockDriverState *bs)
bdrv_flush(bs->backing_hd); bdrv_flush(bs->backing_hd);
ro_cleanup: ro_cleanup:
qemu_free(buf);
if (ro) { if (ro) {
/* re-open as RO */ /* re-open as RO */
@ -1476,10 +1477,8 @@ int bdrv_has_zero_init(BlockDriverState *bs)
{ {
assert(bs->drv); assert(bs->drv);
if (bs->drv->no_zero_init) { if (bs->drv->bdrv_has_zero_init) {
return 0; return bs->drv->bdrv_has_zero_init(bs);
} else if (bs->file) {
return bdrv_has_zero_init(bs->file);
} }
return 1; return 1;
@ -2518,7 +2517,7 @@ int bdrv_is_inserted(BlockDriverState *bs)
if (!drv) if (!drv)
return 0; return 0;
if (!drv->bdrv_is_inserted) if (!drv->bdrv_is_inserted)
return 1; return !bs->tray_open;
ret = drv->bdrv_is_inserted(bs); ret = drv->bdrv_is_inserted(bs);
return ret; return ret;
} }
@ -2560,10 +2559,11 @@ int bdrv_eject(BlockDriverState *bs, int eject_flag)
ret = drv->bdrv_eject(bs, eject_flag); ret = drv->bdrv_eject(bs, eject_flag);
} }
if (ret == -ENOTSUP) { if (ret == -ENOTSUP) {
if (eject_flag)
bdrv_close(bs);
ret = 0; ret = 0;
} }
if (ret >= 0) {
bs->tray_open = eject_flag;
}
return ret; return ret;
} }

View File

@ -993,6 +993,11 @@ static int hdev_create(const char *filename, QEMUOptionParameter *options)
return ret; return ret;
} }
static int hdev_has_zero_init(BlockDriverState *bs)
{
return 0;
}
static BlockDriver bdrv_host_device = { static BlockDriver bdrv_host_device = {
.format_name = "host_device", .format_name = "host_device",
.protocol_name = "host_device", .protocol_name = "host_device",
@ -1002,7 +1007,7 @@ static BlockDriver bdrv_host_device = {
.bdrv_close = raw_close, .bdrv_close = raw_close,
.bdrv_create = hdev_create, .bdrv_create = hdev_create,
.create_options = raw_create_options, .create_options = raw_create_options,
.no_zero_init = 1, .bdrv_has_zero_init = hdev_has_zero_init,
.bdrv_flush = raw_flush, .bdrv_flush = raw_flush,
.bdrv_aio_readv = raw_aio_readv, .bdrv_aio_readv = raw_aio_readv,
@ -1117,7 +1122,7 @@ static BlockDriver bdrv_host_floppy = {
.bdrv_close = raw_close, .bdrv_close = raw_close,
.bdrv_create = hdev_create, .bdrv_create = hdev_create,
.create_options = raw_create_options, .create_options = raw_create_options,
.no_zero_init = 1, .bdrv_has_zero_init = hdev_has_zero_init,
.bdrv_flush = raw_flush, .bdrv_flush = raw_flush,
.bdrv_aio_readv = raw_aio_readv, .bdrv_aio_readv = raw_aio_readv,
@ -1217,7 +1222,7 @@ static BlockDriver bdrv_host_cdrom = {
.bdrv_close = raw_close, .bdrv_close = raw_close,
.bdrv_create = hdev_create, .bdrv_create = hdev_create,
.create_options = raw_create_options, .create_options = raw_create_options,
.no_zero_init = 1, .bdrv_has_zero_init = hdev_has_zero_init,
.bdrv_flush = raw_flush, .bdrv_flush = raw_flush,
.bdrv_aio_readv = raw_aio_readv, .bdrv_aio_readv = raw_aio_readv,
@ -1340,7 +1345,7 @@ static BlockDriver bdrv_host_cdrom = {
.bdrv_close = raw_close, .bdrv_close = raw_close,
.bdrv_create = hdev_create, .bdrv_create = hdev_create,
.create_options = raw_create_options, .create_options = raw_create_options,
.no_zero_init = 1, .bdrv_has_zero_init = hdev_has_zero_init,
.bdrv_flush = raw_flush, .bdrv_flush = raw_flush,
.bdrv_aio_readv = raw_aio_readv, .bdrv_aio_readv = raw_aio_readv,

View File

@ -394,6 +394,11 @@ static int raw_set_locked(BlockDriverState *bs, int locked)
} }
#endif #endif
static int hdev_has_zero_init(BlockDriverState *bs)
{
return 0;
}
static BlockDriver bdrv_host_device = { static BlockDriver bdrv_host_device = {
.format_name = "host_device", .format_name = "host_device",
.protocol_name = "host_device", .protocol_name = "host_device",
@ -402,6 +407,7 @@ static BlockDriver bdrv_host_device = {
.bdrv_file_open = hdev_open, .bdrv_file_open = hdev_open,
.bdrv_close = raw_close, .bdrv_close = raw_close,
.bdrv_flush = raw_flush, .bdrv_flush = raw_flush,
.bdrv_has_zero_init = hdev_has_zero_init,
.bdrv_read = raw_read, .bdrv_read = raw_read,
.bdrv_write = raw_write, .bdrv_write = raw_write,

View File

@ -237,6 +237,11 @@ static QEMUOptionParameter raw_create_options[] = {
{ NULL } { NULL }
}; };
static int raw_has_zero_init(BlockDriverState *bs)
{
return bdrv_has_zero_init(bs->file);
}
static BlockDriver bdrv_raw = { static BlockDriver bdrv_raw = {
.format_name = "raw", .format_name = "raw",
@ -264,6 +269,7 @@ static BlockDriver bdrv_raw = {
.bdrv_create = raw_create, .bdrv_create = raw_create,
.create_options = raw_create_options, .create_options = raw_create_options,
.bdrv_has_zero_init = raw_has_zero_init,
}; };
static void bdrv_raw_init(void) static void bdrv_raw_init(void)

View File

@ -127,8 +127,11 @@ struct BlockDriver {
void (*bdrv_debug_event)(BlockDriverState *bs, BlkDebugEvent event); void (*bdrv_debug_event)(BlockDriverState *bs, BlkDebugEvent event);
/* Set if newly created images are not guaranteed to contain only zeros */ /*
int no_zero_init; * Returns 1 if newly created images are guaranteed to contain only
* zeros, 0 otherwise.
*/
int (*bdrv_has_zero_init)(BlockDriverState *bs);
QLIST_ENTRY(BlockDriver) list; QLIST_ENTRY(BlockDriver) list;
}; };
@ -141,6 +144,7 @@ struct BlockDriverState {
int open_flags; /* flags used to open the file, re-used for re-open */ int open_flags; /* flags used to open the file, re-used for re-open */
int removable; /* if true, the media can be removed */ int removable; /* if true, the media can be removed */
int locked; /* if true, the media cannot temporarily be ejected */ int locked; /* if true, the media cannot temporarily be ejected */
int tray_open; /* if true, the virtual tray is open */
int encrypted; /* if true, the media is encrypted */ int encrypted; /* if true, the media is encrypted */
int valid_key; /* if true, a valid encryption key has been set */ int valid_key; /* if true, a valid encryption key has been set */
int sg; /* if true, the device is a /dev/sg* */ int sg; /* if true, the device is a /dev/sg* */

View File

@ -40,8 +40,27 @@ void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val)
printf("%s: 0x%08x\n", __func__, val); printf("%s: 0x%08x\n", __func__, val);
#endif #endif
if (!(val & BM_CMD_START)) { if (!(val & BM_CMD_START)) {
/* XXX: do it better */ /*
ide_dma_cancel(bm); * We can't cancel Scatter Gather DMA in the middle of the
* operation or a partial (not full) DMA transfer would reach
* the storage so we wait for completion instead (we beahve
* like if the DMA was completed by the time the guest trying
* to cancel dma with bmdma_cmd_writeb with BM_CMD_START not
* set).
*
* In the future we'll be able to safely cancel the I/O if the
* whole DMA operation will be submitted to disk with a single
* aio operation with preadv/pwritev.
*/
if (bm->aiocb) {
qemu_aio_flush();
#ifdef DEBUG_IDE
if (bm->aiocb)
printf("ide_dma_cancel: aiocb still pending");
if (bm->status & BM_STATUS_DMAING)
printf("ide_dma_cancel: BM_STATUS_DMAING still pending");
#endif
}
bm->cmd = val & 0x09; bm->cmd = val & 0x09;
} else { } else {
if (!(bm->status & BM_STATUS_DMAING)) { if (!(bm->status & BM_STATUS_DMAING)) {

View File

@ -2274,8 +2274,9 @@ static void do_loadvm(Monitor *mon, const QDict *qdict)
vm_stop(0); vm_stop(0);
if (load_vmstate(name) >= 0 && saved_vm_running) if (load_vmstate(name) == 0 && saved_vm_running) {
vm_start(); vm_start();
}
} }
int monitor_get_fd(Monitor *mon, const char *fdname) int monitor_get_fd(Monitor *mon, const char *fdname)

View File

@ -1894,12 +1894,27 @@ void do_savevm(Monitor *mon, const QDict *qdict)
int load_vmstate(const char *name) int load_vmstate(const char *name)
{ {
BlockDriverState *bs, *bs1; BlockDriverState *bs, *bs_vm_state;
QEMUSnapshotInfo sn; QEMUSnapshotInfo sn;
QEMUFile *f; QEMUFile *f;
int ret; int ret;
/* Verify if there is a device that doesn't support snapshots and is writable */ bs_vm_state = bdrv_snapshots();
if (!bs_vm_state) {
error_report("No block device supports snapshots");
return -ENOTSUP;
}
/* Don't even try to load empty VM states */
ret = bdrv_snapshot_find(bs_vm_state, &sn, name);
if (ret < 0) {
return ret;
} else if (sn.vm_state_size == 0) {
return -EINVAL;
}
/* Verify if there is any device that doesn't support snapshots and is
writable and check if the requested snapshot is available too. */
bs = NULL; bs = NULL;
while ((bs = bdrv_next(bs))) { while ((bs = bdrv_next(bs))) {
@ -1912,63 +1927,45 @@ int load_vmstate(const char *name)
bdrv_get_device_name(bs)); bdrv_get_device_name(bs));
return -ENOTSUP; return -ENOTSUP;
} }
}
bs = bdrv_snapshots(); ret = bdrv_snapshot_find(bs, &sn, name);
if (!bs) { if (ret < 0) {
error_report("No block device supports snapshots"); error_report("Device '%s' does not have the requested snapshot '%s'",
return -EINVAL; bdrv_get_device_name(bs), name);
return ret;
}
} }
/* Flush all IO requests so they don't interfere with the new state. */ /* Flush all IO requests so they don't interfere with the new state. */
qemu_aio_flush(); qemu_aio_flush();
bs1 = NULL; bs = NULL;
while ((bs1 = bdrv_next(bs1))) { while ((bs = bdrv_next(bs))) {
if (bdrv_can_snapshot(bs1)) { if (bdrv_can_snapshot(bs)) {
ret = bdrv_snapshot_goto(bs1, name); ret = bdrv_snapshot_goto(bs, name);
if (ret < 0) { if (ret < 0) {
switch(ret) { error_report("Error %d while activating snapshot '%s' on '%s'",
case -ENOTSUP: ret, name, bdrv_get_device_name(bs));
error_report("%sSnapshots not supported on device '%s'", return ret;
bs != bs1 ? "Warning: " : "",
bdrv_get_device_name(bs1));
break;
case -ENOENT:
error_report("%sCould not find snapshot '%s' on device '%s'",
bs != bs1 ? "Warning: " : "",
name, bdrv_get_device_name(bs1));
break;
default:
error_report("%sError %d while activating snapshot on '%s'",
bs != bs1 ? "Warning: " : "",
ret, bdrv_get_device_name(bs1));
break;
}
/* fatal on snapshot block device */
if (bs == bs1)
return 0;
} }
} }
} }
/* Don't even try to load empty VM states */
ret = bdrv_snapshot_find(bs, &sn, name);
if ((ret >= 0) && (sn.vm_state_size == 0))
return -EINVAL;
/* restore the VM state */ /* restore the VM state */
f = qemu_fopen_bdrv(bs, 0); f = qemu_fopen_bdrv(bs_vm_state, 0);
if (!f) { if (!f) {
error_report("Could not open VM state file"); error_report("Could not open VM state file");
return -EINVAL; return -EINVAL;
} }
ret = qemu_loadvm_state(f); ret = qemu_loadvm_state(f);
qemu_fclose(f); qemu_fclose(f);
if (ret < 0) { if (ret < 0) {
error_report("Error %d while loading VM state", ret); error_report("Error %d while loading VM state", ret);
return ret; return ret;
} }
return 0; return 0;
} }