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? -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list