Skip to content

Commit

Permalink
Merge remote-tracking branch 'kwolf/for-anthony' into staging
Browse files Browse the repository at this point in the history
# By Kevin Wolf (6) and Stefan Hajnoczi (2)
# Via Kevin Wolf
* kwolf/for-anthony:
  ahci: Fix FLUSH command
  migration: Fail migration on bdrv_flush_all() error
  cpus: Add return value for vm_stop()
  block: Add return value for bdrv_flush_all()
  qemu-iotests: Update 051 reference output
  block: Don't parse protocol from file.filename
  block: add drive_backup HMP command
  blockdev: add sync mode to drive-backup QMP command

Message-id: 1373887000-4488-1-git-send-email-kwolf@redhat.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
  • Loading branch information
Anthony Liguori committed Jul 15, 2013
2 parents c3cb8e7 + a62eaa2 commit 5699a02
Show file tree
Hide file tree
Showing 21 changed files with 262 additions and 76 deletions.
27 changes: 20 additions & 7 deletions block.c
Expand Up @@ -417,7 +417,7 @@ int bdrv_create_file(const char* filename, QEMUOptionParameter *options)
{
BlockDriver *drv;

drv = bdrv_find_protocol(filename);
drv = bdrv_find_protocol(filename, true);
if (drv == NULL) {
return -ENOENT;
}
Expand Down Expand Up @@ -482,7 +482,8 @@ static BlockDriver *find_hdev_driver(const char *filename)
return drv;
}

BlockDriver *bdrv_find_protocol(const char *filename)
BlockDriver *bdrv_find_protocol(const char *filename,
bool allow_protocol_prefix)
{
BlockDriver *drv1;
char protocol[128];
Expand All @@ -503,9 +504,10 @@ BlockDriver *bdrv_find_protocol(const char *filename)
return drv1;
}

if (!path_has_protocol(filename)) {
if (!path_has_protocol(filename) || !allow_protocol_prefix) {
return bdrv_find_format("file");
}

p = strchr(filename, ':');
assert(p != NULL);
len = p - filename;
Expand Down Expand Up @@ -784,6 +786,7 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename,
BlockDriverState *bs;
BlockDriver *drv;
const char *drvname;
bool allow_protocol_prefix = false;
int ret;

/* NULL means an empty set of options */
Expand All @@ -800,6 +803,7 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename,
filename = qdict_get_try_str(options, "filename");
} else if (filename && !qdict_haskey(options, "filename")) {
qdict_put(options, "filename", qstring_from_str(filename));
allow_protocol_prefix = true;
} else {
qerror_report(ERROR_CLASS_GENERIC_ERROR, "Can't specify 'file' and "
"'filename' options at the same time");
Expand All @@ -813,7 +817,10 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename,
drv = bdrv_find_whitelisted_format(drvname, !(flags & BDRV_O_RDWR));
qdict_del(options, "driver");
} else if (filename) {
drv = bdrv_find_protocol(filename);
drv = bdrv_find_protocol(filename, allow_protocol_prefix);
if (!drv) {
qerror_report(ERROR_CLASS_GENERIC_ERROR, "Unknown protocol");
}
} else {
qerror_report(ERROR_CLASS_GENERIC_ERROR,
"Must specify either driver or file");
Expand Down Expand Up @@ -2903,13 +2910,19 @@ int bdrv_get_flags(BlockDriverState *bs)
return bs->open_flags;
}

void bdrv_flush_all(void)
int bdrv_flush_all(void)
{
BlockDriverState *bs;
int result = 0;

QTAILQ_FOREACH(bs, &bdrv_states, list) {
bdrv_flush(bs);
int ret = bdrv_flush(bs);
if (ret < 0 && !result) {
result = ret;
}
}

return result;
}

int bdrv_has_zero_init_1(BlockDriverState *bs)
Expand Down Expand Up @@ -4452,7 +4465,7 @@ void bdrv_img_create(const char *filename, const char *fmt,
return;
}

