From 6e2c45d504def8524a85a20dd26c261d19be6e0d Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 16 Jun 2011 08:47:21 -0300 Subject: [RHEL6 qemu-kvm PATCH 05/23] blockdev: Collect block device code in new blockdev.c RH-Author: Markus Armbruster Message-id: <1308214055-31837-5-git-send-email-armbru@redhat.com> Patchwork-id: 27227 O-Subject: [PATCH RHEL-6.2 v2 04/18] blockdev: Collect block device code in new blockdev.c Bugzilla: 627585 RH-Acked-by: Christoph Hellwig RH-Acked-by: Luiz Capitulino RH-Acked-by: Kevin Wolf Anything that moves hundreds of lines out of vl.c can't be all bad. Signed-off-by: Markus Armbruster Signed-off-by: Kevin Wolf (cherry picked from commit 666daa68234b5b1758652633cab07d5ca6046a5b) Conflicts: Makefile.objs hw/acpi_piix4.c hw/ide/core.c hw/pc.c hw/pc_piix.c hw/virtio-blk.c monitor.c sysemu.h vl.c --- Makefile | 1 + blockdev.c | 823 ++++++++++++++++++++++++++++++++++++++++++++++++++ blockdev.h | 86 ++++++ hw/apb_pci.c | 1 + hw/device-hotplug.c | 32 -- hw/fdc.c | 1 - hw/fdc.h | 2 +- hw/ide/core.c | 2 - hw/lan9118.c | 1 + hw/nand.c | 3 +- hw/omap2.c | 2 + hw/onenand.c | 3 +- hw/parallel.c | 1 + hw/pci-hotplug.c | 2 - hw/pcmcia.h | 2 +- hw/qdev-properties.c | 1 - hw/qdev.h | 2 +- hw/scsi-bus.c | 1 - hw/scsi-disk.c | 2 +- hw/scsi-generic.c | 1 - hw/serial.c | 1 + hw/usb-hid.c | 1 + hw/usb-msd.c | 2 +- hw/virtio-blk.c | 2 - hw/virtio-pci.c | 1 - migration.c | 2 +- monitor.c | 213 +------------- qemu-char.c | 1 - savevm.c | 2 +- sysemu.h | 64 ---- vl.c | 566 +---------------------------------- 31 files changed, 928 insertions(+), 896 deletions(-) create mode 100644 blockdev.c create mode 100644 blockdev.h Signed-off-by: Eduardo Habkost --- Makefile | 1 + blockdev.c | 823 ++++++++++++++++++++++++++++++++++++++++++++++++++ blockdev.h | 86 ++++++ hw/apb_pci.c | 1 + hw/device-hotplug.c | 32 -- hw/fdc.c | 1 - hw/fdc.h | 2 +- hw/ide/core.c | 2 - hw/lan9118.c | 1 + hw/nand.c | 3 +- hw/omap2.c | 2 + hw/onenand.c | 3 +- hw/parallel.c | 1 + hw/pci-hotplug.c | 2 - hw/pcmcia.h | 2 +- hw/qdev-properties.c | 1 - hw/qdev.h | 2 +- hw/scsi-bus.c | 1 - hw/scsi-disk.c | 2 +- hw/scsi-generic.c | 1 - hw/serial.c | 1 + hw/usb-hid.c | 1 + hw/usb-msd.c | 2 +- hw/virtio-blk.c | 2 - hw/virtio-pci.c | 1 - migration.c | 2 +- monitor.c | 213 +------------- qemu-char.c | 1 - savevm.c | 2 +- sysemu.h | 64 ---- vl.c | 566 +---------------------------------- 31 files changed, 928 insertions(+), 896 deletions(-) create mode 100644 blockdev.c create mode 100644 blockdev.h diff --git a/Makefile b/Makefile index 63cd006..70a7c7f 100644 --- a/Makefile +++ b/Makefile @@ -155,6 +155,7 @@ shared-obj-y = qemu-error.o $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) obj-y = $(shared-obj-y) obj-y += qemu-thread.o +obj-y += blockdev.o obj-y += $(net-obj-y) obj-y += readline.o console.o cursor.o diff --git a/blockdev.c b/blockdev.c new file mode 100644 index 0000000..16aafa7 --- /dev/null +++ b/blockdev.c @@ -0,0 +1,823 @@ +/* + * QEMU host block devices + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * later. See the COPYING file in the top-level directory. + */ + +#include "block.h" +#include "blockdev.h" +#include "monitor.h" +#include "qerror.h" +#include "qemu-option.h" +#include "qemu-config.h" +#include "sysemu.h" +#include "hw/qdev.h" +#include "block_int.h" + +struct drivelist drives = QTAILQ_HEAD_INITIALIZER(drives); +struct driveoptlist driveopts = QTAILQ_HEAD_INITIALIZER(driveopts); +DriveInfo *extboot_drive = NULL; + +/* + * We automatically delete the drive when a device using it gets + * unplugged. Questionable feature, but we can't just drop it. + * Device models call blockdev_mark_auto_del() to schedule the + * automatic deletion, and generic qdev code calls blockdev_auto_del() + * when deletion is actually safe. + */ +void blockdev_mark_auto_del(BlockDriverState *bs) +{ + DriveInfo *dinfo = drive_get_by_blockdev(bs); + + if (dinfo) { + dinfo->auto_del = 1; + } +} + +void blockdev_auto_del(BlockDriverState *bs) +{ + DriveInfo *dinfo = drive_get_by_blockdev(bs); + + if (dinfo && dinfo->auto_del) { + drive_uninit(dinfo); + } +} + +QemuOpts *drive_add(const char *file, const char *fmt, ...) +{ + va_list ap; + char optstr[1024]; + QemuOpts *opts; + + va_start(ap, fmt); + vsnprintf(optstr, sizeof(optstr), fmt, ap); + va_end(ap); + + opts = qemu_opts_parse(&qemu_drive_opts, optstr, 0); + if (!opts) { + return NULL; + } + if (file) + qemu_opt_set(opts, "file", file); + return opts; +} + +DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit) +{ + DriveInfo *dinfo; + + /* seek interface, bus and unit */ + + QTAILQ_FOREACH(dinfo, &drives, next) { + if (dinfo->type == type && + dinfo->bus == bus && + dinfo->unit == unit) + return dinfo; + } + + return NULL; +} + +DriveInfo *drive_get_by_id(const char *id) +{ + DriveInfo *dinfo; + + QTAILQ_FOREACH(dinfo, &drives, next) { + if (strcmp(id, dinfo->id)) + continue; + return dinfo; + } + return NULL; +} + +int drive_get_max_bus(BlockInterfaceType type) +{ + int max_bus; + DriveInfo *dinfo; + + max_bus = -1; + QTAILQ_FOREACH(dinfo, &drives, next) { + if(dinfo->type == type && + dinfo->bus > max_bus) + max_bus = dinfo->bus; + } + return max_bus; +} + +DriveInfo *drive_get_by_blockdev(BlockDriverState *bs) +{ + DriveInfo *dinfo; + + QTAILQ_FOREACH(dinfo, &drives, next) { + if (dinfo->bdrv == bs) { + return dinfo; + } + } + return NULL; +} + +const char *drive_get_serial(BlockDriverState *bdrv) +{ + DriveInfo *dinfo; + + QTAILQ_FOREACH(dinfo, &drives, next) { + if (dinfo->bdrv == bdrv) + return dinfo->serial; + } + + return "\0"; +} + +BlockInterfaceErrorAction drive_get_on_error( + BlockDriverState *bdrv, int is_read) +{ + DriveInfo *dinfo; + + QTAILQ_FOREACH(dinfo, &drives, next) { + if (dinfo->bdrv == bdrv) + return is_read ? dinfo->on_read_error : dinfo->on_write_error; + } + + return is_read ? BLOCK_ERR_REPORT : BLOCK_ERR_STOP_ENOSPC; +} + +static void bdrv_format_print(void *opaque, const char *name) +{ + fprintf(stderr, " %s", name); +} + +void drive_uninit(DriveInfo *dinfo) +{ + qemu_opts_del(dinfo->opts); + bdrv_delete(dinfo->bdrv); + QTAILQ_REMOVE(&drives, dinfo, next); + qemu_free(dinfo->file); + qemu_free(dinfo); +} + +static int parse_block_error_action(const char *buf, int is_read) +{ + if (!strcmp(buf, "ignore")) { + return BLOCK_ERR_IGNORE; + } else if (!is_read && !strcmp(buf, "enospc")) { + return BLOCK_ERR_STOP_ENOSPC; + } else if (!strcmp(buf, "stop")) { + return BLOCK_ERR_STOP_ANY; + } else if (!strcmp(buf, "report")) { + return BLOCK_ERR_REPORT; + } else { + fprintf(stderr, "qemu: '%s' invalid %s error action\n", + buf, is_read ? "read" : "write"); + return -1; + } +} + +static int drive_open(DriveInfo *dinfo) +{ + int res = bdrv_open(dinfo->bdrv, dinfo->file, dinfo->bdrv_flags, dinfo->drv); + + if (res < 0) { + fprintf(stderr, "qemu: could not open disk image %s: %s\n", + dinfo->file, strerror(-res)); + } + return res; +} + +int drives_reopen(void) +{ + DriveInfo *dinfo; + + QTAILQ_FOREACH(dinfo, &drives, next) { + if (dinfo->opened && !bdrv_is_read_only(dinfo->bdrv)) { + int res; + int media_changed = dinfo->bdrv->media_changed; + bdrv_close(dinfo->bdrv); + res = drive_open(dinfo); + dinfo->bdrv->media_changed = media_changed; + if (res) { + fprintf(stderr, "qemu: re-open of %s failed wth error %d\n", + dinfo->file, res); + return res; + } + } + } + return 0; +} + +DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi, int *fatal_error) +{ + const char *buf; + const char *file = NULL; + char devname[128]; + const char *serial; + const char *mediastr = ""; + BlockInterfaceType type; + enum { MEDIA_DISK, MEDIA_CDROM } media; + int bus_id, unit_id; + int cyls, heads, secs, translation; + BlockDriver *drv = NULL; + int max_devs; + int index; + int ro = 0; + int bdrv_flags = 0; + int on_read_error, on_write_error; + const char *devaddr; + DriveInfo *dinfo; + int is_extboot = 0; + int snapshot = 0; + + *fatal_error = 1; + + translation = BIOS_ATA_TRANSLATION_AUTO; + + if (default_to_scsi) { + type = IF_SCSI; + max_devs = MAX_SCSI_DEVS; + pstrcpy(devname, sizeof(devname), "scsi"); + } else { + type = IF_IDE; + max_devs = MAX_IDE_DEVS; + pstrcpy(devname, sizeof(devname), "ide"); + } + media = MEDIA_DISK; + + /* extract parameters */ + bus_id = qemu_opt_get_number(opts, "bus", 0); + unit_id = qemu_opt_get_number(opts, "unit", -1); + index = qemu_opt_get_number(opts, "index", -1); + + cyls = qemu_opt_get_number(opts, "cyls", 0); + heads = qemu_opt_get_number(opts, "heads", 0); + secs = qemu_opt_get_number(opts, "secs", 0); + + snapshot = qemu_opt_get_bool(opts, "snapshot", 0); + ro = qemu_opt_get_bool(opts, "readonly", 0); + + file = qemu_opt_get(opts, "file"); + serial = qemu_opt_get(opts, "serial"); + + if ((buf = qemu_opt_get(opts, "if")) != NULL) { + pstrcpy(devname, sizeof(devname), buf); + if (!strcmp(buf, "ide")) { + type = IF_IDE; + max_devs = MAX_IDE_DEVS; + } else if (!strcmp(buf, "scsi")) { + type = IF_SCSI; + max_devs = MAX_SCSI_DEVS; + } else if (!strcmp(buf, "floppy")) { + type = IF_FLOPPY; + max_devs = 0; + } else if (!strcmp(buf, "pflash")) { + type = IF_PFLASH; + max_devs = 0; + } else if (!strcmp(buf, "mtd")) { + type = IF_MTD; + max_devs = 0; + } else if (!strcmp(buf, "sd")) { + type = IF_SD; + max_devs = 0; + } else if (!strcmp(buf, "virtio")) { + type = IF_VIRTIO; + max_devs = 0; + } else if (!strcmp(buf, "xen")) { + type = IF_XEN; + max_devs = 0; + } else if (!strcmp(buf, "none")) { + type = IF_NONE; + max_devs = 0; + } else { + fprintf(stderr, "qemu: unsupported bus type '%s'\n", buf); + return NULL; + } + } + + if (cyls || heads || secs) { + if (cyls < 1 || (type == IF_IDE && cyls > 16383)) { + fprintf(stderr, "qemu: '%s' invalid physical cyls number\n", buf); + return NULL; + } + if (heads < 1 || (type == IF_IDE && heads > 16)) { + fprintf(stderr, "qemu: '%s' invalid physical heads number\n", buf); + return NULL; + } + if (secs < 1 || (type == IF_IDE && secs > 63)) { + fprintf(stderr, "qemu: '%s' invalid physical secs number\n", buf); + return NULL; + } + } + + if ((buf = qemu_opt_get(opts, "trans")) != NULL) { + if (!cyls) { + fprintf(stderr, + "qemu: '%s' trans must be used with cyls,heads and secs\n", + buf); + return NULL; + } + if (!strcmp(buf, "none")) + translation = BIOS_ATA_TRANSLATION_NONE; + else if (!strcmp(buf, "lba")) + translation = BIOS_ATA_TRANSLATION_LBA; + else if (!strcmp(buf, "auto")) + translation = BIOS_ATA_TRANSLATION_AUTO; + else { + fprintf(stderr, "qemu: '%s' invalid translation type\n", buf); + return NULL; + } + } + + if ((buf = qemu_opt_get(opts, "media")) != NULL) { + if (!strcmp(buf, "disk")) { + media = MEDIA_DISK; + } else if (!strcmp(buf, "cdrom")) { + if (cyls || secs || heads) { + fprintf(stderr, + "qemu: '%s' invalid physical CHS format\n", buf); + return NULL; + } + media = MEDIA_CDROM; + } else { + fprintf(stderr, "qemu: '%s' invalid media\n", buf); + return NULL; + } + } + + if ((buf = qemu_opt_get(opts, "cache")) != NULL) { + if (!strcmp(buf, "off") || !strcmp(buf, "none")) { + bdrv_flags |= BDRV_O_NOCACHE; + } else if (!strcmp(buf, "writeback")) { + bdrv_flags |= BDRV_O_CACHE_WB; + } else if (!strcmp(buf, "unsafe")) { + bdrv_flags |= BDRV_O_CACHE_WB; + bdrv_flags |= BDRV_O_NO_FLUSH; + } else if (!strcmp(buf, "writethrough")) { + /* this is the default */ + } else { + fprintf(stderr, "qemu: invalid cache option\n"); + return NULL; + } + } + +#ifdef CONFIG_LINUX_AIO + if ((buf = qemu_opt_get(opts, "aio")) != NULL) { + if (!strcmp(buf, "native")) { + bdrv_flags |= BDRV_O_NATIVE_AIO; + } else if (!strcmp(buf, "threads")) { + /* this is the default */ + } else { + fprintf(stderr, "qemu: invalid aio option\n"); + return NULL; + } + } +#endif + + if ((buf = qemu_opt_get(opts, "format")) != NULL) { + if (strcmp(buf, "?") == 0) { + fprintf(stderr, "qemu: Supported formats:"); + bdrv_iterate_format(bdrv_format_print, NULL); + fprintf(stderr, "\n"); + return NULL; + } + drv = bdrv_find_whitelisted_format(buf); + if (!drv) { + fprintf(stderr, "qemu: '%s' invalid format\n", buf); + return NULL; + } + } + + is_extboot = qemu_opt_get_bool(opts, "boot", 0); + if (is_extboot && extboot_drive) { + fprintf(stderr, "qemu: two bootable drives specified\n"); + return NULL; + } + + on_write_error = BLOCK_ERR_STOP_ENOSPC; + if ((buf = qemu_opt_get(opts, "werror")) != NULL) { + if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO && type != IF_NONE) { + fprintf(stderr, "werror is no supported by this format\n"); + return NULL; + } + + on_write_error = parse_block_error_action(buf, 0); + if (on_write_error < 0) { + return NULL; + } + } + + on_read_error = BLOCK_ERR_REPORT; + if ((buf = qemu_opt_get(opts, "rerror")) != NULL) { + if (type != IF_IDE && type != IF_VIRTIO && type != IF_NONE) { + fprintf(stderr, "rerror is no supported by this format\n"); + return NULL; + } + + on_read_error = parse_block_error_action(buf, 1); + if (on_read_error < 0) { + return NULL; + } + } + + if ((devaddr = qemu_opt_get(opts, "addr")) != NULL) { + if (type != IF_VIRTIO) { + fprintf(stderr, "addr is not supported\n"); + return NULL; + } + } + + /* compute bus and unit according index */ + + if (index != -1) { + if (bus_id != 0 || unit_id != -1) { + fprintf(stderr, + "qemu: index cannot be used with bus and unit\n"); + return NULL; + } + if (max_devs == 0) + { + unit_id = index; + bus_id = 0; + } else { + unit_id = index % max_devs; + bus_id = index / max_devs; + } + } + + /* if user doesn't specify a unit_id, + * try to find the first free + */ + + if (unit_id == -1) { + unit_id = 0; + while (drive_get(type, bus_id, unit_id) != NULL) { + unit_id++; + if (max_devs && unit_id >= max_devs) { + unit_id -= max_devs; + bus_id++; + } + } + } + + /* check unit id */ + + if (max_devs && unit_id >= max_devs) { + fprintf(stderr, "qemu: unit %d too big (max is %d)\n", + unit_id, max_devs - 1); + return NULL; + } + + /* + * ignore multiple definitions + */ + + if (drive_get(type, bus_id, unit_id) != NULL) { + *fatal_error = 0; + return NULL; + } + + /* init */ + + dinfo = qemu_mallocz(sizeof(*dinfo)); + if ((buf = qemu_opts_id(opts)) != NULL) { + dinfo->id = qemu_strdup(buf); + } else { + /* no id supplied -> create one */ + dinfo->id = qemu_mallocz(32); + if (type == IF_IDE || type == IF_SCSI) + mediastr = (media == MEDIA_CDROM) ? "-cd" : "-hd"; + if (max_devs) + snprintf(dinfo->id, 32, "%s%i%s%i", + devname, bus_id, mediastr, unit_id); + else + snprintf(dinfo->id, 32, "%s%s%i", + devname, mediastr, unit_id); + } + dinfo->bdrv = bdrv_new(dinfo->id); + dinfo->devaddr = devaddr; + dinfo->type = type; + dinfo->bus = bus_id; + dinfo->unit = unit_id; + dinfo->on_read_error = on_read_error; + dinfo->on_write_error = on_write_error; + dinfo->opts = opts; + if (serial) + strncpy(dinfo->serial, serial, sizeof(dinfo->serial) - 1); + QTAILQ_INSERT_TAIL(&drives, dinfo, next); + if (is_extboot) { + extboot_drive = dinfo; + } + + switch(type) { + case IF_IDE: + 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: + bdrv_set_type_hint(dinfo->bdrv, BDRV_TYPE_CDROM); + break; + } + break; + case IF_SD: + /* FIXME: This isn't really a floppy, but it's a reasonable + approximation. */ + case IF_FLOPPY: + bdrv_set_type_hint(dinfo->bdrv, BDRV_TYPE_FLOPPY); + break; + case IF_PFLASH: + case IF_MTD: + break; + case IF_VIRTIO: + /* add virtio block device */ + opts = qemu_opts_create(&qemu_device_opts, NULL, 0); + qemu_opt_set(opts, "driver", "virtio-blk-pci"); + qemu_opt_set(opts, "drive", dinfo->id); + if (devaddr) + qemu_opt_set(opts, "addr", devaddr); + break; + case IF_COUNT: + abort(); + } + if (!file) { + *fatal_error = 0; + return NULL; + } + if (snapshot) { + /* always use write-back with snapshot */ + bdrv_flags &= ~BDRV_O_CACHE_MASK; + bdrv_flags |= (BDRV_O_SNAPSHOT|BDRV_O_CACHE_WB); + } + + if (media == MEDIA_CDROM) { + /* mark CDROM as read-only. CDROM is fine for any interface, don't check */ + ro = 1; + } else if (ro == 1) { + if (type != IF_SCSI && type != IF_VIRTIO && type != IF_FLOPPY && type != IF_NONE) { + fprintf(stderr, "qemu: readonly flag not supported for drive with this interface\n"); + return NULL; + } + } + bdrv_flags |= ro ? 0 : BDRV_O_RDWR; + + dinfo->file = qemu_strdup(file); + dinfo->bdrv_flags = bdrv_flags; + dinfo->drv = drv; + dinfo->opened = 1; + + if (drive_open(dinfo) < 0) { + *fatal_error = 1; + return NULL; + } + + if (bdrv_key_required(dinfo->bdrv)) + autostart = 0; + *fatal_error = 0; + return dinfo; +} + +void do_commit(Monitor *mon, const QDict *qdict) +{ + int all_devices; + DriveInfo *dinfo; + const char *device = qdict_get_str(qdict, "device"); + + all_devices = !strcmp(device, "all"); + QTAILQ_FOREACH(dinfo, &drives, next) { + if (!all_devices) + if (strcmp(bdrv_get_device_name(dinfo->bdrv), device)) + continue; + bdrv_commit(dinfo->bdrv); + } +} + +int do_snapshot_blkdev(Monitor *mon, const QDict *qdict, QObject **ret_data) +{ + const char *device = qdict_get_str(qdict, "device"); + const char *filename = qdict_get_try_str(qdict, "snapshot_file"); + const char *format = qdict_get_try_str(qdict, "format"); + BlockDriverState *bs; + BlockDriver *drv, *old_drv, *proto_drv; + int ret = 0; + int flags; + char old_filename[1024]; + + if (!filename) { + qerror_report(QERR_MISSING_PARAMETER, "snapshot_file"); + ret = -1; + goto out; + } + + bs = bdrv_find(device); + if (!bs) { + qerror_report(QERR_DEVICE_NOT_FOUND, device); + ret = -1; + goto out; + } + + pstrcpy(old_filename, sizeof(old_filename), bs->filename); + + old_drv = bs->drv; + flags = bs->open_flags; + + if (!format) { + format = "qcow2"; + } + + drv = bdrv_find_format(format); + if (!drv) { + qerror_report(QERR_INVALID_BLOCK_FORMAT, format); + ret = -1; + goto out; + } + + proto_drv = bdrv_find_protocol(filename); + if (!proto_drv) { + qerror_report(QERR_INVALID_BLOCK_FORMAT, format); + ret = -1; + goto out; + } + + ret = bdrv_img_create(filename, format, bs->filename, + bs->drv->format_name, NULL, -1, flags); + if (ret) { + goto out; + } + + qemu_aio_flush(); + bdrv_flush(bs); + + bdrv_close(bs); + ret = bdrv_open(bs, filename, 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) { + qerror_report(QERR_OPEN_FILE_FAILED, old_filename); + } else { + qerror_report(QERR_OPEN_FILE_FAILED, filename); + } + } +out: + if (ret) { + ret = -1; + } + + return ret; +} + +static int eject_device(Monitor *mon, BlockDriverState *bs, int force) +{ + if (!force) { + if (!bdrv_is_removable(bs)) { + qerror_report(QERR_DEVICE_NOT_REMOVABLE, + bdrv_get_device_name(bs)); + return -1; + } + if (bdrv_is_locked(bs)) { + qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs)); + return -1; + } + } + bdrv_close(bs); + return 0; +} + +int do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data) +{ + BlockDriverState *bs; + int force = qdict_get_int(qdict, "force"); + const char *filename = qdict_get_str(qdict, "device"); + + bs = bdrv_find(filename); + if (!bs) { + qerror_report(QERR_DEVICE_NOT_FOUND, filename); + return -1; + } + return eject_device(mon, bs, force); +} + +int do_block_set_passwd(Monitor *mon, const QDict *qdict, + QObject **ret_data) +{ + BlockDriverState *bs; + int err; + + bs = bdrv_find(qdict_get_str(qdict, "device")); + if (!bs) { + qerror_report(QERR_DEVICE_NOT_FOUND, qdict_get_str(qdict, "device")); + return -1; + } + + err = bdrv_set_key(bs, qdict_get_str(qdict, "password")); + if (err == -EINVAL) { + qerror_report(QERR_DEVICE_NOT_ENCRYPTED, bdrv_get_device_name(bs)); + return -1; + } else if (err < 0) { + qerror_report(QERR_INVALID_PASSWORD); + return -1; + } + + return 0; +} + +int do_change_block(Monitor *mon, const char *device, + const char *filename, const char *fmt) +{ + BlockDriverState *bs; + BlockDriver *drv = NULL; + int bdrv_flags; + + bs = bdrv_find(device); + if (!bs) { + qerror_report(QERR_DEVICE_NOT_FOUND, device); + return -1; + } + if (fmt) { + drv = bdrv_find_whitelisted_format(fmt); + if (!drv) { + qerror_report(QERR_INVALID_BLOCK_FORMAT, fmt); + return -1; + } + } + if (eject_device(mon, bs, 0) < 0) { + return -1; + } + bdrv_flags = bdrv_get_type_hint(bs) == BDRV_TYPE_CDROM ? 0 : BDRV_O_RDWR; + bdrv_flags |= bdrv_is_snapshot(bs) ? BDRV_O_SNAPSHOT : 0; + if (bdrv_open(bs, filename, bdrv_flags, drv)) { + qerror_report(QERR_OPEN_FILE_FAILED, filename); + return -1; + } + return monitor_read_bdrv_key_start(mon, bs, NULL, NULL); +} + +int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data) +{ + const char *id = qdict_get_str(qdict, "id"); + BlockDriverState *bs; + + bs = bdrv_find(id); + if (!bs) { + qerror_report(QERR_DEVICE_NOT_FOUND, id); + return -1; + } + + /* quiesce block driver; prevent further io */ + qemu_aio_flush(); + bdrv_flush(bs); + bdrv_close(bs); + + /* if we have a device associated with this BlockDriverState (bs->peer) + * then we need to make the drive anonymous until the device + * can be removed. If this is a drive with no device backing + * then we can just get rid of the block driver state right here. + */ + if (bs->peer) { + bdrv_make_anon(bs); + } else { + drive_uninit(drive_get_by_blockdev(bs)); + } + + return 0; +} + +/* + * XXX: replace the QERR_UNDEFINED_ERROR errors with real values once the + * existing QERR_ macro mess is cleaned up. A good example for better + * error reports can be found in the qemu-img resize code. + */ +int do_block_resize(Monitor *mon, const QDict *qdict, QObject **ret_data) +{ + const char *device = qdict_get_str(qdict, "device"); + int64_t size = qdict_get_int(qdict, "size"); + BlockDriverState *bs; + + bs = bdrv_find(device); + if (!bs) { + qerror_report(QERR_DEVICE_NOT_FOUND, device); + return -1; + } + + if (size < 0) { + qerror_report(QERR_UNDEFINED_ERROR); + return -1; + } + + if (bdrv_truncate(bs, size)) { + qerror_report(QERR_UNDEFINED_ERROR); + return -1; + } + + return 0; +} diff --git a/blockdev.h b/blockdev.h new file mode 100644 index 0000000..bc48cc3 --- /dev/null +++ b/blockdev.h @@ -0,0 +1,86 @@ +/* + * QEMU host block devices + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * later. See the COPYING file in the top-level directory. + */ + +#ifndef BLOCKDEV_H +#define BLOCKDEV_H + +#include "block.h" +#include "qemu-queue.h" + +void blockdev_mark_auto_del(BlockDriverState *bs); +void blockdev_auto_del(BlockDriverState *bs); + +#define BLOCK_SERIAL_STRLEN 20 + +typedef enum { + IF_NONE, + IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD, IF_VIRTIO, IF_XEN, + IF_COUNT +} BlockInterfaceType; + +typedef enum { + BLOCK_ERR_REPORT, BLOCK_ERR_IGNORE, BLOCK_ERR_STOP_ENOSPC, + BLOCK_ERR_STOP_ANY +} BlockInterfaceErrorAction; + +typedef struct DriveInfo { + BlockDriverState *bdrv; + char *id; + const char *devaddr; + BlockInterfaceType type; + int bus; + int unit; + int auto_del; /* see blockdev_mark_auto_del() */ + QemuOpts *opts; + BlockInterfaceErrorAction on_read_error; + BlockInterfaceErrorAction on_write_error; + char serial[BLOCK_SERIAL_STRLEN + 1]; + QTAILQ_ENTRY(DriveInfo) next; + int opened; + int bdrv_flags; + char *file; + BlockDriver *drv; +} DriveInfo; + +#define MAX_IDE_DEVS 2 +#define MAX_SCSI_DEVS 7 + +extern QTAILQ_HEAD(drivelist, DriveInfo) drives; +extern QTAILQ_HEAD(driveoptlist, DriveOpt) driveopts; +extern DriveInfo *extboot_drive; + +extern DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit); +extern DriveInfo *drive_get_by_id(const char *id); +extern int drive_get_max_bus(BlockInterfaceType type); +extern void drive_uninit(DriveInfo *dinfo); +extern DriveInfo *drive_get_by_blockdev(BlockDriverState *bs); +extern const char *drive_get_serial(BlockDriverState *bdrv); + +extern BlockInterfaceErrorAction drive_get_on_error( + BlockDriverState *bdrv, int is_read); + +extern QemuOpts *drive_add(const char *file, const char *fmt, ...); +extern DriveInfo *drive_init(QemuOpts *arg, int default_to_scsi, + int *fatal_error); + +extern int drives_reopen(void); + +/* device-hotplug */ + +DriveInfo *add_init_drive(const char *opts); + +void do_commit(Monitor *mon, const QDict *qdict); +int do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data); +int do_block_set_passwd(Monitor *mon, const QDict *qdict, QObject **ret_data); +int do_change_block(Monitor *mon, const char *device, + const char *filename, const char *fmt); +int simple_drive_add(Monitor *mon, const QDict *qdict, QObject **ret_data); +int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data); + +#endif diff --git a/hw/apb_pci.c b/hw/apb_pci.c index fe8faa6..588dc6e 100644 --- a/hw/apb_pci.c +++ b/hw/apb_pci.c @@ -30,6 +30,7 @@ #include "pci.h" #include "pci_host.h" #include "apb_pci.h" +#include "sysemu.h" /* debug APB */ //#define DEBUG_APB diff --git a/hw/device-hotplug.c b/hw/device-hotplug.c index 8705654..a6d3867 100644 --- a/hw/device-hotplug.c +++ b/hw/device-hotplug.c @@ -26,8 +26,6 @@ #include "boards.h" #include "qerror.h" #include "net.h" -#include "block_int.h" -#include "sysemu.h" DriveInfo *add_init_drive(const char *optstr) { @@ -110,33 +108,3 @@ int simple_drive_add(Monitor *mon, const QDict *qdict, QObject **ret_data) return 0; } - -int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data) -{ - const char *id = qdict_get_str(qdict, "id"); - BlockDriverState *bs; - - bs = bdrv_find(id); - if (!bs) { - qerror_report(QERR_DEVICE_NOT_FOUND, id); - return -1; - } - - /* quiesce block driver; prevent further io */ - qemu_aio_flush(); - bdrv_flush(bs); - bdrv_close(bs); - - /* if we have a device associated with this BlockDriverState (bs->peer) - * then we need to make the drive anonymous until the device - * can be removed. If this is a drive with no device backing - * then we can just get rid of the block driver state right here. - */ - if (bs->peer) { - bdrv_make_anon(bs); - } else { - drive_uninit(drive_get_by_blockdev(bs)); - } - - return 0; -} diff --git a/hw/fdc.c b/hw/fdc.c index e78d76b..4848bb2 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -29,7 +29,6 @@ #include "hw.h" #include "fdc.h" -#include "block.h" #include "qemu-timer.h" #include "isa.h" #include "sysbus.h" diff --git a/hw/fdc.h b/hw/fdc.h index c64e8b4..6c84aa4 100644 --- a/hw/fdc.h +++ b/hw/fdc.h @@ -1,5 +1,5 @@ /* fdc.c */ -#include "sysemu.h" +#include "blockdev.h" #define MAX_FD 2 typedef struct fdctrl_t fdctrl_t; diff --git a/hw/ide/core.c b/hw/ide/core.c index 3e133f1..07141bb 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -27,8 +27,6 @@ #include #include #include -#include "block.h" -#include "block_int.h" #include "qemu-error.h" #include "qemu-timer.h" #include "sysemu.h" diff --git a/hw/lan9118.c b/hw/lan9118.c index ba982d1..ec2a43e 100644 --- a/hw/lan9118.c +++ b/hw/lan9118.c @@ -10,6 +10,7 @@ #include "sysbus.h" #include "net.h" #include "devices.h" +#include "sysemu.h" /* For crc32 */ #include diff --git a/hw/nand.c b/hw/nand.c index 8b34f14..b54caff 100644 --- a/hw/nand.c +++ b/hw/nand.c @@ -13,9 +13,8 @@ # include "hw.h" # include "flash.h" -# include "block.h" +# include "blockdev.h" /* FIXME: Pass block device as an argument. */ -# include "sysemu.h" # define NAND_CMD_READ0 0x00 # define NAND_CMD_READ1 0x01 diff --git a/hw/omap2.c b/hw/omap2.c index 05ef7f7..f26fb9f 100644 --- a/hw/omap2.c +++ b/hw/omap2.c @@ -17,6 +17,8 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see . */ + +#include "blockdev.h" #include "hw.h" #include "arm-misc.h" #include "omap.h" diff --git a/hw/onenand.c b/hw/onenand.c index 40390ad..f7afeca 100644 --- a/hw/onenand.c +++ b/hw/onenand.c @@ -21,8 +21,7 @@ #include "qemu-common.h" #include "flash.h" #include "irq.h" -#include "sysemu.h" -#include "block.h" +#include "blockdev.h" /* 11 for 2kB-page OneNAND ("2nd generation") and 10 for 1kB-page chips */ #define PAGE_SHIFT 11 diff --git a/hw/parallel.c b/hw/parallel.c index 57d9f94..8402c62 100644 --- a/hw/parallel.c +++ b/hw/parallel.c @@ -26,6 +26,7 @@ #include "qemu-char.h" #include "isa.h" #include "pc.h" +#include "sysemu.h" //#define DEBUG_PARALLEL diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c index bf34747..4d429c7 100644 --- a/hw/pci-hotplug.c +++ b/hw/pci-hotplug.c @@ -26,10 +26,8 @@ #include "boards.h" #include "pci.h" #include "net.h" -#include "sysemu.h" #include "pc.h" #include "monitor.h" -#include "block_int.h" #include "scsi.h" #include "virtio-blk.h" #include "qemu-config.h" diff --git a/hw/pcmcia.h b/hw/pcmcia.h index cf2db9d..3602923 100644 --- a/hw/pcmcia.h +++ b/hw/pcmcia.h @@ -1,7 +1,7 @@ /* PCMCIA/Cardbus */ #include "qemu-common.h" -#include "sysemu.h" +#include "blockdev.h" typedef struct { qemu_irq irq; diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c index a84a6f3..5491276 100644 --- a/hw/qdev-properties.c +++ b/hw/qdev-properties.c @@ -1,4 +1,3 @@ -#include "sysemu.h" #include "net.h" #include "qdev.h" #include "qerror.h" diff --git a/hw/qdev.h b/hw/qdev.h index 24072cd..06a3b2e 100644 --- a/hw/qdev.h +++ b/hw/qdev.h @@ -2,7 +2,7 @@ #define QDEV_H #include "hw.h" -#include "sysemu.h" +#include "blockdev.h" #include "qemu-queue.h" #include "qemu-char.h" #include "qemu-option.h" diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index 3848ff2..2bb7c70 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -2,7 +2,6 @@ #include "qemu-error.h" #include "scsi.h" #include "scsi-defs.h" -#include "block.h" #include "qdev.h" static char *scsibus_get_fw_dev_path(DeviceState *dev); diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 78445ac..2391e23 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -33,9 +33,9 @@ do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0) #include "qemu-common.h" #include "qemu-error.h" -#include "block.h" #include "scsi.h" #include "scsi-defs.h" +#include "sysemu.h" #define SCSI_DMA_BUF_SIZE 131072 #define SCSI_MAX_INQUIRY_LEN 256 diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index 7dc800d..3915e78 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -13,7 +13,6 @@ #include "qemu-common.h" #include "qemu-error.h" -#include "block.h" #include "scsi.h" #ifdef __linux__ diff --git a/hw/serial.c b/hw/serial.c index 44a2810..29151e9 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -27,6 +27,7 @@ #include "isa.h" #include "pc.h" #include "qemu-timer.h" +#include "sysemu.h" //#define DEBUG_SERIAL diff --git a/hw/usb-hid.c b/hw/usb-hid.c index 449cd6c..3bb77b3 100644 --- a/hw/usb-hid.c +++ b/hw/usb-hid.c @@ -25,6 +25,7 @@ #include "hw.h" #include "console.h" #include "usb.h" +#include "sysemu.h" /* HID interface requests */ #define GET_REPORT 0xa101 diff --git a/hw/usb-msd.c b/hw/usb-msd.c index 7ca2a0c..4cf4ce3 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -11,10 +11,10 @@ #include "qemu-option.h" #include "qemu-config.h" #include "usb.h" -#include "block.h" #include "scsi.h" #include "console.h" #include "monitor.h" +#include "sysemu.h" //#define DEBUG_MSD diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index 8329bf3..7e97e83 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -12,10 +12,8 @@ */ #include -#include #include "trace.h" #include "virtio-blk.h" -#include "block_int.h" #ifdef __linux__ # include #endif diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index 3098d34..d1a0c84 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -23,7 +23,6 @@ #include "qemu-error.h" #include "msix.h" #include "net.h" -#include "block_int.h" #include "loader.h" #include "kvm.h" diff --git a/migration.c b/migration.c index bba30d9..515f697 100644 --- a/migration.c +++ b/migration.c @@ -16,7 +16,7 @@ #include "monitor.h" #include "buffered_file.h" #include "sysemu.h" -#include "block.h" +#include "blockdev.h" #include "qemu_socket.h" #include "block-migration.h" #include "qemu-objects.h" diff --git a/monitor.c b/monitor.c index b9c5423..ef6fd6a 100644 --- a/monitor.c +++ b/monitor.c @@ -39,8 +39,7 @@ #include "monitor.h" #include "readline.h" #include "console.h" -#include "block.h" -#include "block_int.h" +#include "blockdev.h" #include "audio/audio.h" #include "disas.h" #include "balloon.h" @@ -597,21 +596,6 @@ static void do_help_cmd(Monitor *mon, const QDict *qdict) help_cmd(mon, qdict_get_try_str(qdict, "name")); } -static void do_commit(Monitor *mon, const QDict *qdict) -{ - int all_devices; - DriveInfo *dinfo; - const char *device = qdict_get_str(qdict, "device"); - - all_devices = !strcmp(device, "all"); - QTAILQ_FOREACH(dinfo, &drives, next) { - if (!all_devices) - if (strcmp(bdrv_get_device_name(dinfo->bdrv), device)) - continue; - bdrv_commit(dinfo->bdrv); - } -} - static void user_monitor_complete(void *opaque, QObject *ret_data) { MonitorCompletionData *data = (MonitorCompletionData *)opaque; @@ -1047,201 +1031,6 @@ static int do_quit(Monitor *mon, const QDict *qdict, QObject **ret_data) return 0; } -int do_snapshot_blkdev(Monitor *mon, const QDict *qdict, QObject **ret_data) -{ - const char *device = qdict_get_str(qdict, "device"); - const char *filename = qdict_get_try_str(qdict, "snapshot_file"); - const char *format = qdict_get_try_str(qdict, "format"); - BlockDriverState *bs; - BlockDriver *drv, *old_drv, *proto_drv; - int ret = 0; - int flags; - char old_filename[1024]; - - if (!filename) { - qerror_report(QERR_MISSING_PARAMETER, "snapshot_file"); - ret = -1; - goto out; - } - - bs = bdrv_find(device); - if (!bs) { - qerror_report(QERR_DEVICE_NOT_FOUND, device); - ret = -1; - goto out; - } - - pstrcpy(old_filename, sizeof(old_filename), bs->filename); - - old_drv = bs->drv; - flags = bs->open_flags; - - if (!format) { - format = "qcow2"; - } - - drv = bdrv_find_format(format); - if (!drv) { - qerror_report(QERR_INVALID_BLOCK_FORMAT, format); - ret = -1; - goto out; - } - - proto_drv = bdrv_find_protocol(filename); - if (!proto_drv) { - qerror_report(QERR_INVALID_BLOCK_FORMAT, format); - ret = -1; - goto out; - } - - ret = bdrv_img_create(filename, format, bs->filename, - bs->drv->format_name, NULL, -1, flags); - if (ret) { - goto out; - } - - qemu_aio_flush(); - bdrv_flush(bs); - - bdrv_close(bs); - ret = bdrv_open(bs, filename, 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) { - qerror_report(QERR_OPEN_FILE_FAILED, old_filename); - } else { - qerror_report(QERR_OPEN_FILE_FAILED, filename); - } - } -out: - if (ret) { - ret = -1; - } - - return ret; -} - -/* - * XXX: replace the QERR_UNDEFINED_ERROR errors with real values once the - * existing QERR_ macro mess is cleaned up. A good example for better - * error reports can be found in the qemu-img resize code. - */ -int do_block_resize(Monitor *mon, const QDict *qdict, QObject **ret_data) -{ - const char *device = qdict_get_str(qdict, "device"); - int64_t size = qdict_get_int(qdict, "size"); - BlockDriverState *bs; - - bs = bdrv_find(device); - if (!bs) { - qerror_report(QERR_DEVICE_NOT_FOUND, device); - return -1; - } - - if (size < 0) { - qerror_report(QERR_UNDEFINED_ERROR); - return -1; - } - - if (bdrv_truncate(bs, size)) { - qerror_report(QERR_UNDEFINED_ERROR); - return -1; - } - - return 0; -} - -static int eject_device(Monitor *mon, BlockDriverState *bs, int force) -{ - if (!force) { - if (!bdrv_is_removable(bs)) { - qerror_report(QERR_DEVICE_NOT_REMOVABLE, - bdrv_get_device_name(bs)); - return -1; - } - if (bdrv_is_locked(bs)) { - qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs)); - return -1; - } - } - bdrv_close(bs); - return 0; -} - -static int do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data) -{ - BlockDriverState *bs; - int force = qdict_get_int(qdict, "force"); - const char *filename = qdict_get_str(qdict, "device"); - - bs = bdrv_find(filename); - if (!bs) { - qerror_report(QERR_DEVICE_NOT_FOUND, filename); - return -1; - } - return eject_device(mon, bs, force); -} - -static int do_block_set_passwd(Monitor *mon, const QDict *qdict, - QObject **ret_data) -{ - BlockDriverState *bs; - int err; - - bs = bdrv_find(qdict_get_str(qdict, "device")); - if (!bs) { - qerror_report(QERR_DEVICE_NOT_FOUND, qdict_get_str(qdict, "device")); - return -1; - } - - err = bdrv_set_key(bs, qdict_get_str(qdict, "password")); - if (err == -EINVAL) { - qerror_report(QERR_DEVICE_NOT_ENCRYPTED, bdrv_get_device_name(bs)); - return -1; - } else if (err < 0) { - qerror_report(QERR_INVALID_PASSWORD); - return -1; - } - - return 0; -} - -static int do_change_block(Monitor *mon, const char *device, - const char *filename, const char *fmt) -{ - BlockDriverState *bs; - BlockDriver *drv = NULL; - int bdrv_flags; - - bs = bdrv_find(device); - if (!bs) { - qerror_report(QERR_DEVICE_NOT_FOUND, device); - return -1; - } - if (fmt) { - drv = bdrv_find_whitelisted_format(fmt); - if (!drv) { - qerror_report(QERR_INVALID_BLOCK_FORMAT, fmt); - return -1; - } - } - if (eject_device(mon, bs, 0) < 0) { - return -1; - } - bdrv_flags = bdrv_get_type_hint(bs) == BDRV_TYPE_CDROM ? 0 : BDRV_O_RDWR; - bdrv_flags |= bdrv_is_snapshot(bs) ? BDRV_O_SNAPSHOT : 0; - if (bdrv_open(bs, filename, bdrv_flags, drv)) { - qerror_report(QERR_OPEN_FILE_FAILED, filename); - return -1; - } - return monitor_read_bdrv_key_start(mon, bs, NULL, NULL); -} - static int change_vnc_password(const char *password) { if (vnc_display_password(NULL, password) < 0) { diff --git a/qemu-char.c b/qemu-char.c index 38148a0..b11752a 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -28,7 +28,6 @@ #include "sysemu.h" #include "qemu-timer.h" #include "qemu-char.h" -#include "block.h" #include "hw/usb.h" #include "hw/baum.h" #include "hw/msmouse.h" diff --git a/savevm.c b/savevm.c index e85e630..9205e51 100644 --- a/savevm.c +++ b/savevm.c @@ -78,7 +78,7 @@ #include "sysemu.h" #include "qemu-timer.h" #include "qemu-char.h" -#include "block.h" +#include "blockdev.h" #include "audio/audio.h" #include "migration.h" #include "qemu_socket.h" diff --git a/sysemu.h b/sysemu.h index e7e9b1e..b84a2a2 100644 --- a/sysemu.h +++ b/sysemu.h @@ -158,73 +158,9 @@ extern unsigned int nb_prom_envs; #endif #endif -typedef enum { - IF_NONE, - IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD, IF_VIRTIO, IF_XEN, - IF_COUNT -} BlockInterfaceType; - -typedef enum { - BLOCK_ERR_REPORT, BLOCK_ERR_IGNORE, BLOCK_ERR_STOP_ENOSPC, - BLOCK_ERR_STOP_ANY -} BlockInterfaceErrorAction; - -void blockdev_mark_auto_del(BlockDriverState *bs); -void blockdev_auto_del(BlockDriverState *bs); - -#define BLOCK_SERIAL_STRLEN 20 - -typedef struct DriveInfo { - BlockDriverState *bdrv; - char *id; - const char *devaddr; - BlockInterfaceType type; - int bus; - int unit; - int auto_del; /* see blockdev_mark_auto_del() */ - QemuOpts *opts; - BlockInterfaceErrorAction on_read_error; - BlockInterfaceErrorAction on_write_error; - char serial[BLOCK_SERIAL_STRLEN + 1]; - QTAILQ_ENTRY(DriveInfo) next; - int opened; - int bdrv_flags; - char *file; - BlockDriver *drv; -} DriveInfo; - -#define MAX_IDE_DEVS 2 -#define MAX_SCSI_DEVS 7 - -extern QTAILQ_HEAD(drivelist, DriveInfo) drives; -extern QTAILQ_HEAD(driveoptlist, DriveOpt) driveopts; -extern DriveInfo *extboot_drive; - -extern DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit); -extern DriveInfo *drive_get_by_id(const char *id); -extern int drive_get_max_bus(BlockInterfaceType type); -extern void drive_uninit(DriveInfo *dinfo); -extern DriveInfo *drive_get_by_blockdev(BlockDriverState *bs); -extern const char *drive_get_serial(BlockDriverState *bdrv); - -extern BlockInterfaceErrorAction drive_get_on_error( - BlockDriverState *bdrv, int is_read); - -extern QemuOpts *drive_add(const char *file, const char *fmt, ...); -extern DriveInfo *drive_init(QemuOpts *arg, int default_to_scsi, - int *fatal_error); - -extern int drives_reopen(void); - /* acpi */ void qemu_system_cpu_hot_add(int cpu, int state); -/* device-hotplug */ - -DriveInfo *add_init_drive(const char *opts); -int simple_drive_add(Monitor *mon, const QDict *qdict, QObject **ret_data); -int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data); - /* pci-hotplug */ void pci_device_hot_add(Monitor *mon, const QDict *qdict); void drive_hot_add(Monitor *mon, const QDict *qdict); diff --git a/vl.c b/vl.c index 158a584..20c1190 100644 --- a/vl.c +++ b/vl.c @@ -147,7 +147,7 @@ int main(int argc, char **argv) #include "qemu-char.h" #include "cache-utils.h" #include "block.h" -#include "block_int.h" +#include "blockdev.h" #include "block-migration.h" #include "dma.h" #include "audio/audio.h" @@ -185,9 +185,6 @@ int main(int argc, char **argv) static const char *data_dir; const char *bios_name = NULL; -struct drivelist drives = QTAILQ_HEAD_INITIALIZER(drives); -struct driveoptlist driveopts = QTAILQ_HEAD_INITIALIZER(driveopts); -DriveInfo *extboot_drive = NULL; enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB; static DisplayState *display_state; DisplayType display_type = DT_DEFAULT; @@ -2083,567 +2080,6 @@ static int bt_parse(const char *opt) #define MTD_ALIAS "if=mtd" #define SD_ALIAS "index=0,if=sd" -QemuOpts *drive_add(const char *file, const char *fmt, ...) -{ - va_list ap; - char optstr[1024]; - QemuOpts *opts; - - va_start(ap, fmt); - vsnprintf(optstr, sizeof(optstr), fmt, ap); - va_end(ap); - - opts = qemu_opts_parse(&qemu_drive_opts, optstr, 0); - if (!opts) { - return NULL; - } - if (file) - qemu_opt_set(opts, "file", file); - return opts; -} - -DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit) -{ - DriveInfo *dinfo; - - /* seek interface, bus and unit */ - - QTAILQ_FOREACH(dinfo, &drives, next) { - if (dinfo->type == type && - dinfo->bus == bus && - dinfo->unit == unit) - return dinfo; - } - - return NULL; -} - -DriveInfo *drive_get_by_id(const char *id) -{ - DriveInfo *dinfo; - - QTAILQ_FOREACH(dinfo, &drives, next) { - if (strcmp(id, dinfo->id)) - continue; - return dinfo; - } - return NULL; -} - -DriveInfo *drive_get_by_blockdev(BlockDriverState *bs) -{ - DriveInfo *dinfo; - - QTAILQ_FOREACH(dinfo, &drives, next) { - if (dinfo->bdrv == bs) { - return dinfo; - } - } - return NULL; -} - -/* - * We automatically delete the drive when a device using it gets - * unplugged. Questionable feature, but we can't just drop it. - * Device models call blockdev_mark_auto_del() to schedule the - * automatic deletion, and generic qdev code calls blockdev_auto_del() - * when deletion is actually safe. - */ -void blockdev_mark_auto_del(BlockDriverState *bs) -{ - DriveInfo *dinfo = drive_get_by_blockdev(bs); - - if (dinfo) { - dinfo->auto_del = 1; - } -} - -void blockdev_auto_del(BlockDriverState *bs) -{ - DriveInfo *dinfo = drive_get_by_blockdev(bs); - - if (dinfo && dinfo->auto_del) { - drive_uninit(dinfo); - } -} - -int drive_get_max_bus(BlockInterfaceType type) -{ - int max_bus; - DriveInfo *dinfo; - - max_bus = -1; - QTAILQ_FOREACH(dinfo, &drives, next) { - if(dinfo->type == type && - dinfo->bus > max_bus) - max_bus = dinfo->bus; - } - return max_bus; -} - -const char *drive_get_serial(BlockDriverState *bdrv) -{ - DriveInfo *dinfo; - - QTAILQ_FOREACH(dinfo, &drives, next) { - if (dinfo->bdrv == bdrv) - return dinfo->serial; - } - - return "\0"; -} - -BlockInterfaceErrorAction drive_get_on_error( - BlockDriverState *bdrv, int is_read) -{ - DriveInfo *dinfo; - - QTAILQ_FOREACH(dinfo, &drives, next) { - if (dinfo->bdrv == bdrv) - return is_read ? dinfo->on_read_error : dinfo->on_write_error; - } - - return is_read ? BLOCK_ERR_REPORT : BLOCK_ERR_STOP_ENOSPC; -} - -static void bdrv_format_print(void *opaque, const char *name) -{ - fprintf(stderr, " %s", name); -} - -void drive_uninit(DriveInfo *dinfo) -{ - qemu_opts_del(dinfo->opts); - bdrv_delete(dinfo->bdrv); - QTAILQ_REMOVE(&drives, dinfo, next); - qemu_free(dinfo->file); - qemu_free(dinfo); -} - -static int parse_block_error_action(const char *buf, int is_read) -{ - if (!strcmp(buf, "ignore")) { - return BLOCK_ERR_IGNORE; - } else if (!is_read && !strcmp(buf, "enospc")) { - return BLOCK_ERR_STOP_ENOSPC; - } else if (!strcmp(buf, "stop")) { - return BLOCK_ERR_STOP_ANY; - } else if (!strcmp(buf, "report")) { - return BLOCK_ERR_REPORT; - } else { - fprintf(stderr, "qemu: '%s' invalid %s error action\n", - buf, is_read ? "read" : "write"); - return -1; - } -} - -static int drive_open(DriveInfo *dinfo) -{ - int res = bdrv_open(dinfo->bdrv, dinfo->file, dinfo->bdrv_flags, dinfo->drv); - - if (res < 0) { - fprintf(stderr, "qemu: could not open disk image %s: %s\n", - dinfo->file, strerror(-res)); - } - return res; -} - -int drives_reopen(void) -{ - DriveInfo *dinfo; - - QTAILQ_FOREACH(dinfo, &drives, next) { - if (dinfo->opened && !bdrv_is_read_only(dinfo->bdrv)) { - int res; - int media_changed = dinfo->bdrv->media_changed; - bdrv_close(dinfo->bdrv); - res = drive_open(dinfo); - dinfo->bdrv->media_changed = media_changed; - if (res) { - fprintf(stderr, "qemu: re-open of %s failed wth error %d\n", - dinfo->file, res); - return res; - } - } - } - return 0; -} - -DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi, int *fatal_error) -{ - const char *buf; - const char *file = NULL; - char devname[128]; - const char *serial; - const char *mediastr = ""; - BlockInterfaceType type; - enum { MEDIA_DISK, MEDIA_CDROM } media; - int bus_id, unit_id; - int cyls, heads, secs, translation; - BlockDriver *drv = NULL; - int max_devs; - int index; - int ro = 0; - int bdrv_flags = 0; - int on_read_error, on_write_error; - const char *devaddr; - DriveInfo *dinfo; - int is_extboot = 0; - int snapshot = 0; - - *fatal_error = 1; - - translation = BIOS_ATA_TRANSLATION_AUTO; - - if (default_to_scsi) { - type = IF_SCSI; - max_devs = MAX_SCSI_DEVS; - pstrcpy(devname, sizeof(devname), "scsi"); - } else { - type = IF_IDE; - max_devs = MAX_IDE_DEVS; - pstrcpy(devname, sizeof(devname), "ide"); - } - media = MEDIA_DISK; - - /* extract parameters */ - bus_id = qemu_opt_get_number(opts, "bus", 0); - unit_id = qemu_opt_get_number(opts, "unit", -1); - index = qemu_opt_get_number(opts, "index", -1); - - cyls = qemu_opt_get_number(opts, "cyls", 0); - heads = qemu_opt_get_number(opts, "heads", 0); - secs = qemu_opt_get_number(opts, "secs", 0); - - snapshot = qemu_opt_get_bool(opts, "snapshot", 0); - ro = qemu_opt_get_bool(opts, "readonly", 0); - - file = qemu_opt_get(opts, "file"); - serial = qemu_opt_get(opts, "serial"); - - if ((buf = qemu_opt_get(opts, "if")) != NULL) { - pstrcpy(devname, sizeof(devname), buf); - if (!strcmp(buf, "ide")) { - type = IF_IDE; - max_devs = MAX_IDE_DEVS; - } else if (!strcmp(buf, "scsi")) { - type = IF_SCSI; - max_devs = MAX_SCSI_DEVS; - } else if (!strcmp(buf, "floppy")) { - type = IF_FLOPPY; - max_devs = 0; - } else if (!strcmp(buf, "pflash")) { - type = IF_PFLASH; - max_devs = 0; - } else if (!strcmp(buf, "mtd")) { - type = IF_MTD; - max_devs = 0; - } else if (!strcmp(buf, "sd")) { - type = IF_SD; - max_devs = 0; - } else if (!strcmp(buf, "virtio")) { - type = IF_VIRTIO; - max_devs = 0; - } else if (!strcmp(buf, "xen")) { - type = IF_XEN; - max_devs = 0; - } else if (!strcmp(buf, "none")) { - type = IF_NONE; - max_devs = 0; - } else { - fprintf(stderr, "qemu: unsupported bus type '%s'\n", buf); - return NULL; - } - } - - if (cyls || heads || secs) { - if (cyls < 1 || (type == IF_IDE && cyls > 16383)) { - fprintf(stderr, "qemu: '%s' invalid physical cyls number\n", buf); - return NULL; - } - if (heads < 1 || (type == IF_IDE && heads > 16)) { - fprintf(stderr, "qemu: '%s' invalid physical heads number\n", buf); - return NULL; - } - if (secs < 1 || (type == IF_IDE && secs > 63)) { - fprintf(stderr, "qemu: '%s' invalid physical secs number\n", buf); - return NULL; - } - } - - if ((buf = qemu_opt_get(opts, "trans")) != NULL) { - if (!cyls) { - fprintf(stderr, - "qemu: '%s' trans must be used with cyls,heads and secs\n", - buf); - return NULL; - } - if (!strcmp(buf, "none")) - translation = BIOS_ATA_TRANSLATION_NONE; - else if (!strcmp(buf, "lba")) - translation = BIOS_ATA_TRANSLATION_LBA; - else if (!strcmp(buf, "auto")) - translation = BIOS_ATA_TRANSLATION_AUTO; - else { - fprintf(stderr, "qemu: '%s' invalid translation type\n", buf); - return NULL; - } - } - - if ((buf = qemu_opt_get(opts, "media")) != NULL) { - if (!strcmp(buf, "disk")) { - media = MEDIA_DISK; - } else if (!strcmp(buf, "cdrom")) { - if (cyls || secs || heads) { - fprintf(stderr, - "qemu: '%s' invalid physical CHS format\n", buf); - return NULL; - } - media = MEDIA_CDROM; - } else { - fprintf(stderr, "qemu: '%s' invalid media\n", buf); - return NULL; - } - } - - if ((buf = qemu_opt_get(opts, "cache")) != NULL) { - if (!strcmp(buf, "off") || !strcmp(buf, "none")) { - bdrv_flags |= BDRV_O_NOCACHE; - } else if (!strcmp(buf, "writeback")) { - bdrv_flags |= BDRV_O_CACHE_WB; - } else if (!strcmp(buf, "unsafe")) { - bdrv_flags |= BDRV_O_CACHE_WB; - bdrv_flags |= BDRV_O_NO_FLUSH; - } else if (!strcmp(buf, "writethrough")) { - /* this is the default */ - } else { - fprintf(stderr, "qemu: invalid cache option\n"); - return NULL; - } - } - -#ifdef CONFIG_LINUX_AIO - if ((buf = qemu_opt_get(opts, "aio")) != NULL) { - if (!strcmp(buf, "native")) { - bdrv_flags |= BDRV_O_NATIVE_AIO; - } else if (!strcmp(buf, "threads")) { - /* this is the default */ - } else { - fprintf(stderr, "qemu: invalid aio option\n"); - return NULL; - } - } -#endif - - if ((buf = qemu_opt_get(opts, "format")) != NULL) { - if (strcmp(buf, "?") == 0) { - fprintf(stderr, "qemu: Supported formats:"); - bdrv_iterate_format(bdrv_format_print, NULL); - fprintf(stderr, "\n"); - return NULL; - } - drv = bdrv_find_whitelisted_format(buf); - if (!drv) { - fprintf(stderr, "qemu: '%s' invalid format\n", buf); - return NULL; - } - } - - is_extboot = qemu_opt_get_bool(opts, "boot", 0); - if (is_extboot && extboot_drive) { - fprintf(stderr, "qemu: two bootable drives specified\n"); - return NULL; - } - - on_write_error = BLOCK_ERR_STOP_ENOSPC; - if ((buf = qemu_opt_get(opts, "werror")) != NULL) { - if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO && type != IF_NONE) { - fprintf(stderr, "werror is no supported by this format\n"); - return NULL; - } - - on_write_error = parse_block_error_action(buf, 0); - if (on_write_error < 0) { - return NULL; - } - } - - on_read_error = BLOCK_ERR_REPORT; - if ((buf = qemu_opt_get(opts, "rerror")) != NULL) { - if (type != IF_IDE && type != IF_VIRTIO && type != IF_NONE) { - fprintf(stderr, "rerror is no supported by this format\n"); - return NULL; - } - - on_read_error = parse_block_error_action(buf, 1); - if (on_read_error < 0) { - return NULL; - } - } - - if ((devaddr = qemu_opt_get(opts, "addr")) != NULL) { - if (type != IF_VIRTIO) { - fprintf(stderr, "addr is not supported\n"); - return NULL; - } - } - - /* compute bus and unit according index */ - - if (index != -1) { - if (bus_id != 0 || unit_id != -1) { - fprintf(stderr, - "qemu: index cannot be used with bus and unit\n"); - return NULL; - } - if (max_devs == 0) - { - unit_id = index; - bus_id = 0; - } else { - unit_id = index % max_devs; - bus_id = index / max_devs; - } - } - - /* if user doesn't specify a unit_id, - * try to find the first free - */ - - if (unit_id == -1) { - unit_id = 0; - while (drive_get(type, bus_id, unit_id) != NULL) { - unit_id++; - if (max_devs && unit_id >= max_devs) { - unit_id -= max_devs; - bus_id++; - } - } - } - - /* check unit id */ - - if (max_devs && unit_id >= max_devs) { - fprintf(stderr, "qemu: unit %d too big (max is %d)\n", - unit_id, max_devs - 1); - return NULL; - } - - /* - * ignore multiple definitions - */ - - if (drive_get(type, bus_id, unit_id) != NULL) { - *fatal_error = 0; - return NULL; - } - - /* init */ - - dinfo = qemu_mallocz(sizeof(*dinfo)); - if ((buf = qemu_opts_id(opts)) != NULL) { - dinfo->id = qemu_strdup(buf); - } else { - /* no id supplied -> create one */ - dinfo->id = qemu_mallocz(32); - if (type == IF_IDE || type == IF_SCSI) - mediastr = (media == MEDIA_CDROM) ? "-cd" : "-hd"; - if (max_devs) - snprintf(dinfo->id, 32, "%s%i%s%i", - devname, bus_id, mediastr, unit_id); - else - snprintf(dinfo->id, 32, "%s%s%i", - devname, mediastr, unit_id); - } - dinfo->bdrv = bdrv_new(dinfo->id); - dinfo->devaddr = devaddr; - dinfo->type = type; - dinfo->bus = bus_id; - dinfo->unit = unit_id; - dinfo->on_read_error = on_read_error; - dinfo->on_write_error = on_write_error; - dinfo->opts = opts; - if (serial) - strncpy(dinfo->serial, serial, sizeof(dinfo->serial) - 1); - QTAILQ_INSERT_TAIL(&drives, dinfo, next); - if (is_extboot) { - extboot_drive = dinfo; - } - - switch(type) { - case IF_IDE: - 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: - bdrv_set_type_hint(dinfo->bdrv, BDRV_TYPE_CDROM); - break; - } - break; - case IF_SD: - /* FIXME: This isn't really a floppy, but it's a reasonable - approximation. */ - case IF_FLOPPY: - bdrv_set_type_hint(dinfo->bdrv, BDRV_TYPE_FLOPPY); - break; - case IF_PFLASH: - case IF_MTD: - break; - case IF_VIRTIO: - /* add virtio block device */ - opts = qemu_opts_create(&qemu_device_opts, NULL, 0); - qemu_opt_set(opts, "driver", "virtio-blk-pci"); - qemu_opt_set(opts, "drive", dinfo->id); - if (devaddr) - qemu_opt_set(opts, "addr", devaddr); - break; - case IF_COUNT: - abort(); - } - if (!file) { - *fatal_error = 0; - return NULL; - } - if (snapshot) { - /* always use write-back with snapshot */ - bdrv_flags &= ~BDRV_O_CACHE_MASK; - bdrv_flags |= (BDRV_O_SNAPSHOT|BDRV_O_CACHE_WB); - } - - if (media == MEDIA_CDROM) { - /* mark CDROM as read-only. CDROM is fine for any interface, don't check */ - ro = 1; - } else if (ro == 1) { - if (type != IF_SCSI && type != IF_VIRTIO && type != IF_FLOPPY && type != IF_NONE) { - fprintf(stderr, "qemu: readonly flag not supported for drive with this interface\n"); - return NULL; - } - } - bdrv_flags |= ro ? 0 : BDRV_O_RDWR; - - dinfo->file = qemu_strdup(file); - dinfo->bdrv_flags = bdrv_flags; - dinfo->drv = drv; - dinfo->opened = 1; - - if (drive_open(dinfo) < 0) { - *fatal_error = 1; - return NULL; - } - - if (bdrv_key_required(dinfo->bdrv)) - autostart = 0; - *fatal_error = 0; - return dinfo; -} - static int drive_init_func(QemuOpts *opts, void *opaque) { int *use_scsi = opaque; -- 1.7.3.2