int qemudLoadDriverConfig(struct qemud_driver *driver,
const char *filename);
+struct qemuDomainDiskInfo {
+ bool removable;
+ bool locked;
+ bool tray_open;
+};
+
#endif /* __QEMUD_CONF_H */
goto endjob;
}
+ /* Check if there is any 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;
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;
+
+ if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK)
+ continue;
+
+ 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,
virDomainObjPtr vm,
virDomainDiskDefPtr disk,
bool force);
+int qemuDomainCheckEjectableMedia(struct qemud_driver *driver,
+ virDomainObjPtr vm);
int qemuDomainAttachPciDiskDevice(struct qemud_driver *driver,
virDomainObjPtr vm,
virDomainDiskDefPtr disk);
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 *dev_name,
# include "internal.h"
# include "domain_conf.h"
+# include "qemu_conf.h"
# include "hash.h"
typedef struct _qemuMonitor qemuMonitor;
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 *dev_name,
long long *rd_req,
}
+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 *dev_name,
long long *rd_req,
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 *dev_name,
long long *rd_req,
}
+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 != NULL;
+ } 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 *dev_name,
long long *rd_req,
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 *dev_name,
long long *rd_req,
if (qemuProcessFiltersInstantiate(conn, obj->def))
goto error;
+ if (qemuDomainCheckEjectableMedia(driver, obj) < 0)
+ goto error;
+
if (qemuProcessRecoverJob(driver, obj, conn, &oldjob) < 0)
goto error;