[libvirt] [PATCH] qemu: Check for ejected media during startup and migration
Michal Privoznik
mprivozn at redhat.com
Fri Sep 16 15:29:47 UTC 2011
On 13.09.2011 18:14, Michal Privoznik wrote:
> If the daemon is restarted so we reconnect to monitor, cdrom media
> can be ejected. In that case we don't want to show it in domain xml,
> or require it on migration destination.
>
> To check for disk status use 'info block' monitor command.
> ---
> NB, the 'info block' is currently not updated yet. The qemu patches
> that extend the monitor command are in a queue (that will be merged
> quickly):
> http://repo.or.cz/w/qemu/kevin.git
> head for-anthony
> The commit that introduce requested feature:
> http://repo.or.cz/w/qemu/kevin.git/commitdiff/e4def80b36231e161b91fa984cd0d73b45668f00
>
> src/qemu/qemu_conf.h | 6 +++
> src/qemu/qemu_driver.c | 7 +++
> src/qemu/qemu_hotplug.c | 31 ++++++++++++++
> src/qemu/qemu_hotplug.h | 2 +
> src/qemu/qemu_monitor.c | 19 +++++++++
> src/qemu/qemu_monitor.h | 4 ++
> src/qemu/qemu_monitor_json.c | 89 +++++++++++++++++++++++++++++++++++++++++
> src/qemu/qemu_monitor_json.h | 3 +
> src/qemu/qemu_monitor_text.c | 90 ++++++++++++++++++++++++++++++++++++++++++
> src/qemu/qemu_monitor_text.h | 3 +
> src/qemu/qemu_process.c | 3 +
> 11 files changed, 257 insertions(+), 0 deletions(-)
>
> diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
> index e8b92a4..ff5cf23 100644
> --- a/src/qemu/qemu_conf.h
> +++ b/src/qemu/qemu_conf.h
> @@ -165,4 +165,10 @@ void qemuDriverUnlock(struct qemud_driver *driver);
> int qemudLoadDriverConfig(struct qemud_driver *driver,
> const char *filename);
>
> +struct qemuDomainDiskInfo {
> + bool removable;
> + bool locked;
> + bool tray_open;
> +};
> +
> #endif /* __QEMUD_CONF_H */
> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index b94d1c4..b10a56f 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c
> @@ -8236,6 +8236,13 @@ qemuDomainMigrateBegin3(virDomainPtr domain,
> goto endjob;
> }
>
> + /* Check if there is and ejected media.
> + * We don't want to require them on the destination.
> + */
> +
> + if (qemuDomainCheckEjectableMedia(driver, vm) < 0)
> + goto endjob;
> +
> if (!(xml = qemuMigrationBegin(driver, vm, xmlin,
> cookieout, cookieoutlen)))
> goto endjob;
> diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
> index 6cfe392..91ac78a 100644
> --- a/src/qemu/qemu_hotplug.c
> +++ b/src/qemu/qemu_hotplug.c
> @@ -150,6 +150,37 @@ error:
> return -1;
> }
>
> +int
> +qemuDomainCheckEjectableMedia(struct qemud_driver *driver,
> + virDomainObjPtr vm)
> +{
> + qemuDomainObjPrivatePtr priv = vm->privateData;
> + int ret = -1;
> + int i;
> +
> + for (i = 0; i < vm->def->ndisks; i++) {
> + virDomainDiskDefPtr disk = vm->def->disks[i];
> + struct qemuDomainDiskInfo info;
> +
> + memset(&info, 0, sizeof(info));
> +
> + qemuDomainObjEnterMonitor(driver, vm);
> + if (qemuMonitorGetBlockInfo(priv->mon, disk->info.alias, &info) < 0) {
> + qemuDomainObjExitMonitor(driver, vm);
> + goto cleanup;
> + }
> + qemuDomainObjExitMonitor(driver, vm);
> +
> + if (info.tray_open && disk->src)
> + VIR_FREE(disk->src);
> + }
> +
> + ret = 0;
> +
> +cleanup:
> + return ret;
> +}
> +
>
> int qemuDomainAttachPciDiskDevice(struct qemud_driver *driver,
> virDomainObjPtr vm,
> diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h
> index 65d1d30..aaaed88 100644
> --- a/src/qemu/qemu_hotplug.h
> +++ b/src/qemu/qemu_hotplug.h
> @@ -31,6 +31,8 @@ int qemuDomainChangeEjectableMedia(struct qemud_driver *driver,
> virDomainObjPtr vm,
> virDomainDiskDefPtr disk,
> bool force);
> +int qemuDomainCheckEjectableMedia(struct qemud_driver *driver,
> + virDomainObjPtr vm);
> int qemuDomainAttachPciDiskDevice(struct qemud_driver *driver,
> virDomainObjPtr vm,
> virDomainDiskDefPtr disk);
> diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
> index fca8fa4..7005564 100644
> --- a/src/qemu/qemu_monitor.c
> +++ b/src/qemu/qemu_monitor.c
> @@ -1215,6 +1215,25 @@ int qemuMonitorGetMemoryStats(qemuMonitorPtr mon,
> return ret;
> }
>
> +int qemuMonitorGetBlockInfo(qemuMonitorPtr mon,
> + const char *devname,
> + struct qemuDomainDiskInfo *info)
> +{
> + int ret;
> +
> + VIR_DEBUG("mon=%p dev=%p info=%p", mon, devname, info);
> + if (!mon) {
> + qemuReportError(VIR_ERR_INVALID_ARG, "%s",
> + _("monitor must not be NULL"));
> + return -1;
> + }
> +
> + if (mon->json)
> + ret = qemuMonitorJSONGetBlockInfo(mon, devname, info);
> + else
> + ret = qemuMonitorTextGetBlockInfo(mon, devname, info);
> + return ret;
> +}
>
> int qemuMonitorGetBlockStatsInfo(qemuMonitorPtr mon,
> const char *devname,
> diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
> index 390eeff..a05d548 100644
> --- a/src/qemu/qemu_monitor.h
> +++ b/src/qemu/qemu_monitor.h
> @@ -28,6 +28,7 @@
> # include "internal.h"
>
> # include "domain_conf.h"
> +# include "qemu_conf.h"
> # include "hash.h"
>
> typedef struct _qemuMonitor qemuMonitor;
> @@ -212,6 +213,9 @@ int qemuMonitorGetBalloonInfo(qemuMonitorPtr mon,
> int qemuMonitorGetMemoryStats(qemuMonitorPtr mon,
> virDomainMemoryStatPtr stats,
> unsigned int nr_stats);
> +int qemuMonitorGetBlockInfo(qemuMonitorPtr mon,
> + const char *devname,
> + struct qemuDomainDiskInfo *info);
> int qemuMonitorGetBlockStatsInfo(qemuMonitorPtr mon,
> const char *devname,
> long long *rd_req,
> diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
> index 3a81ec8..812a78e 100644
> --- a/src/qemu/qemu_monitor_json.c
> +++ b/src/qemu/qemu_monitor_json.c
> @@ -1337,6 +1337,95 @@ cleanup:
> }
>
>
> +int qemuMonitorJSONGetBlockInfo(qemuMonitorPtr mon,
> + const char *devname,
> + struct qemuDomainDiskInfo *info)
> +{
> + int ret = 0;
> + bool found = false;
> + int i;
> +
> + virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("query-block",
> + NULL);
> + virJSONValuePtr reply = NULL;
> + virJSONValuePtr devices;
> +
> + ret = qemuMonitorJSONCommand(mon, cmd, &reply);
> + if (ret == 0)
> + ret = qemuMonitorJSONCheckError(cmd, reply);
> + if (ret < 0)
> + goto cleanup;
> +
> + ret = -1;
> +
> + devices = virJSONValueObjectGet(reply, "return");
> + if (!devices || devices->type != VIR_JSON_TYPE_ARRAY) {
> + qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("block info reply was missing device list"));
> + goto cleanup;
> + }
> +
> + for (i = 0; i < virJSONValueArraySize(devices); i++) {
> + virJSONValuePtr dev = virJSONValueArrayGet(devices, i);
> + const char *thisdev;
> +
> + if (!dev || dev->type != VIR_JSON_TYPE_OBJECT) {
> + qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("block info device entry was not in expected format"));
> + goto cleanup;
> + }
> +
> + if ((thisdev = virJSONValueObjectGetString(dev, "device")) == NULL) {
> + qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("block info device entry was not in expected format"));
> + goto cleanup;
> + }
> +
> + if (STRPREFIX(thisdev, QEMU_DRIVE_HOST_PREFIX))
> + thisdev += strlen(QEMU_DRIVE_HOST_PREFIX);
> +
> + if (STRNEQ(thisdev, devname))
> + continue;
> +
> + found = true;
> + if (virJSONValueObjectGetBoolean(dev, "removable", &info->removable) < 0) {
> + qemuReportError(VIR_ERR_INTERNAL_ERROR,
> + _("cannot read %s value"),
> + "removable");
> + goto cleanup;
> + }
> +
> + if (virJSONValueObjectGetBoolean(dev, "locked", &info->locked) < 0) {
> + qemuReportError(VIR_ERR_INTERNAL_ERROR,
> + _("cannot read %s value"),
> + "locked");
> + goto cleanup;
> + }
> +
> + /* Don't check for success here, because 'tray-open' is presented iff
> + * medium is ejected.
> + */
> + virJSONValueObjectGetBoolean(dev, "tray-open", &info->tray_open);
> +
> + break;
> + }
> +
> + if (!found) {
> + qemuReportError(VIR_ERR_INTERNAL_ERROR,
> + _("cannot find info for device '%s'"),
> + devname);
> + goto cleanup;
> + }
> +
> + ret = 0;
> +
> +cleanup:
> + virJSONValueFree(cmd);
> + virJSONValueFree(reply);
> + return ret;
> +}
> +
> +
> int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon,
> const char *devname,
> long long *rd_req,
> diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
> index dfeba7e..24d6aec 100644
> --- a/src/qemu/qemu_monitor_json.h
> +++ b/src/qemu/qemu_monitor_json.h
> @@ -60,6 +60,9 @@ int qemuMonitorJSONGetBalloonInfo(qemuMonitorPtr mon,
> int qemuMonitorJSONGetMemoryStats(qemuMonitorPtr mon,
> virDomainMemoryStatPtr stats,
> unsigned int nr_stats);
> +int qemuMonitorJSONGetBlockInfo(qemuMonitorPtr mon,
> + const char *devname,
> + struct qemuDomainDiskInfo *info);
> int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon,
> const char *devname,
> long long *rd_req,
> diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c
> index 0b50ba2..50b9836 100644
> --- a/src/qemu/qemu_monitor_text.c
> +++ b/src/qemu/qemu_monitor_text.c
> @@ -750,6 +750,96 @@ int qemuMonitorTextGetMemoryStats(qemuMonitorPtr mon,
> }
>
>
> +int qemuMonitorTextGetBlockInfo(qemuMonitorPtr mon,
> + const char *devname,
> + struct qemuDomainDiskInfo *info)
> +{
> + char *reply = NULL;
> + int ret = -1;
> + char *dummy;
> + const char *p, *eol;
> + int devnamelen = strlen(devname);
> + int tmp;
> +
> + if (qemuMonitorHMPCommand(mon, "info block", &reply) < 0) {
> + qemuReportError(VIR_ERR_OPERATION_FAILED,
> + "%s", _("info block command failed"));
> + goto cleanup;
> + }
> +
> + if (strstr(reply, "\ninfo ")) {
> + qemuReportError(VIR_ERR_OPERATION_INVALID,
> + "%s",
> + _("info block not supported by this qemu"));
> + goto cleanup;
> + }
> +
> + /* The output looks like this:
> + * drive-ide0-0-0: removable=0 file=<path> ro=0 drv=raw encrypted=0
> + * drive-ide0-1-0: removable=1 locked=0 file=<path> ro=1 drv=raw encrypted=0
> + */
> + p = reply;
> +
> + while (*p) {
> + if (STRPREFIX(p, QEMU_DRIVE_HOST_PREFIX))
> + p += strlen(QEMU_DRIVE_HOST_PREFIX);
> +
> + if (STREQLEN(p, devname, devnamelen) &&
> + p[devnamelen] == ':' && p[devnamelen+1] == ' ') {
> +
> + eol = strchr(p, '\n');
> + if (!eol)
> + eol = p + strlen(p);
> +
> + p += devnamelen + 2; /*Skip to first label. */
> +
> + while (*p) {
> + if (STRPREFIX(p, "removable=")) {
> + p += strlen("removable=");
> + if (virStrToLong_i(p, &dummy, 10, &tmp) == -1)
> + VIR_DEBUG("error reading removable: %s", p);
> + else
> + info->removable = p ? true : false;
> + } else if (STRPREFIX(p, "locked=")) {
> + p += strlen("locked=");
> + if (virStrToLong_i(p, &dummy, 10, &tmp) == -1)
> + VIR_DEBUG("error reading locked: %s", p);
> + else
> + info->locked = p ? true : false;
> + } else if (STRPREFIX(p, "tray_open=")) {
> + p += strlen("tray_open=");
> + if (virStrToLong_i(p, &dummy, 10, &tmp) == -1)
> + VIR_DEBUG("error reading tray_open: %s", p);
> + else
> + info->tray_open = p ? true : false;
> + } else {
> + /* ignore because we don't parse all options */
> + }
> +
> + /* skip to next label */
> + p = strchr(p, ' ');
> + if (!p || p >= eol) break;
> + p++;
> + }
> +
> + ret = 0;
> + goto cleanup;
> + }
> +
> + /* skip to next line */
> + p = strchr(p, '\n');
> + if (!p) break;
> + p++;
> + }
> +
> + qemuReportError(VIR_ERR_INVALID_ARG,
> + _("no info for device '%s'"), devname);
> +
> +cleanup:
> + VIR_FREE(reply);
> + return ret;
> +}
> +
> int qemuMonitorTextGetBlockStatsInfo(qemuMonitorPtr mon,
> const char *devname,
> long long *rd_req,
> diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h
> index 7cc3172..68e16b3 100644
> --- a/src/qemu/qemu_monitor_text.h
> +++ b/src/qemu/qemu_monitor_text.h
> @@ -57,6 +57,9 @@ int qemuMonitorTextGetBalloonInfo(qemuMonitorPtr mon,
> int qemuMonitorTextGetMemoryStats(qemuMonitorPtr mon,
> virDomainMemoryStatPtr stats,
> unsigned int nr_stats);
> +int qemuMonitorTextGetBlockInfo(qemuMonitorPtr mon,
> + const char *devname,
> + struct qemuDomainDiskInfo *info);
> int qemuMonitorTextGetBlockStatsInfo(qemuMonitorPtr mon,
> const char *devname,
> long long *rd_req,
> diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
> index f8a8475..7b5d10a 100644
> --- a/src/qemu/qemu_process.c
> +++ b/src/qemu/qemu_process.c
> @@ -2612,6 +2612,9 @@ qemuProcessReconnect(void *opaque)
> if (qemuProcessFiltersInstantiate(conn, obj->def))
> goto error;
>
> + if (qemuDomainCheckEjectableMedia(driver, obj) < 0)
> + goto error;
> +
> if (qemuProcessRecoverJob(driver, obj, conn, &oldjob) < 0)
> goto error;
>
Ping?
More information about the libvir-list
mailing list