* later. See the COPYING file in the top-level directory.
*/
-#include "block.h"
#include "blockdev.h"
+#include "hw/block-common.h"
#include "monitor.h"
#include "qerror.h"
#include "qemu-option.h"
{
DriveInfo *dinfo = drive_get_by_blockdev(bs);
+ if (bs->job) {
+ block_job_cancel(bs->job);
+ }
if (dinfo) {
dinfo->auto_del = 1;
}
{
const char *buf;
const char *file = NULL;
- char devname[128];
const char *serial;
const char *mediastr = "";
BlockInterfaceType type;
serial = qemu_opt_get(opts, "serial");
if ((buf = qemu_opt_get(opts, "if")) != NULL) {
- pstrcpy(devname, sizeof(devname), buf);
for (type = 0; type < IF_COUNT && strcmp(buf, if_name[type]); type++)
;
if (type == IF_COUNT) {
}
} else {
type = default_to_scsi ? IF_SCSI : IF_IDE;
- pstrcpy(devname, sizeof(devname), if_name[type]);
}
max_devs = if_max_devs[type];
if (cyls || heads || secs) {
- if (cyls < 1 || (type == IF_IDE && cyls > 16383)) {
+ if (cyls < 1) {
error_report("invalid physical cyls number");
return NULL;
}
- if (heads < 1 || (type == IF_IDE && heads > 16)) {
+ if (heads < 1) {
error_report("invalid physical heads number");
return NULL;
}
- if (secs < 1 || (type == IF_IDE && secs > 63)) {
+ if (secs < 1) {
error_report("invalid physical secs number");
return NULL;
}
mediastr = (media == MEDIA_CDROM) ? "-cd" : "-hd";
if (max_devs)
snprintf(dinfo->id, 32, "%s%i%s%i",
- devname, bus_id, mediastr, unit_id);
+ if_name[type], bus_id, mediastr, unit_id);
else
snprintf(dinfo->id, 32, "%s%s%i",
- devname, mediastr, unit_id);
+ if_name[type], mediastr, unit_id);
}
dinfo->bdrv = bdrv_new(dinfo->id);
dinfo->devaddr = devaddr;
dinfo->type = type;
dinfo->bus = bus_id;
dinfo->unit = unit_id;
+ dinfo->cyls = cyls;
+ dinfo->heads = heads;
+ dinfo->secs = secs;
+ dinfo->trans = translation;
dinfo->opts = opts;
dinfo->refcount = 1;
- if (serial)
- strncpy(dinfo->serial, serial, sizeof(dinfo->serial) - 1);
+ dinfo->serial = serial;
QTAILQ_INSERT_TAIL(&drives, dinfo, next);
bdrv_set_on_error(dinfo->bdrv, on_read_error, on_write_error);
case IF_SCSI:
case IF_XEN:
case IF_NONE:
- switch(media) {
- case MEDIA_DISK:
- if (cyls != 0) {
- bdrv_set_geometry_hint(dinfo->bdrv, cyls, heads, secs);
- bdrv_set_translation_hint(dinfo->bdrv, translation);
- }
- break;
- case MEDIA_CDROM:
- dinfo->media_cd = 1;
- break;
- }
+ dinfo->media_cd = media == MEDIA_CDROM;
break;
case IF_SD:
case IF_FLOPPY:
break;
case IF_VIRTIO:
/* add virtio block device */
- opts = qemu_opts_create(qemu_find_opts("device"), NULL, 0);
+ opts = qemu_opts_create(qemu_find_opts("device"), NULL, 0, NULL);
if (arch_type == QEMU_ARCH_S390X) {
qemu_opt_set(opts, "driver", "virtio-blk-s390");
} else {
bdrv_flags |= BDRV_O_COPY_ON_READ;
}
+ if (runstate_check(RUN_STATE_INMIGRATE)) {
+ bdrv_flags |= BDRV_O_INCOMING;
+ }
+
if (media == MEDIA_CDROM) {
/* CDROM is fine for any interface, don't check. */
ro = 1;
bdrv_flags |= ro ? 0 : BDRV_O_RDWR;
+ if (ro && copy_on_read) {
+ error_report("warning: disabling copy_on_read on readonly drive");
+ }
+
ret = bdrv_open(dinfo->bdrv, file, bdrv_flags, drv);
if (ret < 0) {
error_report("could not open disk image %s: %s",
{
const char *device = qdict_get_str(qdict, "device");
BlockDriverState *bs;
+ int ret;
if (!strcmp(device, "all")) {
- bdrv_commit_all();
+ ret = bdrv_commit_all();
+ if (ret == -EBUSY) {
+ qerror_report(QERR_DEVICE_IN_USE, device);
+ return;
+ }
} else {
- int ret;
-
bs = bdrv_find(device);
if (!bs) {
qerror_report(QERR_DEVICE_NOT_FOUND, device);
}
}
+static void blockdev_do_action(int kind, void *data, Error **errp)
+{
+ BlockdevAction action;
+ BlockdevActionList list;
+
+ action.kind = kind;
+ action.data = data;
+ list.value = &action;
+ list.next = NULL;
+ qmp_transaction(&list, errp);
+}
+
void qmp_blockdev_snapshot_sync(const char *device, const char *snapshot_file,
bool has_format, const char *format,
+ bool has_mode, enum NewImageMode mode,
Error **errp)
{
- BlockDriverState *bs;
- BlockDriver *drv, *old_drv, *proto_drv;
- int ret = 0;
- int flags;
- char old_filename[1024];
-
- bs = bdrv_find(device);
- if (!bs) {
- error_set(errp, QERR_DEVICE_NOT_FOUND, device);
- return;
- }
- if (bdrv_in_use(bs)) {
- error_set(errp, QERR_DEVICE_IN_USE, device);
- return;
- }
-
- pstrcpy(old_filename, sizeof(old_filename), bs->filename);
-
- old_drv = bs->drv;
- flags = bs->open_flags;
-
- if (!has_format) {
- format = "qcow2";
- }
-
- drv = bdrv_find_format(format);
- if (!drv) {
- error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
- return;
- }
-
- proto_drv = bdrv_find_protocol(snapshot_file);
- if (!proto_drv) {
- error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
- return;
- }
-
- ret = bdrv_img_create(snapshot_file, format, bs->filename,
- bs->drv->format_name, NULL, -1, flags);
- if (ret) {
- error_set(errp, QERR_UNDEFINED_ERROR);
- return;
- }
-
- bdrv_drain_all();
- bdrv_flush(bs);
-
- bdrv_close(bs);
- ret = bdrv_open(bs, snapshot_file, flags, drv);
- /*
- * If reopening the image file we just created fails, fall back
- * and try to re-open the original image. If that fails too, we
- * are in serious trouble.
- */
- if (ret != 0) {
- ret = bdrv_open(bs, old_filename, flags, old_drv);
- if (ret != 0) {
- error_set(errp, QERR_OPEN_FILE_FAILED, old_filename);
- } else {
- error_set(errp, QERR_OPEN_FILE_FAILED, snapshot_file);
- }
- }
+ BlockdevSnapshot snapshot = {
+ .device = (char *) device,
+ .snapshot_file = (char *) snapshot_file,
+ .has_format = has_format,
+ .format = (char *) format,
+ .has_mode = has_mode,
+ .mode = mode,
+ };
+ blockdev_do_action(BLOCKDEV_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC, &snapshot,
+ errp);
}
/* New and old BlockDriverState structs for group snapshots */
-typedef struct BlkGroupSnapshotStates {
+typedef struct BlkTransactionStates {
BlockDriverState *old_bs;
BlockDriverState *new_bs;
- QSIMPLEQ_ENTRY(BlkGroupSnapshotStates) entry;
-} BlkGroupSnapshotStates;
+ QSIMPLEQ_ENTRY(BlkTransactionStates) entry;
+} BlkTransactionStates;
/*
* 'Atomic' group snapshots. The snapshots are taken as a set, and if any fail
* then we do not pivot any of the devices in the group, and abandon the
* snapshots
*/
-void qmp_blockdev_group_snapshot_sync(SnapshotDevList *dev_list,
- Error **errp)
+void qmp_transaction(BlockdevActionList *dev_list, Error **errp)
{
int ret = 0;
- SnapshotDevList *dev_entry = dev_list;
- SnapshotDev *dev_info = NULL;
- BlkGroupSnapshotStates *states;
- BlockDriver *proto_drv;
- BlockDriver *drv;
- int flags;
- const char *format;
- const char *snapshot_file;
-
- QSIMPLEQ_HEAD(snap_bdrv_states, BlkGroupSnapshotStates) snap_bdrv_states;
+ BlockdevActionList *dev_entry = dev_list;
+ BlkTransactionStates *states, *next;
+
+ QSIMPLEQ_HEAD(snap_bdrv_states, BlkTransactionStates) snap_bdrv_states;
QSIMPLEQ_INIT(&snap_bdrv_states);
/* drain all i/o before any snapshots */
/* We don't do anything in this loop that commits us to the snapshot */
while (NULL != dev_entry) {
+ BlockdevAction *dev_info = NULL;
+ BlockDriver *proto_drv;
+ BlockDriver *drv;
+ int flags;
+ enum NewImageMode mode;
+ const char *new_image_file;
+ const char *device;
+ const char *format = "qcow2";
+
dev_info = dev_entry->value;
dev_entry = dev_entry->next;
- states = g_malloc0(sizeof(BlkGroupSnapshotStates));
+ states = g_malloc0(sizeof(BlkTransactionStates));
QSIMPLEQ_INSERT_TAIL(&snap_bdrv_states, states, entry);
- states->old_bs = bdrv_find(dev_info->device);
+ switch (dev_info->kind) {
+ case BLOCKDEV_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC:
+ device = dev_info->blockdev_snapshot_sync->device;
+ if (!dev_info->blockdev_snapshot_sync->has_mode) {
+ dev_info->blockdev_snapshot_sync->mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
+ }
+ new_image_file = dev_info->blockdev_snapshot_sync->snapshot_file;
+ if (dev_info->blockdev_snapshot_sync->has_format) {
+ format = dev_info->blockdev_snapshot_sync->format;
+ }
+ mode = dev_info->blockdev_snapshot_sync->mode;
+ break;
+ default:
+ abort();
+ }
+ drv = bdrv_find_format(format);
+ if (!drv) {
+ error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
+ goto delete_and_fail;
+ }
+
+ states->old_bs = bdrv_find(device);
if (!states->old_bs) {
- error_set(errp, QERR_DEVICE_NOT_FOUND, dev_info->device);
+ error_set(errp, QERR_DEVICE_NOT_FOUND, device);
goto delete_and_fail;
}
- if (bdrv_in_use(states->old_bs)) {
- error_set(errp, QERR_DEVICE_IN_USE, dev_info->device);
+ if (!bdrv_is_inserted(states->old_bs)) {
+ error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
goto delete_and_fail;
}
- if (!bdrv_is_read_only(states->old_bs) &&
- bdrv_is_inserted(states->old_bs)) {
+ if (bdrv_in_use(states->old_bs)) {
+ error_set(errp, QERR_DEVICE_IN_USE, device);
+ goto delete_and_fail;
+ }
+ if (!bdrv_is_read_only(states->old_bs)) {
if (bdrv_flush(states->old_bs)) {
error_set(errp, QERR_IO_ERROR);
goto delete_and_fail;
}
}
- snapshot_file = dev_info->snapshot_file;
-
flags = states->old_bs->open_flags;
- if (!dev_info->has_format) {
- format = "qcow2";
- } else {
- format = dev_info->format;
- }
-
- drv = bdrv_find_format(format);
- if (!drv) {
- error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
- goto delete_and_fail;
- }
-
- proto_drv = bdrv_find_protocol(snapshot_file);
+ proto_drv = bdrv_find_protocol(new_image_file);
if (!proto_drv) {
error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
goto delete_and_fail;
}
/* create new image w/backing file */
- ret = bdrv_img_create(snapshot_file, format,
- states->old_bs->filename,
- states->old_bs->drv->format_name,
- NULL, -1, flags);
- if (ret) {
- error_set(errp, QERR_OPEN_FILE_FAILED, snapshot_file);
- goto delete_and_fail;
+ if (mode != NEW_IMAGE_MODE_EXISTING) {
+ ret = bdrv_img_create(new_image_file, format,
+ states->old_bs->filename,
+ states->old_bs->drv->format_name,
+ NULL, -1, flags);
+ if (ret) {
+ error_set(errp, QERR_OPEN_FILE_FAILED, new_image_file);
+ goto delete_and_fail;
+ }
}
/* We will manually add the backing_hd field to the bs later */
states->new_bs = bdrv_new("");
- ret = bdrv_open(states->new_bs, snapshot_file,
+ ret = bdrv_open(states->new_bs, new_image_file,
flags | BDRV_O_NO_BACKING, drv);
if (ret != 0) {
- error_set(errp, QERR_OPEN_FILE_FAILED, snapshot_file);
+ error_set(errp, QERR_OPEN_FILE_FAILED, new_image_file);
goto delete_and_fail;
}
}
}
}
exit:
- QSIMPLEQ_FOREACH(states, &snap_bdrv_states, entry) {
+ QSIMPLEQ_FOREACH_SAFE(states, &snap_bdrv_states, entry, next) {
g_free(states);
}
return;
}
void qmp_block_stream(const char *device, bool has_base,
- const char *base, Error **errp)
+ const char *base, bool has_speed,
+ int64_t speed, Error **errp)
{
BlockDriverState *bs;
BlockDriverState *base_bs = NULL;
- int ret;
+ Error *local_err = NULL;
bs = bdrv_find(device);
if (!bs) {
}
}
- ret = stream_start(bs, base_bs, base, block_stream_cb, bs);
- if (ret < 0) {
- switch (ret) {
- case -EBUSY:
- error_set(errp, QERR_DEVICE_IN_USE, device);
- return;
- default:
- error_set(errp, QERR_NOT_SUPPORTED);
- return;
- }
+ stream_start(bs, base_bs, base, has_speed ? speed : 0,
+ block_stream_cb, bs, &local_err);
+ if (error_is_set(&local_err)) {
+ error_propagate(errp, local_err);
+ return;
}
/* Grab a reference so hotplug does not delete the BlockDriverState from
return bs->job;
}
-void qmp_block_job_set_speed(const char *device, int64_t value, Error **errp)
+void qmp_block_job_set_speed(const char *device, int64_t speed, Error **errp)
{
BlockJob *job = find_block_job(device);
return;
}
- if (block_job_set_speed(job, value) < 0) {
- error_set(errp, QERR_NOT_SUPPORTED);
- }
+ block_job_set_speed(job, speed, errp);
}
void qmp_block_job_cancel(const char *device, Error **errp)