[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