proto_drv = bdrv_find_protocol(filename);
proto_drv = bdrv_find_protocol(filename, true);
if (!proto_drv) {
error_setg(errp, "Unknown protocol '%s'", filename);
return;
Expand Down
2 changes: 1 addition & 1 deletion block/sheepdog.c
Expand Up @@ -1510,7 +1510,7 @@ static int sd_create(const char *filename, QEMUOptionParameter *options)
BlockDriver *drv;

/* Currently, only Sheepdog backing image is supported. */
drv = bdrv_find_protocol(backing_file);
drv = bdrv_find_protocol(backing_file, true);
if (!drv || strcmp(drv->protocol_name, "sheepdog") != 0) {
error_report("backing_file must be a sheepdog image");
ret = -EINVAL;
Expand Down
6 changes: 6 additions & 0 deletions blockdev.c
Expand Up @@ -936,6 +936,7 @@ static void drive_backup_prepare(BlkTransactionState *common, Error **errp)

qmp_drive_backup(backup->device, backup->target,
backup->has_format, backup->format,
backup->sync,
backup->has_mode, backup->mode,
backup->has_speed, backup->speed,
backup->has_on_source_error, backup->on_source_error,
Expand Down Expand Up @@ -1421,6 +1422,7 @@ void qmp_block_commit(const char *device,

void qmp_drive_backup(const char *device, const char *target,
bool has_format, const char *format,
enum MirrorSyncMode sync,
bool has_mode, enum NewImageMode mode,
bool has_speed, int64_t speed,
bool has_on_source_error, BlockdevOnError on_source_error,
Expand All @@ -1435,6 +1437,10 @@ void qmp_drive_backup(const char *device, const char *target,
int64_t size;
int ret;

if (sync != MIRROR_SYNC_MODE_FULL) {
error_setg(errp, "only sync mode 'full' is currently supported");
return;
}
if (!has_speed) {
speed = 0;
}
Expand Down
20 changes: 13 additions & 7 deletions cpus.c
Expand Up @@ -434,17 +434,21 @@ bool cpu_is_stopped(CPUState *cpu)
return !runstate_is_running() || cpu->stopped;
}

static void do_vm_stop(RunState state)
static int do_vm_stop(RunState state)
{
int ret = 0;

if (runstate_is_running()) {
cpu_disable_ticks();
pause_all_vcpus();
runstate_set(state);
vm_state_notify(0, state);
bdrv_drain_all();
bdrv_flush_all();
ret = bdrv_flush_all();
monitor_protocol_event(QEVENT_STOP, NULL);
}

return ret;
}

static bool cpu_can_run(CPUState *cpu)
Expand Down Expand Up @@ -1070,7 +1074,7 @@ void cpu_stop_current(void)
}
}

void vm_stop(RunState state)
int vm_stop(RunState state)
{
if (qemu_in_vcpu_thread()) {
qemu_system_vmstop_request(state);
Expand All @@ -1079,19 +1083,21 @@ void vm_stop(RunState state)
* vm_stop() has been requested.
*/
cpu_stop_current();
return;
return 0;
}
do_vm_stop(state);

return do_vm_stop(state);
}

/* does a state transition even if the VM is already stopped,
current state is forgotten forever */
void vm_stop_force_state(RunState state)
int vm_stop_force_state(RunState state)
{
if (runstate_is_running()) {
vm_stop(state);
return vm_stop(state);
} else {
runstate_set(state);
return 0;
}
}

Expand Down
20 changes: 20 additions & 0 deletions hmp-commands.hx
Expand Up @@ -1056,6 +1056,26 @@ STEXI
@findex drive_mirror
Start mirroring a block device's writes to a new destination,
using the specified target.
ETEXI

{
.name = "drive_backup",
.args_type = "reuse:-n,full:-f,device:B,target:s,format:s?",
.params = "[-n] [-f] device target [format]",
.help = "initiates a point-in-time\n\t\t\t"
"copy for a device. The device's contents are\n\t\t\t"
"copied to the new image file, excluding data that\n\t\t\t"
"is written after the command is started.\n\t\t\t"
"The -n flag requests QEMU to reuse the image found\n\t\t\t"
"in new-image-file, instead of recreating it from scratch.\n\t\t\t"
"The -f flag requests QEMU to copy the whole disk,\n\t\t\t"
"so that the result does not need a backing file.\n\t\t\t",
.mhandler.cmd = hmp_drive_backup,
},
STEXI
@item drive_backup
@findex drive_backup
Start a point-in-time copy of a block device to a specificed target.
ETEXI

{
Expand Down
28 changes: 28 additions & 0 deletions hmp.c
Expand Up @@ -907,6 +907,34 @@ void hmp_drive_mirror(Monitor *mon, const QDict *qdict)
hmp_handle_error(mon, &errp);
}

void hmp_drive_backup(Monitor *mon, const QDict *qdict)
{
const char *device = qdict_get_str(qdict, "device");
const char *filename = qdict_get_str(qdict, "target");
const char *format = qdict_get_try_str(qdict, "format");
int reuse = qdict_get_try_bool(qdict, "reuse", 0);
int full = qdict_get_try_bool(qdict, "full", 0);
enum NewImageMode mode;
Error *errp = NULL;

if (!filename) {
error_set(&errp, QERR_MISSING_PARAMETER, "target");
hmp_handle_error(mon, &errp);
return;
}

if (reuse) {
mode = NEW_IMAGE_MODE_EXISTING;
} else {
mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
}

qmp_drive_backup(device, filename, !!format, format,
full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP,
true, mode, false, 0, false, 0, false, 0, &errp);
hmp_handle_error(mon, &errp);
}

void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict)
{
const char *device = qdict_get_str(qdict, "device");
Expand Down
1 change: 1 addition & 0 deletions hmp.h
Expand Up @@ -55,6 +55,7 @@ void hmp_balloon(Monitor *mon, const QDict *qdict);
void hmp_block_resize(Monitor *mon, const QDict *qdict);
void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict);
void hmp_drive_mirror(Monitor *mon, const QDict *qdict);
void hmp_drive_backup(Monitor *mon, const QDict *qdict);
void hmp_migrate_cancel(Monitor *mon, const QDict *qdict);
void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict);
void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict);
Expand Down
8 changes: 7 additions & 1 deletion hw/ide/ahci.c
Expand Up @@ -1106,10 +1106,15 @@ static int ahci_dma_add_status(IDEDMA *dma, int status)
}

