"drive-mirror", /* 115 */
"usb-redir.bootindex",
"usb-host.bootindex",
+ "blockdev-snapshot-sync",
);
struct _qemuCaps {
qemuCapsSet(caps, QEMU_CAPS_VNC);
else if (STREQ(name, "drive-mirror"))
qemuCapsSet(caps, QEMU_CAPS_DRIVE_MIRROR);
+ else if (STREQ(name, "blockdev-snapshot-sync"))
+ qemuCapsSet(caps, QEMU_CAPS_DISK_SNAPSHOT);
VIR_FREE(name);
}
VIR_FREE(commands);
QEMU_CAPS_DRIVE_MIRROR = 115, /* drive-mirror monitor command */
QEMU_CAPS_USB_REDIR_BOOTINDEX = 116, /* usb-redir.bootindex */
QEMU_CAPS_USB_HOST_BOOTINDEX = 117, /* usb-host.bootindex */
+ QEMU_CAPS_DISK_SNAPSHOT = 118, /* blockdev-snapshot-sync command */
QEMU_CAPS_LAST, /* this must always be the last item */
};
virReportOOMError();
goto cleanup;
}
+ } else if (!qemuCapsGet(priv->caps, QEMU_CAPS_DISK_SNAPSHOT)) {
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+ _("live disk snapshot not supported with this "
+ "QEMU binary"));
+ goto cleanup;
}
/* No way to roll back if first disk succeeds but later disks
const char *device, const char *file,
const char *format, bool reuse)
{
- int ret;
+ int ret = -1;
VIR_DEBUG("mon=%p, actions=%p, device=%s, file=%s, format=%s, reuse=%d",
mon, actions, device, file, format, reuse);
return -1;
}
- if (mon->json) {
+ if (mon->json)
ret = qemuMonitorJSONDiskSnapshot(mon, actions, device, file, format,
reuse);
- } else {
- if (actions || STRNEQ(format, "qcow2") || reuse) {
- virReportError(VIR_ERR_INVALID_ARG, "%s",
- _("text monitor lacks several snapshot features"));
- return -1;
- }
- ret = qemuMonitorTextDiskSnapshot(mon, device, file);
- }
+ else
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("disk snapshot requires JSON monitor"));
return ret;
}
if ((ret = qemuMonitorJSONCommand(mon, cmd, &reply)) < 0)
goto cleanup;
- if (qemuMonitorJSONHasError(reply, "CommandNotFound")) {
- VIR_DEBUG("blockdev-snapshot-sync command not found, trying HMP");
- ret = qemuMonitorTextDiskSnapshot(mon, device, file);
- goto cleanup;
- }
-
ret = qemuMonitorJSONCheckError(cmd, reply);
}
return ret;
}
-int
-qemuMonitorTextDiskSnapshot(qemuMonitorPtr mon, const char *device,
- const char *file)
-{
- char *cmd = NULL;
- char *reply = NULL;
- int ret = -1;
- char *safename;
-
- if (!(safename = qemuMonitorEscapeArg(file)) ||
- virAsprintf(&cmd, "snapshot_blkdev %s \"%s\"", device, safename) < 0) {
- virReportOOMError();
- goto cleanup;
- }
-
- if (qemuMonitorHMPCommand(mon, cmd, &reply))
- goto cleanup;
-
- if (strstr(reply, "error while creating qcow2") != NULL ||
- strstr(reply, "unknown command:") != NULL) {
- virReportError(VIR_ERR_OPERATION_FAILED,
- _("Failed to take snapshot: %s"), reply);
- goto cleanup;
- }
-
- /* XXX Should we scrape 'info block' output for
- * 'device:... file=name backing_file=oldname' to make sure the
- * command succeeded? */
-
- ret = 0;
-
-cleanup:
- VIR_FREE(safename);
- VIR_FREE(cmd);
- VIR_FREE(reply);
- return ret;
-}
int qemuMonitorTextArbitraryCommand(qemuMonitorPtr mon, const char *cmd,
char **reply)
int qemuMonitorTextLoadSnapshot(qemuMonitorPtr mon, const char *name);
int qemuMonitorTextDeleteSnapshot(qemuMonitorPtr mon, const char *name);
-int qemuMonitorTextDiskSnapshot(qemuMonitorPtr mon,
- const char *device,
- const char *file);
-
int qemuMonitorTextArbitraryCommand(qemuMonitorPtr mon, const char *cmd,
char **reply);