mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-03 10:25:16 +00:00
Refactor qemudDomainRestore
We need to be able to restore a domain which we already locked and started a job for it without undoing these steps. This patch factors out internals of qemudDomainRestore into separate functions which work for locked objects.
This commit is contained in:
parent
b8ed797c7c
commit
de5a60e1cc
@ -5992,29 +5992,44 @@ child_cleanup:
|
|||||||
_exit(exit_code);
|
_exit(exit_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: check seclabel restore */
|
static int qemudDomainSaveImageClose(int fd, pid_t read_pid, int *status)
|
||||||
static int qemudDomainRestore(virConnectPtr conn,
|
{
|
||||||
const char *path) {
|
int ret = 0;
|
||||||
struct qemud_driver *driver = conn->privateData;
|
|
||||||
virDomainDefPtr def = NULL;
|
if (fd != -1)
|
||||||
virDomainObjPtr vm = NULL;
|
close(fd);
|
||||||
int fd = -1;
|
|
||||||
pid_t read_pid = -1;
|
if (read_pid != -1) {
|
||||||
int ret = -1;
|
/* reap the process that read the file */
|
||||||
char *xml = NULL;
|
while ((ret = waitpid(read_pid, status, 0)) == -1
|
||||||
struct qemud_save_header header;
|
&& errno == EINTR) {
|
||||||
virDomainEventPtr event = NULL;
|
/* empty */
|
||||||
int intermediatefd = -1;
|
}
|
||||||
pid_t intermediate_pid = -1;
|
} else if (status) {
|
||||||
int childstat;
|
*status = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5)
|
||||||
|
qemudDomainSaveImageOpen(struct qemud_driver *driver,
|
||||||
|
const char *path,
|
||||||
|
virDomainDefPtr *ret_def,
|
||||||
|
struct qemud_save_header *ret_header,
|
||||||
|
pid_t *ret_read_pid)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
pid_t read_pid = -1;
|
||||||
|
struct qemud_save_header header;
|
||||||
|
char *xml = NULL;
|
||||||
|
virDomainDefPtr def = NULL;
|
||||||
|
|
||||||
qemuDriverLock(driver);
|
|
||||||
/* Verify the header and read the XML */
|
|
||||||
if ((fd = open(path, O_RDONLY)) < 0) {
|
if ((fd = open(path, O_RDONLY)) < 0) {
|
||||||
if ((driver->user == 0) || (getuid() != 0)) {
|
if ((driver->user == 0) || (getuid() != 0)) {
|
||||||
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
||||||
"%s", _("cannot read domain image"));
|
"%s", _("cannot read domain image"));
|
||||||
goto cleanup;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Opening as root failed, but qemu runs as a different user
|
/* Opening as root failed, but qemu runs as a different user
|
||||||
@ -6023,44 +6038,44 @@ static int qemudDomainRestore(virConnectPtr conn,
|
|||||||
have the necessary authority to read the file. */
|
have the necessary authority to read the file. */
|
||||||
if ((fd = qemudOpenAsUID(path, driver->user, &read_pid)) < 0) {
|
if ((fd = qemudOpenAsUID(path, driver->user, &read_pid)) < 0) {
|
||||||
/* error already reported */
|
/* error already reported */
|
||||||
goto cleanup;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (saferead(fd, &header, sizeof(header)) != sizeof(header)) {
|
if (saferead(fd, &header, sizeof(header)) != sizeof(header)) {
|
||||||
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
||||||
"%s", _("failed to read qemu header"));
|
"%s", _("failed to read qemu header"));
|
||||||
goto cleanup;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (memcmp(header.magic, QEMUD_SAVE_MAGIC, sizeof(header.magic)) != 0) {
|
if (memcmp(header.magic, QEMUD_SAVE_MAGIC, sizeof(header.magic)) != 0) {
|
||||||
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
||||||
"%s", _("image magic is incorrect"));
|
"%s", _("image magic is incorrect"));
|
||||||
goto cleanup;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header.version > QEMUD_SAVE_VERSION) {
|
if (header.version > QEMUD_SAVE_VERSION) {
|
||||||
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
||||||
_("image version is not supported (%d > %d)"),
|
_("image version is not supported (%d > %d)"),
|
||||||
header.version, QEMUD_SAVE_VERSION);
|
header.version, QEMUD_SAVE_VERSION);
|
||||||
goto cleanup;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header.xml_len <= 0) {
|
if (header.xml_len <= 0) {
|
||||||
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
||||||
_("invalid XML length: %d"), header.xml_len);
|
_("invalid XML length: %d"), header.xml_len);
|
||||||
goto cleanup;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (VIR_ALLOC_N(xml, header.xml_len) < 0) {
|
if (VIR_ALLOC_N(xml, header.xml_len) < 0) {
|
||||||
virReportOOMError();
|
virReportOOMError();
|
||||||
goto cleanup;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (saferead(fd, xml, header.xml_len) != header.xml_len) {
|
if (saferead(fd, xml, header.xml_len) != header.xml_len) {
|
||||||
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
||||||
"%s", _("failed to read XML"));
|
"%s", _("failed to read XML"));
|
||||||
goto cleanup;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create a domain from this XML */
|
/* Create a domain from this XML */
|
||||||
@ -6068,35 +6083,54 @@ static int qemudDomainRestore(virConnectPtr conn,
|
|||||||
VIR_DOMAIN_XML_INACTIVE))) {
|
VIR_DOMAIN_XML_INACTIVE))) {
|
||||||
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
||||||
"%s", _("failed to parse XML"));
|
"%s", _("failed to parse XML"));
|
||||||
goto cleanup;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
|
VIR_FREE(xml);
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
if (!(vm = virDomainAssignDef(driver->caps,
|
*ret_def = def;
|
||||||
&driver->domains,
|
*ret_header = header;
|
||||||
def, true))) {
|
*ret_read_pid = read_pid;
|
||||||
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
||||||
"%s", _("failed to assign new VM"));
|
return fd;
|
||||||
goto cleanup;
|
|
||||||
|
error:
|
||||||
|
virDomainDefFree(def);
|
||||||
|
VIR_FREE(xml);
|
||||||
|
qemudDomainSaveImageClose(fd, read_pid, NULL);
|
||||||
|
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
def = NULL;
|
|
||||||
|
|
||||||
if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
|
/* TODO: check seclabel restore */
|
||||||
goto cleanup;
|
static int ATTRIBUTE_NONNULL(6)
|
||||||
|
qemudDomainSaveImageStartVM(virConnectPtr conn,
|
||||||
|
struct qemud_driver *driver,
|
||||||
|
virDomainObjPtr vm,
|
||||||
|
int fd,
|
||||||
|
pid_t read_pid,
|
||||||
|
const struct qemud_save_header *header,
|
||||||
|
const char *path)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
virDomainEventPtr event;
|
||||||
|
int intermediatefd = -1;
|
||||||
|
pid_t intermediate_pid = -1;
|
||||||
|
int childstat;
|
||||||
|
int wait_ret;
|
||||||
|
int status;
|
||||||
|
|
||||||
if (header.version == 2) {
|
if (header->version == 2) {
|
||||||
const char *intermediate_argv[3] = { NULL, "-dc", NULL };
|
const char *intermediate_argv[3] = { NULL, "-dc", NULL };
|
||||||
const char *prog = qemudSaveCompressionTypeToString(header.compressed);
|
const char *prog = qemudSaveCompressionTypeToString(header->compressed);
|
||||||
if (prog == NULL) {
|
if (prog == NULL) {
|
||||||
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
||||||
_("Invalid compressed save format %d"),
|
_("Invalid compressed save format %d"),
|
||||||
header.compressed);
|
header->compressed);
|
||||||
goto endjob;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header.compressed != QEMUD_SAVE_FORMAT_RAW) {
|
if (header->compressed != QEMUD_SAVE_FORMAT_RAW) {
|
||||||
intermediate_argv[0] = prog;
|
intermediate_argv[0] = prog;
|
||||||
intermediatefd = fd;
|
intermediatefd = fd;
|
||||||
fd = -1;
|
fd = -1;
|
||||||
@ -6105,29 +6139,27 @@ static int qemudDomainRestore(virConnectPtr conn,
|
|||||||
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
_("Failed to start decompression binary %s"),
|
_("Failed to start decompression binary %s"),
|
||||||
intermediate_argv[0]);
|
intermediate_argv[0]);
|
||||||
goto endjob;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the migration source and start it up. */
|
/* Set the migration source and start it up. */
|
||||||
ret = qemudStartVMDaemon(conn, driver, vm, "stdio", fd);
|
ret = qemudStartVMDaemon(conn, driver, vm, "stdio", fd);
|
||||||
|
|
||||||
if (intermediate_pid != -1) {
|
if (intermediate_pid != -1) {
|
||||||
/* Wait for intermediate process to exit */
|
/* Wait for intermediate process to exit */
|
||||||
while (waitpid(intermediate_pid, &childstat, 0) == -1 &&
|
while (waitpid(intermediate_pid, &childstat, 0) == -1 &&
|
||||||
errno == EINTR);
|
errno == EINTR) {
|
||||||
|
/* empty */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (intermediatefd != -1)
|
if (intermediatefd != -1)
|
||||||
close(intermediatefd);
|
close(intermediatefd);
|
||||||
close(fd);
|
|
||||||
|
wait_ret = qemudDomainSaveImageClose(fd, read_pid, &status);
|
||||||
fd = -1;
|
fd = -1;
|
||||||
if (read_pid != -1) {
|
if (read_pid != -1) {
|
||||||
int wait_ret;
|
|
||||||
int status;
|
|
||||||
/* reap the process that read the file */
|
|
||||||
while (((wait_ret = waitpid(read_pid, &status, 0)) == -1)
|
|
||||||
&& (errno == EINTR)) {
|
|
||||||
/* empty */
|
|
||||||
}
|
|
||||||
read_pid = -1;
|
read_pid = -1;
|
||||||
if (wait_ret == -1) {
|
if (wait_ret == -1) {
|
||||||
virReportSystemError(errno,
|
virReportSystemError(errno,
|
||||||
@ -6149,22 +6181,19 @@ static int qemudDomainRestore(virConnectPtr conn,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ret < 0) {
|
|
||||||
if (!vm->persistent) {
|
if (ret < 0)
|
||||||
if (qemuDomainObjEndJob(vm) > 0)
|
goto out;
|
||||||
virDomainRemoveInactive(&driver->domains,
|
|
||||||
vm);
|
|
||||||
vm = NULL;
|
|
||||||
}
|
|
||||||
goto endjob;
|
|
||||||
}
|
|
||||||
|
|
||||||
event = virDomainEventNewFromObj(vm,
|
event = virDomainEventNewFromObj(vm,
|
||||||
VIR_DOMAIN_EVENT_STARTED,
|
VIR_DOMAIN_EVENT_STARTED,
|
||||||
VIR_DOMAIN_EVENT_STARTED_RESTORED);
|
VIR_DOMAIN_EVENT_STARTED_RESTORED);
|
||||||
|
if (event)
|
||||||
|
qemuDomainEventQueue(driver, event);
|
||||||
|
|
||||||
|
|
||||||
/* If it was running before, resume it now. */
|
/* If it was running before, resume it now. */
|
||||||
if (header.was_running) {
|
if (header->was_running) {
|
||||||
qemuDomainObjPrivatePtr priv = vm->privateData;
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
||||||
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
||||||
if (qemuMonitorStartCPUs(priv->mon, conn) < 0) {
|
if (qemuMonitorStartCPUs(priv->mon, conn) < 0) {
|
||||||
@ -6172,38 +6201,68 @@ static int qemudDomainRestore(virConnectPtr conn,
|
|||||||
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
||||||
"%s", _("failed to resume domain"));
|
"%s", _("failed to resume domain"));
|
||||||
qemuDomainObjExitMonitorWithDriver(driver,vm);
|
qemuDomainObjExitMonitorWithDriver(driver,vm);
|
||||||
goto endjob;
|
goto out;
|
||||||
}
|
}
|
||||||
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
||||||
vm->state = VIR_DOMAIN_RUNNING;
|
vm->state = VIR_DOMAIN_RUNNING;
|
||||||
if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) {
|
if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) {
|
||||||
VIR_WARN("Failed to save status on vm %s", vm->def->name);
|
VIR_WARN("Failed to save status on vm %s", vm->def->name);
|
||||||
goto endjob;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
endjob:
|
out:
|
||||||
if (vm &&
|
return ret;
|
||||||
qemuDomainObjEndJob(vm) == 0)
|
}
|
||||||
|
|
||||||
|
static int qemudDomainRestore(virConnectPtr conn,
|
||||||
|
const char *path) {
|
||||||
|
struct qemud_driver *driver = conn->privateData;
|
||||||
|
virDomainDefPtr def = NULL;
|
||||||
|
virDomainObjPtr vm = NULL;
|
||||||
|
int fd = -1;
|
||||||
|
pid_t read_pid = -1;
|
||||||
|
int ret = -1;
|
||||||
|
struct qemud_save_header header;
|
||||||
|
|
||||||
|
qemuDriverLock(driver);
|
||||||
|
|
||||||
|
fd = qemudDomainSaveImageOpen(driver, path, &def, &header, &read_pid);
|
||||||
|
if (fd < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (!(vm = virDomainAssignDef(driver->caps,
|
||||||
|
&driver->domains,
|
||||||
|
def, true))) {
|
||||||
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
||||||
|
"%s", _("failed to assign new VM"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
def = NULL;
|
||||||
|
|
||||||
|
if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
ret = qemudDomainSaveImageStartVM(conn, driver, vm, fd,
|
||||||
|
read_pid, &header, path);
|
||||||
|
|
||||||
|
if (qemuDomainObjEndJob(vm) == 0)
|
||||||
vm = NULL;
|
vm = NULL;
|
||||||
|
else if (ret < 0 && !vm->persistent) {
|
||||||
|
virDomainRemoveInactive(&driver->domains, vm);
|
||||||
|
vm = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
virDomainDefFree(def);
|
virDomainDefFree(def);
|
||||||
VIR_FREE(xml);
|
qemudDomainSaveImageClose(fd, read_pid, NULL);
|
||||||
if (fd != -1)
|
|
||||||
close(fd);
|
|
||||||
if (read_pid != 0) {
|
|
||||||
/* reap the process that read the file */
|
|
||||||
while ((waitpid(read_pid, NULL, 0) == -1)
|
|
||||||
&& (errno == EINTR)) {
|
|
||||||
/* empty */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (vm)
|
if (vm)
|
||||||
virDomainObjUnlock(vm);
|
virDomainObjUnlock(vm);
|
||||||
if (event)
|
|
||||||
qemuDomainEventQueue(driver, event);
|
|
||||||
qemuDriverUnlock(driver);
|
qemuDriverUnlock(driver);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user