static int ahci_dma_set_inactive(IDEDMA *dma)
{
return 0;
}

static int ahci_async_cmd_done(IDEDMA *dma)
{
AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);

DPRINTF(ad->port_no, "dma done\n");
DPRINTF(ad->port_no, "async cmd done\n");

/* update d2h status */
ahci_write_fis_d2h(ad, NULL);
Expand Down Expand Up @@ -1144,6 +1149,7 @@ static const IDEDMAOps ahci_dma_ops = {
.set_unit = ahci_dma_set_unit,
.add_status = ahci_dma_add_status,
.set_inactive = ahci_dma_set_inactive,
.async_cmd_done = ahci_async_cmd_done,
.restart_cb = ahci_dma_restart_cb,
.reset = ahci_dma_reset,
};
Expand Down
9 changes: 9 additions & 0 deletions hw/ide/core.c
Expand Up @@ -568,10 +568,18 @@ static void dma_buf_commit(IDEState *s)
qemu_sglist_destroy(&s->sg);
}

static void ide_async_cmd_done(IDEState *s)
{
if (s->bus->dma->ops->async_cmd_done) {
s->bus->dma->ops->async_cmd_done(s->bus->dma);
}
}

void ide_set_inactive(IDEState *s)
{
s->bus->dma->aiocb = NULL;
s->bus->dma->ops->set_inactive(s->bus->dma);
ide_async_cmd_done(s);
}

void ide_dma_error(IDEState *s)
Expand Down Expand Up @@ -804,6 +812,7 @@ static void ide_flush_cb(void *opaque, int ret)

bdrv_acct_done(s->bs, &s->acct);
s->status = READY_STAT | SEEK_STAT;
ide_async_cmd_done(s);
ide_set_irq(s->bus);
}

Expand Down
1 change: 1 addition & 0 deletions hw/ide/internal.h
Expand Up @@ -433,6 +433,7 @@ struct IDEDMAOps {
DMAIntFunc *set_unit;
DMAIntFunc *add_status;
DMAFunc *set_inactive;
DMAFunc *async_cmd_done;
DMARestartFunc *restart_cb;
DMAFunc *reset;
};
Expand Down
5 changes: 3 additions & 2 deletions include/block/block.h
Expand Up @@ -111,7 +111,8 @@ bool bdrv_io_limits_enabled(BlockDriverState *bs);

void bdrv_init(void);
void bdrv_init_with_whitelist(void);
BlockDriver *bdrv_find_protocol(const char *filename);
BlockDriver *bdrv_find_protocol(const char *filename,
bool allow_protocol_prefix);
BlockDriver *bdrv_find_format(const char *format_name);
BlockDriver *bdrv_find_whitelisted_format(const char *format_name,
bool readonly);
Expand Down Expand Up @@ -266,7 +267,7 @@ void bdrv_clear_incoming_migration_all(void);
/* Ensure contents are flushed to disk. */
int bdrv_flush(BlockDriverState *bs);
int coroutine_fn bdrv_co_flush(BlockDriverState *bs);
void bdrv_flush_all(void);
int bdrv_flush_all(void);
void bdrv_close_all(void);
void bdrv_drain_all(void);

Expand Down
4 changes: 2 additions & 2 deletions include/sysemu/sysemu.h
Expand Up @@ -35,8 +35,8 @@ void vm_state_notify(int running, RunState state);
#define VMRESET_REPORT true

void vm_start(void);
void vm_stop(RunState state);
void vm_stop_force_state(RunState state);
int vm_stop(RunState state);
int vm_stop_force_state(RunState state);

typedef enum WakeupReason {
QEMU_WAKEUP_REASON_OTHER = 0,
Expand Down
17 changes: 14 additions & 3 deletions migration.c
Expand Up @@ -527,15 +527,26 @@ static void *migration_thread(void *opaque)
if (pending_size && pending_size >= max_size) {
qemu_savevm_state_iterate(s->file);
} else {
int ret;

DPRINTF("done iterating\n");
qemu_mutex_lock_iothread();
start_time = qemu_get_clock_ms(rt_clock);
qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
old_vm_running = runstate_is_running();
vm_stop_force_state(RUN_STATE_FINISH_MIGRATE);
qemu_file_set_rate_limit(s->file, INT_MAX);
qemu_savevm_state_complete(s->file);

ret = vm_stop_force_state(RUN_STATE_FINISH_MIGRATE);
if (ret >= 0) {
qemu_file_set_rate_limit(s->file, INT_MAX);
qemu_savevm_state_complete(s->file);
}
qemu_mutex_unlock_iothread();

if (ret < 0) {
migrate_finish_set_state(s, MIG_STATE_ERROR);
break;
}

if (!qemu_file_get_error(s->file)) {
migrate_finish_set_state(s, MIG_STATE_COMPLETED);
break;
Expand Down
7 changes: 6 additions & 1 deletion qapi-schema.json
Expand Up @@ -1634,6 +1634,10 @@
# @format: #optional the format of the new destination, default is to
# probe if @mode is 'existing', else the format of the source
#
# @sync: what parts of the disk image should be copied to the destination
# (all the disk, only the sectors allocated in the topmost image, or
# only new I/O).
#
# @mode: #optional whether and how QEMU should create a new image, default is
# 'absolute-paths'.
#
Expand All @@ -1655,7 +1659,8 @@
##
{ 'type': 'DriveBackup',
'data': { 'device': 'str', 'target': 'str', '*format': 'str',
'*mode': 'NewImageMode', '*speed': 'int',
'sync': 'MirrorSyncMode', '*mode': 'NewImageMode',
'*speed': 'int',
'*on-source-error': 'BlockdevOnError',
'*on-target-error': 'BlockdevOnError' } }

Expand Down

0 comments on commit 5699a02

Please sign in to comment.