[libvirt] [PATCH 00/27] Refactor QEMU monitor command handling

In the QEMU driver source code the methods which talk to the QEMU monitor currently all just call qemudMonitorCommand() directly with the raw command string, and then parse the raw reply. In the not too distant future QEMU is introducing a new machine parsable monitor syntax. With the current way the code is structured supporting this new mode will be seriously unpleasant. This large series of patches, moves all the monitor command formatting and parsing code out into a separate source file src/qemu/qemu_monitor_text.c. There is one API in that file for each logical monitor command we wish to issue, accepting (mostly) strongly typed arguments. The exception is the NIC hotplug method which still takes the raw NIC string for now. The main qemu_driver.c file now directly calls the appropriate monitor command APIs, making logic there much cleaner. When we add support for the new QEMU monitor syntax we'll gain another file src/qemu/qemu_monitor_json.c which implements all the same APIs as src/qemu/qemu_monitor_text.c, but using the new JSON syntax instead of raw text strings This patch series is soooooo large, because I did it in many small steps, one command at a time. It is also now much easier to debug the monitor by just setting the env variables LIBVIRT_LOG_OUTPUTS="1:stderr" LIBVIRT_LOG_FILTERS="1:qemu_monitor" And you'll get the command & reply of each monitor interaction printed I've tested basic handling of every new method with the exception of the migration ones, since I don't have a convenient target host when on my laptop. Overall we get a small increase in code size, but huge increase in readability ! Makefile.am | 1 libvirt_private.syms | 1 qemu/qemu_conf.c | 20 qemu/qemu_conf.h | 2 qemu/qemu_driver.c | 1669 +++++--------------------------------------- qemu/qemu_monitor_text.c | 1777 +++++++++++++++++++++++++++++++++++++++++++++++ qemu/qemu_monitor_text.h | 173 ++++ 7 files changed, 2171 insertions(+), 1472 deletions(-) Daniel

Pull out all the QEMU monitor interaction code to a separate file. This will make life easier when we need to drop in a new implementation for the forthcoming QMP machine friendly monitor support. Next step is to add formal APIs for each monitor command, and remove direct commands for sending/receiving generic data. * src/Makefile.am: Add qemu_monitor.c to build * src/qemu/qemu_driver.c: Remove code for monitor interaction * src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h: New file for monitor interaction --- src/Makefile.am | 1 + src/qemu/qemu_driver.c | 426 +---------------------------------------- src/qemu/qemu_monitor_text.c | 437 ++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 72 +++++++ 4 files changed, 511 insertions(+), 425 deletions(-) create mode 100644 src/qemu/qemu_monitor_text.c create mode 100644 src/qemu/qemu_monitor_text.h diff --git a/src/Makefile.am b/src/Makefile.am index 9cbec47..7520e96 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -169,6 +169,7 @@ VBOX_DRIVER_EXTRA_DIST = vbox/vbox_tmpl.c vbox/README QEMU_DRIVER_SOURCES = \ qemu/qemu_conf.c qemu/qemu_conf.h \ + qemu/qemu_monitor_text.c qemu/qemu_monitortext.h\ qemu/qemu_driver.c qemu/qemu_driver.h UML_DRIVER_SOURCES = \ diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 25d983e..9f17aae 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -55,6 +55,7 @@ #include "datatypes.h" #include "qemu_driver.h" #include "qemu_conf.h" +#include "qemu_monitor_text.h" #include "c-ctype.h" #include "event.h" #include "buf.h" @@ -74,9 +75,6 @@ #define VIR_FROM_THIS VIR_FROM_QEMU -#define QEMU_CMD_PROMPT "\n(qemu) " -#define QEMU_PASSWD_PROMPT "Password: " - static int qemudShutdown(void); static void qemuDriverLock(struct qemud_driver *driver) @@ -88,12 +86,6 @@ static void qemuDriverUnlock(struct qemud_driver *driver) virMutexUnlock(&driver->lock); } -/* Return -1 for error, 0 for success */ -typedef int qemudMonitorExtraPromptHandler(const virDomainObjPtr vm, - const char *buf, - const char *prompt, - void *data); - static void qemuDomainEventFlush(int timer, void *opaque); static void qemuDomainEventQueue(struct qemud_driver *driver, virDomainEventPtr event); @@ -115,28 +107,6 @@ static void qemudShutdownVMDaemon(virConnectPtr conn, static int qemudDomainGetMaxVcpus(virDomainPtr dom); -static int qemudMonitorCommand(const virDomainObjPtr vm, - const char *cmd, - char **reply); -static int qemudMonitorCommandWithFd(const virDomainObjPtr vm, - const char *cmd, - int scm_fd, - char **reply); -static int qemudMonitorCommandWithHandler(const virDomainObjPtr vm, - const char *cmd, - const char *extraPrompt, - qemudMonitorExtraPromptHandler extraHandler, - void *handlerData, - int scm_fd, - char **reply); -static int qemudMonitorCommandExtra(const virDomainObjPtr vm, - const char *cmd, - const char *extra, - const char *extraPrompt, - int scm_fd, - char **reply); -static int qemudMonitorSendCont(virConnectPtr conn, - const virDomainObjPtr vm); static int qemudDomainSetMemoryBalloon(virConnectPtr conn, virDomainObjPtr vm, unsigned long newmem); @@ -2411,400 +2381,6 @@ cleanup: } -/* Throw away any data available on the monitor - * This is done before executing a command, in order - * to allow re-synchronization if something went badly - * wrong in the past. it also deals with problem of - * QEMU *sometimes* re-printing its initial greeting - * when we reconnect to the monitor after restarts. - */ -static void -qemuMonitorDiscardPendingData(virDomainObjPtr vm) { - char buf[1024]; - int ret = 0; - - /* Monitor is non-blocking, so just loop till we - * get -1 or 0. Don't bother with detecting - * errors, since we'll deal with that better later */ - do { - ret = read(vm->monitor, buf, sizeof (buf)-1); - } while (ret > 0); -} - -static int -qemudMonitorSendUnix(const virDomainObjPtr vm, - const char *cmd, - size_t cmdlen, - int scm_fd) -{ - struct msghdr msg; - struct iovec iov[1]; - ssize_t ret; - - memset(&msg, 0, sizeof(msg)); - - iov[0].iov_base = (void *)cmd; - iov[0].iov_len = cmdlen; - - msg.msg_iov = iov; - msg.msg_iovlen = 1; - - if (scm_fd != -1) { - char control[CMSG_SPACE(sizeof(int))]; - struct cmsghdr *cmsg; - - msg.msg_control = control; - msg.msg_controllen = sizeof(control); - - cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_len = CMSG_LEN(sizeof(int)); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - memcpy(CMSG_DATA(cmsg), &scm_fd, sizeof(int)); - } - - do { - ret = sendmsg(vm->monitor, &msg, 0); - } while (ret < 0 && errno == EINTR); - - return ret == cmdlen ? 0 : -1; -} - -static int -qemudMonitorSend(const virDomainObjPtr vm, - const char *cmd, - int scm_fd) -{ - char *full; - size_t len; - int ret = -1; - - if (virAsprintf(&full, "%s\r", cmd) < 0) - return -1; - - len = strlen(full); - - switch (vm->monitor_chr->type) { - case VIR_DOMAIN_CHR_TYPE_UNIX: - if (qemudMonitorSendUnix(vm, full, len, scm_fd) < 0) - goto out; - break; - default: - case VIR_DOMAIN_CHR_TYPE_PTY: - if (safewrite(vm->monitor, full, len) != len) - goto out; - break; - } - - ret = 0; -out: - VIR_FREE(full); - return ret; -} - -static int -qemudMonitorCommandWithHandler(const virDomainObjPtr vm, - const char *cmd, - const char *extraPrompt, - qemudMonitorExtraPromptHandler extraHandler, - void *handlerData, - int scm_fd, - char **reply) { - int size = 0; - char *buf = NULL; - - /* Should never happen, but just in case, protect - * against null monitor (ocurrs when VM is inactive) */ - if (!vm->monitor_chr) - return -1; - - qemuMonitorDiscardPendingData(vm); - - VIR_DEBUG("Send '%s'", cmd); - if (qemudMonitorSend(vm, cmd, scm_fd) < 0) - return -1; - - *reply = NULL; - - for (;;) { - struct pollfd fd = { vm->monitor, POLLIN | POLLERR | POLLHUP, 0 }; - char *tmp; - - /* Read all the data QEMU has sent thus far */ - for (;;) { - char data[1024]; - int got = read(vm->monitor, data, sizeof(data)); - - if (got == 0) - goto error; - if (got < 0) { - if (errno == EINTR) - continue; - if (errno == EAGAIN) - break; - goto error; - } - if (VIR_REALLOC_N(buf, size+got+1) < 0) - goto error; - - memmove(buf+size, data, got); - buf[size+got] = '\0'; - size += got; - } - - /* Look for QEMU prompt to indicate completion */ - if (buf) { - char *foundPrompt; - - if (extraPrompt && - (foundPrompt = strstr(buf, extraPrompt)) != NULL) { - char *promptEnd; - - if (extraHandler(vm, buf, foundPrompt, handlerData) < 0) - return -1; - /* Discard output so far, necessary to detect whether - extraPrompt appears again. We don't need the output between - original command and this prompt anyway. */ - promptEnd = foundPrompt + strlen(extraPrompt); - memmove(buf, promptEnd, strlen(promptEnd)+1); - size -= promptEnd - buf; - } else if ((tmp = strstr(buf, QEMU_CMD_PROMPT)) != NULL) { - char *commptr = NULL, *nlptr = NULL; - /* Preserve the newline */ - tmp[1] = '\0'; - - /* The monitor doesn't dump clean output after we have written to - * it. Every character we write dumps a bunch of useless stuff, - * so the result looks like "cXcoXcomXcommXcommaXcommanXcommand" - * Try to throw away everything before the first full command - * occurence, and inbetween the command and the newline starting - * the response - */ - if ((commptr = strstr(buf, cmd))) { - memmove(buf, commptr, strlen(commptr)+1); - if ((nlptr = strchr(buf, '\n'))) - memmove(buf+strlen(cmd), nlptr, strlen(nlptr)+1); - } - - break; - } - } - pollagain: - /* Need to wait for more data */ - if (poll(&fd, 1, -1) < 0) { - if (errno == EINTR) - goto pollagain; - goto error; - } - } - *reply = buf; - return 0; - - error: - VIR_FREE(buf); - return -1; -} - -struct extraHandlerData -{ - const char *reply; - bool first; -}; - -static int -qemudMonitorCommandSimpleExtraHandler(const virDomainObjPtr vm, - const char *buf ATTRIBUTE_UNUSED, - const char *prompt ATTRIBUTE_UNUSED, - void *data_) -{ - struct extraHandlerData *data = data_; - - if (!data->first) - return 0; - if (qemudMonitorSend(vm, data->reply, -1) < 0) - return -1; - data->first = false; - return 0; -} - -static int -qemudMonitorCommandExtra(const virDomainObjPtr vm, - const char *cmd, - const char *extra, - const char *extraPrompt, - int scm_fd, - char **reply) { - struct extraHandlerData data; - - data.reply = extra; - data.first = true; - return qemudMonitorCommandWithHandler(vm, cmd, extraPrompt, - qemudMonitorCommandSimpleExtraHandler, - &data, scm_fd, reply); -} - -static int -qemudMonitorCommandWithFd(const virDomainObjPtr vm, - const char *cmd, - int scm_fd, - char **reply) { - return qemudMonitorCommandExtra(vm, cmd, NULL, NULL, scm_fd, reply); -} - -static int -qemudMonitorCommand(const virDomainObjPtr vm, - const char *cmd, - char **reply) { - return qemudMonitorCommandWithFd(vm, cmd, -1, reply); -} - -static virStorageEncryptionPtr -findDomainDiskEncryption(virConnectPtr conn, virDomainObjPtr vm, - const char *path) -{ - bool seen_volume; - int i; - - seen_volume = false; - for (i = 0; i < vm->def->ndisks; i++) { - virDomainDiskDefPtr disk; - - disk = vm->def->disks[i]; - if (disk->src != NULL && STREQ(disk->src, path)) { - seen_volume = true; - if (disk->encryption != NULL) - return disk->encryption; - } - } - if (seen_volume) - qemudReportError(conn, NULL, NULL, VIR_ERR_INVALID_DOMAIN, - _("missing <encryption> for volume %s"), path); - else - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("unexpected passphrase request for volume %s"), - path); - return NULL; -} - -static char * -findVolumeQcowPassphrase(virConnectPtr conn, virDomainObjPtr vm, - const char *path, size_t *passphrase_len) -{ - virStorageEncryptionPtr enc; - virSecretPtr secret; - char *passphrase; - unsigned char *data; - size_t size; - - if (conn->secretDriver == NULL || - conn->secretDriver->lookupByUUID == NULL || - conn->secretDriver->getValue == NULL) { - qemudReportError(conn, NULL, NULL, VIR_ERR_NO_SUPPORT, "%s", - _("secret storage not supported")); - return NULL; - } - - enc = findDomainDiskEncryption(conn, vm, path); - if (enc == NULL) - return NULL; - - if (enc->format != VIR_STORAGE_ENCRYPTION_FORMAT_QCOW || - enc->nsecrets != 1 || - enc->secrets[0]->type != - VIR_STORAGE_ENCRYPTION_SECRET_TYPE_PASSPHRASE) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INVALID_DOMAIN, - _("invalid <encryption> for volume %s"), path); - return NULL; - } - - secret = conn->secretDriver->lookupByUUID(conn, - enc->secrets[0]->uuid); - if (secret == NULL) - return NULL; - data = conn->secretDriver->getValue(secret, &size, - VIR_SECRET_GET_VALUE_INTERNAL_CALL); - virUnrefSecret(secret); - if (data == NULL) - return NULL; - - if (memchr(data, '\0', size) != NULL) { - memset(data, 0, size); - VIR_FREE(data); - qemudReportError(conn, NULL, NULL, VIR_ERR_INVALID_SECRET, - _("format='qcow' passphrase for %s must not contain a " - "'\\0'"), path); - return NULL; - } - - if (VIR_ALLOC_N(passphrase, size + 1) < 0) { - memset(data, 0, size); - VIR_FREE(data); - virReportOOMError(conn); - return NULL; - } - memcpy(passphrase, data, size); - passphrase[size] = '\0'; - - memset(data, 0, size); - VIR_FREE(data); - - *passphrase_len = size; - return passphrase; -} - -static int -qemudMonitorSendVolumePassphrase(const virDomainObjPtr vm, - const char *buf, - const char *prompt, - void *data) -{ - virConnectPtr conn = data; - char *passphrase, *path; - const char *prompt_path; - size_t path_len, passphrase_len = 0; - int res; - - /* The complete prompt looks like this: - ide0-hd0 (/path/to/volume) is encrypted. - Password: - "prompt" starts with ") is encrypted". Extract /path/to/volume. */ - for (prompt_path = prompt; prompt_path > buf && prompt_path[-1] != '('; - prompt_path--) - ; - if (prompt_path == buf) - return -1; - path_len = prompt - prompt_path; - if (VIR_ALLOC_N(path, path_len + 1) < 0) - return -1; - memcpy(path, prompt_path, path_len); - path[path_len] = '\0'; - - passphrase = findVolumeQcowPassphrase(conn, vm, path, &passphrase_len); - VIR_FREE(path); - if (passphrase == NULL) - return -1; - - res = qemudMonitorSend(vm, passphrase, -1); - - memset(passphrase, 0, passphrase_len); - VIR_FREE(passphrase); - - return res; -} - -static int -qemudMonitorSendCont(virConnectPtr conn, - const virDomainObjPtr vm) { - char *reply; - - if (qemudMonitorCommandWithHandler(vm, "cont", ") is encrypted.", - qemudMonitorSendVolumePassphrase, conn, - -1, &reply) < 0) - return -1; - qemudDebug ("%s: cont reply: %s", vm->def->name, info); - VIR_FREE(reply); - return 0; -} static virDrvOpenStatus qemudOpen(virConnectPtr conn, virConnectAuthPtr auth ATTRIBUTE_UNUSED, diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c new file mode 100644 index 0000000..76842a5 --- /dev/null +++ b/src/qemu/qemu_monitor_text.c @@ -0,0 +1,437 @@ +/* + * qemu_monitor.h: interaction with QEMU monitor console + * + * Copyright (C) 2006-2009 Red Hat, Inc. + * Copyright (C) 2006 Daniel P. Berrange + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Daniel P. Berrange <berrange@redhat.com> + */ + +#include <config.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <poll.h> +#include <unistd.h> + +#include "qemu_monitor_text.h" +#include "qemu_conf.h" +#include "memory.h" +#include "logging.h" +#include "driver.h" +#include "datatypes.h" +#include "virterror_internal.h" + +#define VIR_FROM_THIS VIR_FROM_QEMU + +/* Throw away any data available on the monitor + * This is done before executing a command, in order + * to allow re-synchronization if something went badly + * wrong in the past. it also deals with problem of + * QEMU *sometimes* re-printing its initial greeting + * when we reconnect to the monitor after restarts. + */ +static void +qemuMonitorDiscardPendingData(virDomainObjPtr vm) { + char buf[1024]; + int ret = 0; + + /* Monitor is non-blocking, so just loop till we + * get -1 or 0. Don't bother with detecting + * errors, since we'll deal with that better later */ + do { + ret = read(vm->monitor, buf, sizeof (buf)-1); + } while (ret > 0); +} + +static int +qemudMonitorSendUnix(const virDomainObjPtr vm, + const char *cmd, + size_t cmdlen, + int scm_fd) +{ + struct msghdr msg; + struct iovec iov[1]; + ssize_t ret; + + memset(&msg, 0, sizeof(msg)); + + iov[0].iov_base = (void *)cmd; + iov[0].iov_len = cmdlen; + + msg.msg_iov = iov; + msg.msg_iovlen = 1; + + if (scm_fd != -1) { + char control[CMSG_SPACE(sizeof(int))]; + struct cmsghdr *cmsg; + + msg.msg_control = control; + msg.msg_controllen = sizeof(control); + + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + memcpy(CMSG_DATA(cmsg), &scm_fd, sizeof(int)); + } + + do { + ret = sendmsg(vm->monitor, &msg, 0); + } while (ret < 0 && errno == EINTR); + + return ret == cmdlen ? 0 : -1; +} + +static int +qemudMonitorSend(const virDomainObjPtr vm, + const char *cmd, + int scm_fd) +{ + char *full; + size_t len; + int ret = -1; + + if (virAsprintf(&full, "%s\r", cmd) < 0) + return -1; + + len = strlen(full); + + switch (vm->monitor_chr->type) { + case VIR_DOMAIN_CHR_TYPE_UNIX: + if (qemudMonitorSendUnix(vm, full, len, scm_fd) < 0) + goto out; + break; + default: + case VIR_DOMAIN_CHR_TYPE_PTY: + if (safewrite(vm->monitor, full, len) != len) + goto out; + break; + } + + ret = 0; +out: + VIR_FREE(full); + return ret; +} + +int +qemudMonitorCommandWithHandler(const virDomainObjPtr vm, + const char *cmd, + const char *extraPrompt, + qemudMonitorExtraPromptHandler extraHandler, + void *handlerData, + int scm_fd, + char **reply) { + int size = 0; + char *buf = NULL; + + /* Should never happen, but just in case, protect + * against null monitor (ocurrs when VM is inactive) */ + if (!vm->monitor_chr) + return -1; + + qemuMonitorDiscardPendingData(vm); + + VIR_DEBUG("Send '%s'", cmd); + if (qemudMonitorSend(vm, cmd, scm_fd) < 0) + return -1; + + *reply = NULL; + + for (;;) { + struct pollfd fd = { vm->monitor, POLLIN | POLLERR | POLLHUP, 0 }; + char *tmp; + + /* Read all the data QEMU has sent thus far */ + for (;;) { + char data[1024]; + int got = read(vm->monitor, data, sizeof(data)); + + if (got == 0) + goto error; + if (got < 0) { + if (errno == EINTR) + continue; + if (errno == EAGAIN) + break; + goto error; + } + if (VIR_REALLOC_N(buf, size+got+1) < 0) + goto error; + + memmove(buf+size, data, got); + buf[size+got] = '\0'; + size += got; + } + + /* Look for QEMU prompt to indicate completion */ + if (buf) { + char *foundPrompt; + + if (extraPrompt && + (foundPrompt = strstr(buf, extraPrompt)) != NULL) { + char *promptEnd; + + if (extraHandler(vm, buf, foundPrompt, handlerData) < 0) + return -1; + /* Discard output so far, necessary to detect whether + extraPrompt appears again. We don't need the output between + original command and this prompt anyway. */ + promptEnd = foundPrompt + strlen(extraPrompt); + memmove(buf, promptEnd, strlen(promptEnd)+1); + size -= promptEnd - buf; + } else if ((tmp = strstr(buf, QEMU_CMD_PROMPT)) != NULL) { + char *commptr = NULL, *nlptr = NULL; + /* Preserve the newline */ + tmp[1] = '\0'; + + /* The monitor doesn't dump clean output after we have written to + * it. Every character we write dumps a bunch of useless stuff, + * so the result looks like "cXcoXcomXcommXcommaXcommanXcommand" + * Try to throw away everything before the first full command + * occurence, and inbetween the command and the newline starting + * the response + */ + if ((commptr = strstr(buf, cmd))) { + memmove(buf, commptr, strlen(commptr)+1); + if ((nlptr = strchr(buf, '\n'))) + memmove(buf+strlen(cmd), nlptr, strlen(nlptr)+1); + } + + break; + } + } + pollagain: + /* Need to wait for more data */ + if (poll(&fd, 1, -1) < 0) { + if (errno == EINTR) + goto pollagain; + goto error; + } + } + *reply = buf; + return 0; + + error: + VIR_FREE(buf); + return -1; +} + +struct extraHandlerData +{ + const char *reply; + bool first; +}; + +static int +qemudMonitorCommandSimpleExtraHandler(const virDomainObjPtr vm, + const char *buf ATTRIBUTE_UNUSED, + const char *prompt ATTRIBUTE_UNUSED, + void *data_) +{ + struct extraHandlerData *data = data_; + + if (!data->first) + return 0; + if (qemudMonitorSend(vm, data->reply, -1) < 0) + return -1; + data->first = false; + return 0; +} + +int +qemudMonitorCommandExtra(const virDomainObjPtr vm, + const char *cmd, + const char *extra, + const char *extraPrompt, + int scm_fd, + char **reply) { + struct extraHandlerData data; + + data.reply = extra; + data.first = true; + return qemudMonitorCommandWithHandler(vm, cmd, extraPrompt, + qemudMonitorCommandSimpleExtraHandler, + &data, scm_fd, reply); +} + +int +qemudMonitorCommandWithFd(const virDomainObjPtr vm, + const char *cmd, + int scm_fd, + char **reply) { + return qemudMonitorCommandExtra(vm, cmd, NULL, NULL, scm_fd, reply); +} + +int +qemudMonitorCommand(const virDomainObjPtr vm, + const char *cmd, + char **reply) { + return qemudMonitorCommandWithFd(vm, cmd, -1, reply); +} + + + +static virStorageEncryptionPtr +findDomainDiskEncryption(virConnectPtr conn, virDomainObjPtr vm, + const char *path) +{ + bool seen_volume; + int i; + + seen_volume = false; + for (i = 0; i < vm->def->ndisks; i++) { + virDomainDiskDefPtr disk; + + disk = vm->def->disks[i]; + if (disk->src != NULL && STREQ(disk->src, path)) { + seen_volume = true; + if (disk->encryption != NULL) + return disk->encryption; + } + } + if (seen_volume) + qemudReportError(conn, NULL, NULL, VIR_ERR_INVALID_DOMAIN, + _("missing <encryption> for volume %s"), path); + else + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("unexpected passphrase request for volume %s"), + path); + return NULL; +} + +static char * +findVolumeQcowPassphrase(virConnectPtr conn, virDomainObjPtr vm, + const char *path, size_t *passphrase_len) +{ + virStorageEncryptionPtr enc; + virSecretPtr secret; + char *passphrase; + unsigned char *data; + size_t size; + + if (conn->secretDriver == NULL || + conn->secretDriver->lookupByUUID == NULL || + conn->secretDriver->getValue == NULL) { + qemudReportError(conn, NULL, NULL, VIR_ERR_NO_SUPPORT, "%s", + _("secret storage not supported")); + return NULL; + } + + enc = findDomainDiskEncryption(conn, vm, path); + if (enc == NULL) + return NULL; + + if (enc->format != VIR_STORAGE_ENCRYPTION_FORMAT_QCOW || + enc->nsecrets != 1 || + enc->secrets[0]->type != + VIR_STORAGE_ENCRYPTION_SECRET_TYPE_PASSPHRASE) { + qemudReportError(conn, NULL, NULL, VIR_ERR_INVALID_DOMAIN, + _("invalid <encryption> for volume %s"), path); + return NULL; + } + + secret = conn->secretDriver->lookupByUUID(conn, + enc->secrets[0]->uuid); + if (secret == NULL) + return NULL; + data = conn->secretDriver->getValue(secret, &size, + VIR_SECRET_GET_VALUE_INTERNAL_CALL); + virUnrefSecret(secret); + if (data == NULL) + return NULL; + + if (memchr(data, '\0', size) != NULL) { + memset(data, 0, size); + VIR_FREE(data); + qemudReportError(conn, NULL, NULL, VIR_ERR_INVALID_SECRET, + _("format='qcow' passphrase for %s must not contain a " + "'\\0'"), path); + return NULL; + } + + if (VIR_ALLOC_N(passphrase, size + 1) < 0) { + memset(data, 0, size); + VIR_FREE(data); + virReportOOMError(conn); + return NULL; + } + memcpy(passphrase, data, size); + passphrase[size] = '\0'; + + memset(data, 0, size); + VIR_FREE(data); + + *passphrase_len = size; + return passphrase; +} + +static int +qemudMonitorSendVolumePassphrase(const virDomainObjPtr vm, + const char *buf, + const char *prompt, + void *data) +{ + virConnectPtr conn = data; + char *passphrase, *path; + const char *prompt_path; + size_t path_len, passphrase_len = 0; + int res; + + /* The complete prompt looks like this: + ide0-hd0 (/path/to/volume) is encrypted. + Password: + "prompt" starts with ") is encrypted". Extract /path/to/volume. */ + for (prompt_path = prompt; prompt_path > buf && prompt_path[-1] != '('; + prompt_path--) + ; + if (prompt_path == buf) + return -1; + path_len = prompt - prompt_path; + if (VIR_ALLOC_N(path, path_len + 1) < 0) + return -1; + memcpy(path, prompt_path, path_len); + path[path_len] = '\0'; + + passphrase = findVolumeQcowPassphrase(conn, vm, path, &passphrase_len); + VIR_FREE(path); + if (passphrase == NULL) + return -1; + + res = qemudMonitorSend(vm, passphrase, -1); + + memset(passphrase, 0, passphrase_len); + VIR_FREE(passphrase); + + return res; +} + +int +qemudMonitorSendCont(virConnectPtr conn, + const virDomainObjPtr vm) { + char *reply; + + if (qemudMonitorCommandWithHandler(vm, "cont", ") is encrypted.", + qemudMonitorSendVolumePassphrase, conn, + -1, &reply) < 0) + return -1; + qemudDebug ("%s: cont reply: %s", vm->def->name, info); + VIR_FREE(reply); + return 0; +} diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h new file mode 100644 index 0000000..35ca81d --- /dev/null +++ b/src/qemu/qemu_monitor_text.h @@ -0,0 +1,72 @@ +/* + * qemu_monitor.h: interaction with QEMU monitor console + * + * Copyright (C) 2006-2009 Red Hat, Inc. + * Copyright (C) 2006 Daniel P. Berrange + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Daniel P. Berrange <berrange@redhat.com> + */ + + +#ifndef QEMU_MONITOR_TEXT_H +#define QEMU_MONITOR_TEXT_H + +#include "internal.h" + +#include "domain_conf.h" + +/* XXX remove these two from public header */ +#define QEMU_CMD_PROMPT "\n(qemu) " +#define QEMU_PASSWD_PROMPT "Password: " + +/* Return -1 for error, 0 for success */ +typedef int qemudMonitorExtraPromptHandler(const virDomainObjPtr vm, + const char *buf, + const char *prompt, + void *data); + +/* These first 4 APIs are generic monitor interaction. They will + * go away eventually + */ +int qemudMonitorCommand(const virDomainObjPtr vm, + const char *cmd, + char **reply); +int qemudMonitorCommandWithFd(const virDomainObjPtr vm, + const char *cmd, + int scm_fd, + char **reply); +int qemudMonitorCommandWithHandler(const virDomainObjPtr vm, + const char *cmd, + const char *extraPrompt, + qemudMonitorExtraPromptHandler extraHandler, + void *handlerData, + int scm_fd, + char **reply); +int qemudMonitorCommandExtra(const virDomainObjPtr vm, + const char *cmd, + const char *extra, + const char *extraPrompt, + int scm_fd, + char **reply); + +/* Formal APIs for each required monitor command */ + +int qemudMonitorSendCont(virConnectPtr conn, + const virDomainObjPtr vm); + +#endif /* QEMU_MONITOR_TEXT_H */ + -- 1.6.2.5

On Thu, 2009-09-24 at 16:00 +0100, Daniel P. Berrange wrote:
Pull out all the QEMU monitor interaction code to a separate file. This will make life easier when we need to drop in a new implementation for the forthcoming QMP machine friendly monitor support.
Next step is to add formal APIs for each monitor command, and remove direct commands for sending/receiving generic data.
* src/Makefile.am: Add qemu_monitor.c to build * src/qemu/qemu_driver.c: Remove code for monitor interaction * src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h: New file for monitor interaction --- src/Makefile.am | 1 + src/qemu/qemu_driver.c | 426 +---------------------------------------- src/qemu/qemu_monitor_text.c | 437 ++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 72 +++++++ 4 files changed, 511 insertions(+), 425 deletions(-) create mode 100644 src/qemu/qemu_monitor_text.c create mode 100644 src/qemu/qemu_monitor_text.h
diff --git a/src/Makefile.am b/src/Makefile.am index 9cbec47..7520e96 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -169,6 +169,7 @@ VBOX_DRIVER_EXTRA_DIST = vbox/vbox_tmpl.c vbox/README
QEMU_DRIVER_SOURCES = \ qemu/qemu_conf.c qemu/qemu_conf.h \ + qemu/qemu_monitor_text.c qemu/qemu_monitortext.h\
Typo
qemu/qemu_driver.c qemu/qemu_driver.h
UML_DRIVER_SOURCES = \
...
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c new file mode 100644 index 0000000..76842a5 --- /dev/null +++ b/src/qemu/qemu_monitor_text.c @@ -0,0 +1,437 @@ +/* + * qemu_monitor.h: interaction with QEMU monitor console + *
Incorrect header ...
+ if (seen_volume) + qemudReportError(conn, NULL, NULL, VIR_ERR_INVALID_DOMAIN, + _("missing <encryption> for volume %s"), path); + else + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("unexpected passphrase request for volume %s"), + path);
Need qemu_monitor_text.c in POTFILES.in Otherwise, ACK Cheers, Mark.

* src/qemu/qemu_monitor.h, src/qemu/qemu_monitor.c: Add a new qemuMonitorGetCPUInfo() command * src/qemu/qemu_driver.c: Refactor qemudDetectVcpuPIDs to use qemuMonitorGetCPUInfo() --- src/qemu/qemu_driver.c | 114 ++++++++++-------------------------------- src/qemu/qemu_monitor_text.c | 85 +++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 4 +- 3 files changed, 115 insertions(+), 88 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 9f17aae..30d1468 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -110,8 +110,8 @@ static int qemudDomainGetMaxVcpus(virDomainPtr dom); static int qemudDomainSetMemoryBalloon(virConnectPtr conn, virDomainObjPtr vm, unsigned long newmem); -static int qemudDetectVcpuPIDs(virConnectPtr conn, - virDomainObjPtr vm); +static int qemuDetectVcpuPIDs(virConnectPtr conn, + virDomainObjPtr vm); static int qemuUpdateActivePciHostdevs(struct qemud_driver *driver, virDomainDefPtr def); @@ -1186,100 +1186,40 @@ qemudWaitForMonitor(virConnectPtr conn, } static int -qemudDetectVcpuPIDs(virConnectPtr conn, - virDomainObjPtr vm) { - char *qemucpus = NULL; - char *line; - int lastVcpu = -1; - - /* Only KVM has seperate threads for CPUs, - others just use main QEMU process for CPU */ - if (vm->def->virtType != VIR_DOMAIN_VIRT_KVM) - vm->nvcpupids = 1; - else - vm->nvcpupids = vm->def->vcpus; - - if (VIR_ALLOC_N(vm->vcpupids, vm->nvcpupids) < 0) { - virReportOOMError(conn); - return -1; - } +qemuDetectVcpuPIDs(virConnectPtr conn, + virDomainObjPtr vm) { + pid_t *cpupids = NULL; + int ncpupids; if (vm->def->virtType != VIR_DOMAIN_VIRT_KVM) { + vm->nvcpupids = 1; + if (VIR_ALLOC_N(vm->vcpupids, vm->nvcpupids) < 0) { + virReportOOMError(conn); + return -1; + } vm->vcpupids[0] = vm->pid; return 0; } - if (qemudMonitorCommand(vm, "info cpus", &qemucpus) < 0) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("cannot run monitor command to fetch CPU thread info")); - VIR_FREE(vm->vcpupids); - vm->nvcpupids = 0; - return -1; - } - - /* - * This is the gross format we're about to parse :-{ - * - * (qemu) info cpus - * * CPU #0: pc=0x00000000000f0c4a thread_id=30019 - * CPU #1: pc=0x00000000fffffff0 thread_id=30020 - * CPU #2: pc=0x00000000fffffff0 thread_id=30021 - * - */ - line = qemucpus; - do { - char *offset = strchr(line, '#'); - char *end = NULL; - int vcpu = 0, tid = 0; - - /* See if we're all done */ - if (offset == NULL) - break; + /* What follows is now all KVM specific */ - /* Extract VCPU number */ - if (virStrToLong_i(offset + 1, &end, 10, &vcpu) < 0) - goto error; - if (end == NULL || *end != ':') - goto error; - - /* Extract host Thread ID */ - if ((offset = strstr(line, "thread_id=")) == NULL) - goto error; - if (virStrToLong_i(offset + strlen("thread_id="), &end, 10, &tid) < 0) - goto error; - if (end == NULL || !c_isspace(*end)) - goto error; - - /* Validate the VCPU is in expected range & order */ - if (vcpu > vm->nvcpupids || - vcpu != (lastVcpu + 1)) - goto error; - - lastVcpu = vcpu; - vm->vcpupids[vcpu] = tid; - - /* Skip to next data line */ - line = strchr(offset, '\r'); - if (line == NULL) - line = strchr(offset, '\n'); - } while (line != NULL); - - /* Validate we got data for all VCPUs we expected */ - if (lastVcpu != (vm->def->vcpus - 1)) - goto error; + if ((ncpupids = qemuMonitorGetCPUInfo(vm, &cpupids)) < 0) + return -1; - VIR_FREE(qemucpus); - return 0; + /* Treat failure to get VCPU<->PID mapping as non-fatal */ + if (ncpupids == 0) + return 0; -error: - VIR_FREE(vm->vcpupids); - vm->nvcpupids = 0; - VIR_FREE(qemucpus); + if (ncpupids != vm->def->vcpus) { + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("got wrong number of vCPU pids from QEMU monitor. got %d, wanted %d"), + ncpupids, (int)vm->def->vcpus); + VIR_FREE(cpupids); + return -1; + } - /* Explicitly return success, not error. Older KVM does - not have vCPU -> Thread mapping info and we don't - want to break its use. This merely disables ability - to pin vCPUS with libvirt */ + vm->nvcpupids = ncpupids; + vm->vcpupids = cpupids; return 0; } @@ -2202,7 +2142,7 @@ static int qemudStartVMDaemon(virConnectPtr conn, goto cleanup; if ((qemudWaitForMonitor(conn, driver, vm, pos) < 0) || - (qemudDetectVcpuPIDs(conn, vm) < 0) || + (qemuDetectVcpuPIDs(conn, vm) < 0) || (qemudInitCpus(conn, vm, migrateFrom) < 0) || (qemudInitPasswords(conn, driver, vm) < 0) || (qemudDomainSetMemoryBalloon(conn, vm, vm->def->memory) < 0) || diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 76842a5..d93e475 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -31,6 +31,7 @@ #include "qemu_monitor_text.h" #include "qemu_conf.h" +#include "c-ctype.h" #include "memory.h" #include "logging.h" #include "driver.h" @@ -435,3 +436,87 @@ qemudMonitorSendCont(virConnectPtr conn, VIR_FREE(reply); return 0; } + + +int qemuMonitorGetCPUInfo(const virDomainObjPtr vm, + int **pids) +{ + char *qemucpus = NULL; + char *line; + int lastVcpu = -1; + pid_t *cpupids = NULL; + size_t ncpupids = 0; + + if (qemudMonitorCommand(vm, "info cpus", &qemucpus) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + "%s", _("cannot run monitor command to fetch CPU thread info")); + return -1; + } + + /* + * This is the gross format we're about to parse :-{ + * + * (qemu) info cpus + * * CPU #0: pc=0x00000000000f0c4a thread_id=30019 + * CPU #1: pc=0x00000000fffffff0 thread_id=30020 + * CPU #2: pc=0x00000000fffffff0 thread_id=30021 + * + */ + line = qemucpus; + do { + char *offset = strchr(line, '#'); + char *end = NULL; + int vcpu = 0, tid = 0; + + /* See if we're all done */ + if (offset == NULL) + break; + + /* Extract VCPU number */ + if (virStrToLong_i(offset + 1, &end, 10, &vcpu) < 0) + goto error; + + if (end == NULL || *end != ':') + goto error; + + /* Extract host Thread ID */ + if ((offset = strstr(line, "thread_id=")) == NULL) + goto error; + + if (virStrToLong_i(offset + strlen("thread_id="), &end, 10, &tid) < 0) + goto error; + if (end == NULL || !c_isspace(*end)) + goto error; + + if (vcpu != (lastVcpu + 1)) + goto error; + + if (VIR_REALLOC_N(cpupids, ncpupids+1) < 0) + goto error; + + cpupids[ncpupids++] = tid; + lastVcpu = vcpu; + + /* Skip to next data line */ + line = strchr(offset, '\r'); + if (line == NULL) + line = strchr(offset, '\n'); + } while (line != NULL); + + /* Validate we got data for all VCPUs we expected */ + VIR_FREE(qemucpus); + *pids = cpupids; + return ncpupids; + +error: + VIR_FREE(qemucpus); + VIR_FREE(cpupids); + + /* Returning 0 to indicate non-fatal failure, since + * older QEMU does not have VCPU<->PID mapping and + * we don't want to fail on that + */ + return 0; +} + + diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index 35ca81d..973c3b6 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -68,5 +68,7 @@ int qemudMonitorCommandExtra(const virDomainObjPtr vm, int qemudMonitorSendCont(virConnectPtr conn, const virDomainObjPtr vm); -#endif /* QEMU_MONITOR_TEXT_H */ +int qemuMonitorGetCPUInfo(const virDomainObjPtr vm, + int **pids); +#endif /* QEMU_MONITOR_TEXT_H */ -- 1.6.2.5

On Thu, 2009-09-24 at 16:00 +0100, Daniel P. Berrange wrote:
* src/qemu/qemu_monitor.h, src/qemu/qemu_monitor.c: Add a new qemuMonitorGetCPUInfo() command * src/qemu/qemu_driver.c: Refactor qemudDetectVcpuPIDs to use qemuMonitorGetCPUInfo() --- src/qemu/qemu_driver.c | 114 ++++++++++-------------------------------- src/qemu/qemu_monitor_text.c | 85 +++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 4 +- 3 files changed, 115 insertions(+), 88 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 9f17aae..30d1468 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c ... diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 76842a5..d93e475 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -31,6 +31,7 @@
#include "qemu_monitor_text.h" #include "qemu_conf.h" +#include "c-ctype.h" #include "memory.h" #include "logging.h" #include "driver.h" @@ -435,3 +436,87 @@ qemudMonitorSendCont(virConnectPtr conn, VIR_FREE(reply); return 0; } + + +int qemuMonitorGetCPUInfo(const virDomainObjPtr vm, + int **pids) +{ + char *qemucpus = NULL; + char *line; + int lastVcpu = -1; + pid_t *cpupids = NULL; + size_t ncpupids = 0; + + if (qemudMonitorCommand(vm, "info cpus", &qemucpus) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + "%s", _("cannot run monitor command to fetch CPU thread info")); + return -1; + }
Not passing conn to ReportError in most monitor functions now; is that a problem? ACK Cheers, Mark.

On Mon, Sep 28, 2009 at 02:22:46PM +0100, Mark McLoughlin wrote:
On Thu, 2009-09-24 at 16:00 +0100, Daniel P. Berrange wrote:
* src/qemu/qemu_monitor.h, src/qemu/qemu_monitor.c: Add a new qemuMonitorGetCPUInfo() command * src/qemu/qemu_driver.c: Refactor qemudDetectVcpuPIDs to use qemuMonitorGetCPUInfo() --- src/qemu/qemu_driver.c | 114 ++++++++++-------------------------------- src/qemu/qemu_monitor_text.c | 85 +++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 4 +- 3 files changed, 115 insertions(+), 88 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 9f17aae..30d1468 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c ... diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 76842a5..d93e475 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -31,6 +31,7 @@
#include "qemu_monitor_text.h" #include "qemu_conf.h" +#include "c-ctype.h" #include "memory.h" #include "logging.h" #include "driver.h" @@ -435,3 +436,87 @@ qemudMonitorSendCont(virConnectPtr conn, VIR_FREE(reply); return 0; } + + +int qemuMonitorGetCPUInfo(const virDomainObjPtr vm, + int **pids) +{ + char *qemucpus = NULL; + char *line; + int lastVcpu = -1; + pid_t *cpupids = NULL; + size_t ncpupids = 0; + + if (qemudMonitorCommand(vm, "info cpus", &qemucpus) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + "%s", _("cannot run monitor command to fetch CPU thread info")); + return -1; + }
Not passing conn to ReportError in most monitor functions now; is that a problem?
Historically we needed to pass virConnectPtr around everywhere so that errors would be reported against the connection. When we went multi- threaded, all errors started being reported in a global thread local. The public API entrypoints in src/libvirt.c copy the error across to the per-virConnectPtr error variable for back-compatability right at the end. Thus it is pointless passing virConnectPtr around to all functions internally, except for places which use it for something unrelated to error reporting[1]. In fact passing virConnectPtr around everywhere has actually caused several crashes in the past, because there are some codepaths where we do not have any virConnectPtr available, and thus just pass NULL. Later codepaths mistakenly assumeed that the virConnectPtr was non-NULL with predictably crashtastic results. I'd like to set a goal of removing the virConnectPtr parameters from *all* internal methods, except for the top level driver API method implementations whose API signature obviously matches the public API. The only place we still need to pass virConnectPtr is in places like the QEMU driver which access the conn->networkDriver or conn->secretDriver fields. Addressing that will be more difficult - it would need us to change the way we activate secondary drivers, so the primary driver held a direct reference to the desired secondary driver. I'm not going to attempt that any time soon, but we can still trivially eliminate the virConnectPtr param from 95% of all internal methods. Regards, Daniel [1] Not entirely accurate, because we there is possibility of registering a callback function against a virConnectPtr for receiving errors. This is currently very very unsafe because the callback may be invoked deep inside libvirt internal code where countless locks are held. The invocation of the callbacks needs to be moved right up to the top in src/libvirt.c at the same place as all the virSetConnError() calls. -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add a new qemuMonitorSetVNCPassword() API * src/qemu/qemu_driver.c: Refactor qemudInitPasswords to call qemuMonitorSetVNCPassword() --- src/qemu/qemu_driver.c | 24 ++++++++---------------- src/qemu/qemu_monitor_text.c | 15 +++++++++++++++ src/qemu/qemu_monitor_text.h | 3 +++ 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 30d1468..e0b7c84 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -1275,29 +1275,21 @@ qemudInitCpus(virConnectPtr conn, static int -qemudInitPasswords(virConnectPtr conn, - struct qemud_driver *driver, +qemudInitPasswords(struct qemud_driver *driver, virDomainObjPtr vm) { - char *info = NULL; + int ret = 0; if ((vm->def->ngraphics == 1) && vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC && (vm->def->graphics[0]->data.vnc.passwd || driver->vncPassword)) { - if (qemudMonitorCommandExtra(vm, "change vnc password", - vm->def->graphics[0]->data.vnc.passwd ? - vm->def->graphics[0]->data.vnc.passwd : - driver->vncPassword, - QEMU_PASSWD_PROMPT, - -1, &info) < 0) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("setting VNC password failed")); - return -1; - } - VIR_FREE(info); + ret = qemuMonitorSetVNCPassword(vm, + vm->def->graphics[0]->data.vnc.passwd ? + vm->def->graphics[0]->data.vnc.passwd : + driver->vncPassword); } - return 0; + return ret; } @@ -2144,7 +2136,7 @@ static int qemudStartVMDaemon(virConnectPtr conn, if ((qemudWaitForMonitor(conn, driver, vm, pos) < 0) || (qemuDetectVcpuPIDs(conn, vm) < 0) || (qemudInitCpus(conn, vm, migrateFrom) < 0) || - (qemudInitPasswords(conn, driver, vm) < 0) || + (qemudInitPasswords(driver, vm) < 0) || (qemudDomainSetMemoryBalloon(conn, vm, vm->def->memory) < 0) || (virDomainSaveStatus(conn, driver->stateDir, vm) < 0)) { qemudShutdownVMDaemon(conn, driver, vm); diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index d93e475..ba28f02 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -520,3 +520,18 @@ error: } +int qemuMonitorSetVNCPassword(const virDomainObjPtr vm, + const char *password) +{ + char *info = NULL; + if (qemudMonitorCommandExtra(vm, "change vnc password", + password, + QEMU_PASSWD_PROMPT, + -1, &info) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + "%s", _("setting VNC password failed")); + return -1; + } + VIR_FREE(info); + return 0; +} diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index 973c3b6..fd0fa61 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -71,4 +71,7 @@ int qemudMonitorSendCont(virConnectPtr conn, int qemuMonitorGetCPUInfo(const virDomainObjPtr vm, int **pids); +int qemuMonitorSetVNCPassword(const virDomainObjPtr vm, + const char *password); + #endif /* QEMU_MONITOR_TEXT_H */ -- 1.6.2.5

On Thu, 2009-09-24 at 16:00 +0100, Daniel P. Berrange wrote:
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add a new qemuMonitorSetVNCPassword() API * src/qemu/qemu_driver.c: Refactor qemudInitPasswords to call qemuMonitorSetVNCPassword() --- src/qemu/qemu_driver.c | 24 ++++++++---------------- src/qemu/qemu_monitor_text.c | 15 +++++++++++++++ src/qemu/qemu_monitor_text.h | 3 +++ 3 files changed, 26 insertions(+), 16 deletions(-)
... ACK Cheers, Mark.

* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Rename Rename qemudMonitorSendCont to qemuMonitorStartCPUs * src/qemu/qemu_driver.c: Update callers for new name --- src/qemu/qemu_driver.c | 18 +++++++++--------- src/qemu/qemu_monitor_text.c | 2 +- src/qemu/qemu_monitor_text.h | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index e0b7c84..1717cbd 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -1262,7 +1262,7 @@ qemudInitCpus(virConnectPtr conn, if (migrateFrom == NULL) { /* Allow the CPUS to start executing */ - if (qemudMonitorSendCont(conn, vm) < 0) { + if (qemuMonitorStartCPUs(conn, vm) < 0) { if (virGetLastError() == NULL) qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s", _("resume operation failed")); @@ -1275,8 +1275,8 @@ qemudInitCpus(virConnectPtr conn, static int -qemudInitPasswords(struct qemud_driver *driver, - virDomainObjPtr vm) { +qemuInitPasswords(struct qemud_driver *driver, + virDomainObjPtr vm) { int ret = 0; if ((vm->def->ngraphics == 1) && @@ -2136,7 +2136,7 @@ static int qemudStartVMDaemon(virConnectPtr conn, if ((qemudWaitForMonitor(conn, driver, vm, pos) < 0) || (qemuDetectVcpuPIDs(conn, vm) < 0) || (qemudInitCpus(conn, vm, migrateFrom) < 0) || - (qemudInitPasswords(driver, vm) < 0) || + (qemuInitPasswords(driver, vm) < 0) || (qemudDomainSetMemoryBalloon(conn, vm, vm->def->memory) < 0) || (virDomainSaveStatus(conn, driver->stateDir, vm) < 0)) { qemudShutdownVMDaemon(conn, driver, vm); @@ -2819,7 +2819,7 @@ static int qemudDomainResume(virDomainPtr dom) { goto cleanup; } if (vm->state == VIR_DOMAIN_PAUSED) { - if (qemudMonitorSendCont(dom->conn, vm) < 0) { + if (qemuMonitorStartCPUs(dom->conn, vm) < 0) { if (virGetLastError() == NULL) qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, "%s", _("resume operation failed")); @@ -3579,7 +3579,7 @@ cleanup: will support synchronous operations so we always get here after the migration is complete. */ if (resume && paused) { - if (qemudMonitorSendCont(dom->conn, vm) < 0) { + if (qemuMonitorStartCPUs(dom->conn, vm) < 0) { if (virGetLastError() == NULL) qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, "%s", _("resuming after dump failed")); @@ -4095,7 +4095,7 @@ static int qemudDomainRestore(virConnectPtr conn, /* If it was running before, resume it now. */ if (header.was_running) { - if (qemudMonitorSendCont(conn, vm) < 0) { + if (qemuMonitorStartCPUs(conn, vm) < 0) { if (virGetLastError() == NULL) qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED, "%s", _("failed to resume domain")); @@ -6828,7 +6828,7 @@ qemudDomainMigratePerform (virDomainPtr dom, cleanup: if (paused) { /* we got here through some sort of failure; start the domain again */ - if (qemudMonitorSendCont(dom->conn, vm) < 0) { + if (qemuMonitorStartCPUs(dom->conn, vm) < 0) { /* Hm, we already know we are in error here. We don't want to * overwrite the previous error, though, so we just throw something * to the logs and hope for the best @@ -6884,7 +6884,7 @@ qemudDomainMigrateFinish2 (virConnectPtr dconn, * >= 0.10.6 to work properly. This isn't strictly necessary on * older qemu's, but it also doesn't hurt anything there */ - if (qemudMonitorSendCont(dconn, vm) < 0) { + if (qemuMonitorStartCPUs(dconn, vm) < 0) { if (virGetLastError() == NULL) qemudReportError(dconn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s", _("resume operation failed")); diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index ba28f02..3c12073 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -424,7 +424,7 @@ qemudMonitorSendVolumePassphrase(const virDomainObjPtr vm, } int -qemudMonitorSendCont(virConnectPtr conn, +qemuMonitorStartCPUs(virConnectPtr conn, const virDomainObjPtr vm) { char *reply; diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index fd0fa61..2632ecf 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -65,7 +65,7 @@ int qemudMonitorCommandExtra(const virDomainObjPtr vm, /* Formal APIs for each required monitor command */ -int qemudMonitorSendCont(virConnectPtr conn, +int qemuMonitorStartCPUs(virConnectPtr conn, const virDomainObjPtr vm); int qemuMonitorGetCPUInfo(const virDomainObjPtr vm, -- 1.6.2.5

On Thu, 2009-09-24 at 16:00 +0100, Daniel P. Berrange wrote:
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Rename Rename qemudMonitorSendCont to qemuMonitorStartCPUs * src/qemu/qemu_driver.c: Update callers for new name --- src/qemu/qemu_driver.c | 18 +++++++++--------- src/qemu/qemu_monitor_text.c | 2 +- src/qemu/qemu_monitor_text.h | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index e0b7c84..1717cbd 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c ... @@ -1275,8 +1275,8 @@ qemudInitCpus(virConnectPtr conn,
static int -qemudInitPasswords(struct qemud_driver *driver, - virDomainObjPtr vm) { +qemuInitPasswords(struct qemud_driver *driver, + virDomainObjPtr vm) {
Completely unrelated ACK Cheers, Mark.

* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add a new qemuMonitorStopCPUs() API * src/qemu/qemu_driver.c: Replace direct monitor commands for 'stop' with qemuMonitorStopCPUs() --- src/qemu/qemu_driver.c | 28 ++++------------------------ src/qemu/qemu_monitor_text.c | 13 +++++++++++++ src/qemu/qemu_monitor_text.h | 1 + 3 files changed, 18 insertions(+), 24 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 1717cbd..5ebd4b7 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -2749,7 +2749,6 @@ cleanup: static int qemudDomainSuspend(virDomainPtr dom) { struct qemud_driver *driver = dom->conn->privateData; - char *info; virDomainObjPtr vm; int ret = -1; virDomainEventPtr event = NULL; @@ -2770,17 +2769,12 @@ static int qemudDomainSuspend(virDomainPtr dom) { goto cleanup; } if (vm->state != VIR_DOMAIN_PAUSED) { - if (qemudMonitorCommand(vm, "stop", &info) < 0) { - qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - "%s", _("suspend operation failed")); + if (qemuMonitorStopCPUs(vm) < 0) goto cleanup; - } vm->state = VIR_DOMAIN_PAUSED; - qemudDebug("Reply %s", info); event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_SUSPENDED, VIR_DOMAIN_EVENT_SUSPENDED_PAUSED); - VIR_FREE(info); } if (virDomainSaveStatus(dom->conn, driver->stateDir, vm) < 0) goto cleanup; @@ -3365,13 +3359,9 @@ static int qemudDomainSave(virDomainPtr dom, /* Pause */ if (vm->state == VIR_DOMAIN_RUNNING) { header.was_running = 1; - if (qemudMonitorCommand(vm, "stop", &info) < 0) { - qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - "%s", _("suspend operation failed")); + if (qemuMonitorStopCPUs(vm) < 0) goto cleanup; - } vm->state = VIR_DOMAIN_PAUSED; - qemudDebug("Reply %s", info); VIR_FREE(info); } @@ -3527,13 +3517,8 @@ static int qemudDomainCoreDump(virDomainPtr dom, /* Pause domain for non-live dump */ if (vm->state == VIR_DOMAIN_RUNNING) { - if (qemudMonitorCommand (vm, "stop", &info) < 0) { - qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - "%s", _("suspending before dump failed")); + if (qemuMonitorStopCPUs(vm) < 0) goto cleanup; - } - DEBUG ("%s: stop reply: %s", vm->def->name, info); - VIR_FREE(info); paused = 1; } @@ -6747,13 +6732,8 @@ qemudDomainMigratePerform (virDomainPtr dom, if (!(flags & VIR_MIGRATE_LIVE)) { /* Pause domain for non-live migration */ - if (qemudMonitorCommand (vm, "stop", &info) < 0) { - qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - "%s", _("off-line migration specified, but suspend operation failed")); + if (qemuMonitorStopCPUs(vm) < 0) goto cleanup; - } - DEBUG ("%s: stop reply: %s", vm->def->name, info); - VIR_FREE(info); paused = 1; event = virDomainEventNewFromObj(vm, diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 3c12073..ec30e72 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -438,6 +438,19 @@ qemuMonitorStartCPUs(virConnectPtr conn, } +int +qemuMonitorStopCPUs(const virDomainObjPtr vm) { + char *info; + + if (qemudMonitorCommand(vm, "stop", &info) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + "%s", _("cannot stop CPU execution")); + return -1; + } + VIR_FREE(info); + return 0; +} + int qemuMonitorGetCPUInfo(const virDomainObjPtr vm, int **pids) { diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index 2632ecf..eb1ba44 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -67,6 +67,7 @@ int qemudMonitorCommandExtra(const virDomainObjPtr vm, int qemuMonitorStartCPUs(virConnectPtr conn, const virDomainObjPtr vm); +int qemuMonitorStopCPUs(const virDomainObjPtr vm); int qemuMonitorGetCPUInfo(const virDomainObjPtr vm, int **pids); -- 1.6.2.5

On Thu, 2009-09-24 at 16:00 +0100, Daniel P. Berrange wrote:
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add a new qemuMonitorStopCPUs() API * src/qemu/qemu_driver.c: Replace direct monitor commands for 'stop' with qemuMonitorStopCPUs() --- src/qemu/qemu_driver.c | 28 ++++------------------------ src/qemu/qemu_monitor_text.c | 13 +++++++++++++ src/qemu/qemu_monitor_text.h | 1 + 3 files changed, 18 insertions(+), 24 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 1717cbd..5ebd4b7 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -2749,7 +2749,6 @@ cleanup:
static int qemudDomainSuspend(virDomainPtr dom) { struct qemud_driver *driver = dom->conn->privateData; - char *info; virDomainObjPtr vm; int ret = -1; virDomainEventPtr event = NULL; @@ -2770,17 +2769,12 @@ static int qemudDomainSuspend(virDomainPtr dom) { goto cleanup; } if (vm->state != VIR_DOMAIN_PAUSED) { - if (qemudMonitorCommand(vm, "stop", &info) < 0) { - qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - "%s", _("suspend operation failed")); + if (qemuMonitorStopCPUs(vm) < 0) goto cleanup; - } vm->state = VIR_DOMAIN_PAUSED; - qemudDebug("Reply %s", info); event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_SUSPENDED, VIR_DOMAIN_EVENT_SUSPENDED_PAUSED); - VIR_FREE(info); } if (virDomainSaveStatus(dom->conn, driver->stateDir, vm) < 0) goto cleanup; @@ -3365,13 +3359,9 @@ static int qemudDomainSave(virDomainPtr dom, /* Pause */ if (vm->state == VIR_DOMAIN_RUNNING) { header.was_running = 1; - if (qemudMonitorCommand(vm, "stop", &info) < 0) { - qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - "%s", _("suspend operation failed")); + if (qemuMonitorStopCPUs(vm) < 0) goto cleanup; - } vm->state = VIR_DOMAIN_PAUSED; - qemudDebug("Reply %s", info); VIR_FREE(info);
Shouldn't be free-ing info here ...
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 3c12073..ec30e72 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -438,6 +438,19 @@ qemuMonitorStartCPUs(virConnectPtr conn, }
+int +qemuMonitorStopCPUs(const virDomainObjPtr vm) { + char *info; + + if (qemudMonitorCommand(vm, "stop", &info) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + "%s", _("cannot stop CPU execution")); + return -1; + } + VIR_FREE(info);
Lost debugging of replies here, but you re-add it again in 26/27 ACK Cheers, Mark.

On Mon, Sep 28, 2009 at 02:22:49PM +0100, Mark McLoughlin wrote:
On Thu, 2009-09-24 at 16:00 +0100, Daniel P. Berrange wrote:
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add a new qemuMonitorStopCPUs() API * src/qemu/qemu_driver.c: Replace direct monitor commands for 'stop' with qemuMonitorStopCPUs() --- src/qemu/qemu_driver.c | 28 ++++------------------------ src/qemu/qemu_monitor_text.c | 13 +++++++++++++ src/qemu/qemu_monitor_text.h | 1 + 3 files changed, 18 insertions(+), 24 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 1717cbd..5ebd4b7 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -2749,7 +2749,6 @@ cleanup:
static int qemudDomainSuspend(virDomainPtr dom) { struct qemud_driver *driver = dom->conn->privateData; - char *info; virDomainObjPtr vm; int ret = -1; virDomainEventPtr event = NULL; @@ -2770,17 +2769,12 @@ static int qemudDomainSuspend(virDomainPtr dom) { goto cleanup; } if (vm->state != VIR_DOMAIN_PAUSED) { - if (qemudMonitorCommand(vm, "stop", &info) < 0) { - qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - "%s", _("suspend operation failed")); + if (qemuMonitorStopCPUs(vm) < 0) goto cleanup; - } vm->state = VIR_DOMAIN_PAUSED; - qemudDebug("Reply %s", info); event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_SUSPENDED, VIR_DOMAIN_EVENT_SUSPENDED_PAUSED); - VIR_FREE(info); } if (virDomainSaveStatus(dom->conn, driver->stateDir, vm) < 0) goto cleanup; @@ -3365,13 +3359,9 @@ static int qemudDomainSave(virDomainPtr dom, /* Pause */ if (vm->state == VIR_DOMAIN_RUNNING) { header.was_running = 1; - if (qemudMonitorCommand(vm, "stop", &info) < 0) { - qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - "%s", _("suspend operation failed")); + if (qemuMonitorStopCPUs(vm) < 0) goto cleanup; - } vm->state = VIR_DOMAIN_PAUSED; - qemudDebug("Reply %s", info); VIR_FREE(info);
Shouldn't be free-ing info here
Hmm, 'info' probbaly shouldn't even exist in this method anymore. I'll check if its removed by a later patch in the series - probably only killed it once I added the new methods for migration.
...
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 3c12073..ec30e72 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -438,6 +438,19 @@ qemuMonitorStartCPUs(virConnectPtr conn, }
+int +qemuMonitorStopCPUs(const virDomainObjPtr vm) { + char *info; + + if (qemudMonitorCommand(vm, "stop", &info) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + "%s", _("cannot stop CPU execution")); + return -1; + } + VIR_FREE(info);
Lost debugging of replies here, but you re-add it again in 26/27
The original code was quite inconsistent about logging the reply data, so I didn't worry too much about copying that across perfectly during the course of the series, since I planned a thorough santization in the last patch of the series. Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

* src/qemu/qemu_driver.c: Remove use of 'system_powerdown' * src/qemu/qemu_monitor.h, src/qemu/qemu_monitor.c: Add a new qemuMonitorSystemPowerdown() api call --- src/qemu/qemu_driver.c | 8 ++------ src/qemu/qemu_monitor_text.c | 14 ++++++++++++++ src/qemu/qemu_monitor_text.h | 2 ++ 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 5ebd4b7..841ab68 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -2841,7 +2841,6 @@ cleanup: static int qemudDomainShutdown(virDomainPtr dom) { struct qemud_driver *driver = dom->conn->privateData; virDomainObjPtr vm; - char* info; int ret = -1; qemuDriverLock(driver); @@ -2862,12 +2861,9 @@ static int qemudDomainShutdown(virDomainPtr dom) { goto cleanup; } - if (qemudMonitorCommand(vm, "system_powerdown", &info) < 0) { - qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - "%s", _("shutdown operation failed")); + if (qemuMonitorSystemPowerdown(vm) < 0) goto cleanup; - } - VIR_FREE(info); + ret = 0; cleanup: diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index ec30e72..ec5f670 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -451,6 +451,20 @@ qemuMonitorStopCPUs(const virDomainObjPtr vm) { return 0; } + +int qemuMonitorSystemPowerdown(const virDomainObjPtr vm) { + char *info; + + if (qemudMonitorCommand(vm, "system_powerdown", &info) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + "%s", _("system shutdown operation failed")); + return -1; + } + VIR_FREE(info); + return 0; +} + + int qemuMonitorGetCPUInfo(const virDomainObjPtr vm, int **pids) { diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index eb1ba44..342a3f3 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -69,6 +69,8 @@ int qemuMonitorStartCPUs(virConnectPtr conn, const virDomainObjPtr vm); int qemuMonitorStopCPUs(const virDomainObjPtr vm); +int qemuMonitorSystemPowerdown(const virDomainObjPtr vm); + int qemuMonitorGetCPUInfo(const virDomainObjPtr vm, int **pids); -- 1.6.2.5

On Thu, 2009-09-24 at 16:00 +0100, Daniel P. Berrange wrote:
* src/qemu/qemu_driver.c: Remove use of 'system_powerdown' * src/qemu/qemu_monitor.h, src/qemu/qemu_monitor.c: Add a new qemuMonitorSystemPowerdown() api call --- src/qemu/qemu_driver.c | 8 ++------ src/qemu/qemu_monitor_text.c | 14 ++++++++++++++ src/qemu/qemu_monitor_text.h | 2 ++ 3 files changed, 18 insertions(+), 6 deletions(-)
ACK Cheers, Mark.

* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Pull old qemudDomainGetMemoryBalloon() code into a new method called qemuMonitorGetBalloonInfo() * src/qemu/qemu_driver.c: Update to call qemuMonitorGetBalloonInfo() and remove qemudDomainGetMemoryBalloon(). --- src/qemu/qemu_driver.c | 62 ++++++----------------------------------- src/qemu/qemu_monitor_text.c | 42 ++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 2 + 3 files changed, 53 insertions(+), 53 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 841ab68..8d3c9b6 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -2999,53 +2999,6 @@ cleanup: } -/* The reply from QEMU contains 'ballon: actual=421' where value is in MB */ -#define BALLOON_PREFIX "balloon: actual=" - -/* - * Returns: 0 if balloon not supported, +1 if balloon query worked - * or -1 on failure - */ -static int qemudDomainGetMemoryBalloon(virConnectPtr conn, - virDomainObjPtr vm, - unsigned long *currmem) { - char *reply = NULL; - int ret = -1; - char *offset; - - if (!virDomainIsActive(vm)) - return 0; - - if (qemudMonitorCommand(vm, "info balloon", &reply) < 0) { - qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - "%s", _("could not query memory balloon allocation")); - goto cleanup; - } - - DEBUG ("%s: balloon reply: '%s'", vm->def->name, reply); - if ((offset = strstr(reply, BALLOON_PREFIX)) != NULL) { - unsigned int memMB; - char *end; - offset += strlen(BALLOON_PREFIX); - if (virStrToLong_ui(offset, &end, 10, &memMB) < 0) { - qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - "%s", _("could not parse memory balloon allocation")); - goto cleanup; - } - *currmem = memMB * 1024; - ret = 1; - } else { - /* We don't raise an error here, since its to be expected that - * many QEMU's don't support ballooning - */ - ret = 0; - } - -cleanup: - VIR_FREE(reply); - return ret; -} - /* * Returns: 0 if balloon not supported, +1 if balloon query worked * or -1 on failure @@ -3161,7 +3114,7 @@ static int qemudDomainGetInfo(virDomainPtr dom, info->maxMem = vm->def->maxmem; if (virDomainIsActive(vm)) { - err = qemudDomainGetMemoryBalloon(dom->conn, vm, &balloon); + err = qemuMonitorGetBalloonInfo(vm, &balloon); if (err < 0) goto cleanup; @@ -4122,11 +4075,14 @@ static char *qemudDomainDumpXML(virDomainPtr dom, } /* Refresh current memory based on balloon info */ - err = qemudDomainGetMemoryBalloon(dom->conn, vm, &balloon); - if (err < 0) - goto cleanup; - if (err > 0) - vm->def->memory = balloon; + if (virDomainIsActive(vm)) { + err = qemuMonitorGetBalloonInfo(vm, &balloon); + if (err < 0) + goto cleanup; + if (err > 0) + vm->def->memory = balloon; + /* err == 0 indicates no balloon support, so ignore it */ + } ret = virDomainDefFormat(dom->conn, (flags & VIR_DOMAIN_XML_INACTIVE) && vm->newDef ? diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index ec5f670..2a20db3 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -547,6 +547,48 @@ error: } + +/* The reply from QEMU contains 'ballon: actual=421' where value is in MB */ +#define BALLOON_PREFIX "balloon: actual=" + +int qemuMonitorGetBalloonInfo(const virDomainObjPtr vm, + unsigned long *currmem) +{ + char *reply = NULL; + int ret = -1; + char *offset; + + if (qemudMonitorCommand(vm, "info balloon", &reply) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + "%s", _("could not query memory balloon allocation")); + return -1; + } + + DEBUG ("%s: balloon reply: '%s'", vm->def->name, reply); + if ((offset = strstr(reply, BALLOON_PREFIX)) != NULL) { + unsigned int memMB; + char *end; + offset += strlen(BALLOON_PREFIX); + if (virStrToLong_ui(offset, &end, 10, &memMB) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + _("could not parse memory balloon allocation from '%s'"), reply); + goto cleanup; + } + *currmem = memMB * 1024; + ret = 1; + } else { + /* We don't raise an error here, since its to be expected that + * many QEMU's don't support ballooning + */ + ret = 0; + } + +cleanup: + VIR_FREE(reply); + return ret; +} + + int qemuMonitorSetVNCPassword(const virDomainObjPtr vm, const char *password) { diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index 342a3f3..43b59e2 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -73,6 +73,8 @@ int qemuMonitorSystemPowerdown(const virDomainObjPtr vm); int qemuMonitorGetCPUInfo(const virDomainObjPtr vm, int **pids); +int qemuMonitorGetBalloonInfo(const virDomainObjPtr vm, + unsigned long *currmem); int qemuMonitorSetVNCPassword(const virDomainObjPtr vm, const char *password); -- 1.6.2.5

On Thu, 2009-09-24 at 16:00 +0100, Daniel P. Berrange wrote:
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Pull old qemudDomainGetMemoryBalloon() code into a new method called qemuMonitorGetBalloonInfo() * src/qemu/qemu_driver.c: Update to call qemuMonitorGetBalloonInfo() and remove qemudDomainGetMemoryBalloon(). --- src/qemu/qemu_driver.c | 62 ++++++----------------------------------- src/qemu/qemu_monitor_text.c | 42 ++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 2 + 3 files changed, 53 insertions(+), 53 deletions(-) ...
ACK Cheers, Mark.

* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add new qemuMonitorSetBalloon() based on existing code in qemudDomainSetMemoryBalloon * src/qemu/qemu_driver.c: Remove use of qemudDomainSetMemoryBalloon() in favour of qemuMonitorSetBalloon(). Fix error code when balloon is not supported --- src/qemu/qemu_driver.c | 56 ++++------------------------------------- src/qemu/qemu_monitor_text.c | 47 +++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 2 + 3 files changed, 55 insertions(+), 50 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 8d3c9b6..a0b5e49 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -107,9 +107,6 @@ static void qemudShutdownVMDaemon(virConnectPtr conn, static int qemudDomainGetMaxVcpus(virDomainPtr dom); -static int qemudDomainSetMemoryBalloon(virConnectPtr conn, - virDomainObjPtr vm, - unsigned long newmem); static int qemuDetectVcpuPIDs(virConnectPtr conn, virDomainObjPtr vm); @@ -2137,7 +2134,7 @@ static int qemudStartVMDaemon(virConnectPtr conn, (qemuDetectVcpuPIDs(conn, vm) < 0) || (qemudInitCpus(conn, vm, migrateFrom) < 0) || (qemuInitPasswords(driver, vm) < 0) || - (qemudDomainSetMemoryBalloon(conn, vm, vm->def->memory) < 0) || + (qemuMonitorSetBalloon(vm, vm->def->memory) < 0) || (virDomainSaveStatus(conn, driver->stateDir, vm) < 0)) { qemudShutdownVMDaemon(conn, driver, vm); ret = -1; @@ -2999,50 +2996,6 @@ cleanup: } -/* - * Returns: 0 if balloon not supported, +1 if balloon query worked - * or -1 on failure - */ -static int qemudDomainSetMemoryBalloon(virConnectPtr conn, - virDomainObjPtr vm, - unsigned long newmem) { - char *cmd; - char *reply = NULL; - int ret = -1; - - /* - * 'newmem' is in KB, QEMU monitor works in MB, and we all wish - * we just worked in bytes with unsigned long long everywhere. - */ - if (virAsprintf(&cmd, "balloon %lu", (newmem / 1024)) < 0) { - virReportOOMError(conn); - goto cleanup; - } - - if (qemudMonitorCommand(vm, cmd, &reply) < 0) { - qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - "%s", _("could not balloon memory allocation")); - VIR_FREE(cmd); - goto cleanup; - } - VIR_FREE(cmd); - - /* If the command failed qemu prints: 'unknown command' - * No message is printed on success it seems */ - DEBUG ("%s: balloon reply: %s",vm->def->name, reply); - if (strstr(reply, "\nunknown command:")) { - /* Don't set error - it is expected memory balloon fails on many qemu */ - ret = 0; - } else { - ret = 1; - } - -cleanup: - VIR_FREE(reply); - return ret; -} - - static int qemudDomainSetMemory(virDomainPtr dom, unsigned long newmem) { struct qemud_driver *driver = dom->conn->privateData; virDomainObjPtr vm; @@ -3066,10 +3019,13 @@ static int qemudDomainSetMemory(virDomainPtr dom, unsigned long newmem) { } if (virDomainIsActive(vm)) { - ret = qemudDomainSetMemoryBalloon(dom->conn, vm, newmem); - if (ret == 0) + ret = qemuMonitorSetBalloon(vm, newmem); + /* Turn lack of balloon support into a fatal error */ + if (ret == 0) { qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT, "%s", _("cannot set memory of an active domain")); + ret = -1; + } } else { vm->def->memory = newmem; ret = 0; diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 2a20db3..be13dce 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -551,6 +551,10 @@ error: /* The reply from QEMU contains 'ballon: actual=421' where value is in MB */ #define BALLOON_PREFIX "balloon: actual=" +/* + * Returns: 0 if balloon not supported, +1 if balloon query worked + * or -1 on failure + */ int qemuMonitorGetBalloonInfo(const virDomainObjPtr vm, unsigned long *currmem) { @@ -604,3 +608,46 @@ int qemuMonitorSetVNCPassword(const virDomainObjPtr vm, VIR_FREE(info); return 0; } + +/* + * Returns: 0 if balloon not supported, +1 if balloon adjust worked + * or -1 on failure + */ +int qemuMonitorSetBalloon(const virDomainObjPtr vm, + unsigned long newmem) +{ + char *cmd; + char *reply = NULL; + int ret = -1; + + /* + * 'newmem' is in KB, QEMU monitor works in MB, and we all wish + * we just worked in bytes with unsigned long long everywhere. + */ + if (virAsprintf(&cmd, "balloon %lu", (newmem / 1024)) < 0) { + virReportOOMError(NULL); + return -1; + } + + if (qemudMonitorCommand(vm, cmd, &reply) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + "%s", _("could not balloon memory allocation")); + VIR_FREE(cmd); + return -1; + } + VIR_FREE(cmd); + + /* If the command failed qemu prints: 'unknown command' + * No message is printed on success it seems */ + DEBUG ("%s: balloon reply: %s", vm->def->name, reply); + if (strstr(reply, "\nunknown command:")) { + /* Don't set error - it is expected memory balloon fails on many qemu */ + ret = 0; + } else { + ret = 1; + } + + VIR_FREE(reply); + return ret; +} + diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index 43b59e2..e115791 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -78,5 +78,7 @@ int qemuMonitorGetBalloonInfo(const virDomainObjPtr vm, int qemuMonitorSetVNCPassword(const virDomainObjPtr vm, const char *password); +int qemuMonitorSetBalloon(const virDomainObjPtr vm, + unsigned long newmem); #endif /* QEMU_MONITOR_TEXT_H */ -- 1.6.2.5

On Thu, 2009-09-24 at 16:00 +0100, Daniel P. Berrange wrote:
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add new qemuMonitorSetBalloon() based on existing code in qemudDomainSetMemoryBalloon * src/qemu/qemu_driver.c: Remove use of qemudDomainSetMemoryBalloon() in favour of qemuMonitorSetBalloon(). Fix error code when balloon is not supported --- src/qemu/qemu_driver.c | 56 ++++------------------------------------- src/qemu/qemu_monitor_text.c | 47 +++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 2 + 3 files changed, 55 insertions(+), 50 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 8d3c9b6..a0b5e49 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c ... @@ -3066,10 +3019,13 @@ static int qemudDomainSetMemory(virDomainPtr dom, unsigned long newmem) { }
if (virDomainIsActive(vm)) { - ret = qemudDomainSetMemoryBalloon(dom->conn, vm, newmem); - if (ret == 0) + ret = qemuMonitorSetBalloon(vm, newmem); + /* Turn lack of balloon support into a fatal error */ + if (ret == 0) { qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT, "%s", _("cannot set memory of an active domain")); + ret = -1; + }
Making this an error condition is new; would have been nice as a preceeding patch
} else { vm->def->memory = newmem; ret = 0; diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 2a20db3..be13dce 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -551,6 +551,10 @@ error: /* The reply from QEMU contains 'ballon: actual=421' where value is in MB */ #define BALLOON_PREFIX "balloon: actual="
+/* + * Returns: 0 if balloon not supported, +1 if balloon query worked + * or -1 on failure + */ int qemuMonitorGetBalloonInfo(const virDomainObjPtr vm, unsigned long *currmem) {
Should be in previous patch ACK Cheers, Mark.

* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add new APis qemuMonitorChangeMedia and qemuMonitorEjectMedia. Pull in code for qemudEscape * src/qemu/qemu_driver.c: Remove code that directly issues 'eject' and 'change' commands in favour of API calls. --- src/qemu/qemu_driver.c | 52 +++----------- src/qemu/qemu_monitor_text.c | 159 ++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 10 +++ 3 files changed, 178 insertions(+), 43 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index a0b5e49..b15dc03 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4573,9 +4573,9 @@ static int qemudDomainChangeEjectableMedia(virConnectPtr conn, unsigned int qemuCmdFlags) { virDomainDiskDefPtr origdisk = NULL, newdisk; - char *cmd, *reply, *safe_path; char *devname = NULL; int i; + int ret; origdisk = NULL; newdisk = dev->data.disk; @@ -4621,52 +4621,18 @@ static int qemudDomainChangeEjectableMedia(virConnectPtr conn, } if (newdisk->src) { - safe_path = qemudEscapeMonitorArg(newdisk->src); - if (!safe_path) { - virReportOOMError(conn); - VIR_FREE(devname); - return -1; - } - if (virAsprintf(&cmd, "change %s \"%s\"", devname, safe_path) == -1) { - virReportOOMError(conn); - VIR_FREE(safe_path); - VIR_FREE(devname); - return -1; - } - VIR_FREE(safe_path); - - } else if (virAsprintf(&cmd, "eject %s", devname) == -1) { - virReportOOMError(conn); - VIR_FREE(devname); - return -1; - } - VIR_FREE(devname); - - if (qemudMonitorCommand(vm, cmd, &reply) < 0) { - qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - "%s", _("could not change cdrom media")); - VIR_FREE(cmd); - return -1; + ret = qemuMonitorChangeMedia(vm, devname, newdisk->src); + } else { + ret = qemuMonitorEjectMedia(vm, devname); } - /* If the command failed qemu prints: - * device not found, device is locked ... - * No message is printed on success it seems */ - DEBUG ("%s: ejectable media change reply: %s", vm->def->name, reply); - if (strstr(reply, "\ndevice ")) { - qemudReportError (conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - _("changing cdrom media failed: %s"), reply); - VIR_FREE(reply); - VIR_FREE(cmd); - return -1; + if (ret == 0) { + VIR_FREE(origdisk->src); + origdisk->src = newdisk->src; + newdisk->src = NULL; + origdisk->type = newdisk->type; } - VIR_FREE(reply); - VIR_FREE(cmd); - VIR_FREE(origdisk->src); - origdisk->src = newdisk->src; - newdisk->src = NULL; - origdisk->type = newdisk->type; return 0; } diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index be13dce..8be8047 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -40,6 +40,84 @@ #define VIR_FROM_THIS VIR_FROM_QEMU +static char *qemudEscape(const char *in, int shell) +{ + int len = 0; + int i, j; + char *out; + + /* To pass through the QEMU monitor, we need to use escape + sequences: \r, \n, \", \\ + + To pass through both QEMU + the shell, we need to escape + the single character ' as the five characters '\\'' + */ + + for (i = 0; in[i] != '\0'; i++) { + switch(in[i]) { + case '\r': + case '\n': + case '"': + case '\\': + len += 2; + break; + case '\'': + if (shell) + len += 5; + else + len += 1; + break; + default: + len += 1; + break; + } + } + + if (VIR_ALLOC_N(out, len + 1) < 0) + return NULL; + + for (i = j = 0; in[i] != '\0'; i++) { + switch(in[i]) { + case '\r': + out[j++] = '\\'; + out[j++] = 'r'; + break; + case '\n': + out[j++] = '\\'; + out[j++] = 'n'; + break; + case '"': + case '\\': + out[j++] = '\\'; + out[j++] = in[i]; + break; + case '\'': + if (shell) { + out[j++] = '\''; + out[j++] = '\\'; + out[j++] = '\\'; + out[j++] = '\''; + out[j++] = '\''; + } else { + out[j++] = in[i]; + } + break; + default: + out[j++] = in[i]; + break; + } + } + out[j] = '\0'; + + return out; +} + +static char *qemudEscapeMonitorArg(const char *in) +{ + return qemudEscape(in, 0); +} + + /* Throw away any data available on the monitor * This is done before executing a command, in order * to allow re-synchronization if something went badly @@ -651,3 +729,84 @@ int qemuMonitorSetBalloon(const virDomainObjPtr vm, return ret; } +int qemuMonitorEjectMedia(const virDomainObjPtr vm, + const char *devname) +{ + char *cmd = NULL; + char *reply = NULL; + int ret = -1; + + if (virAsprintf(&cmd, "eject %s", devname) < 0) { + virReportOOMError(NULL); + goto cleanup; + } + + if (qemudMonitorCommand(vm, cmd, &reply) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + _("could not eject media on %s"), devname); + goto cleanup; + } + + /* If the command failed qemu prints: + * device not found, device is locked ... + * No message is printed on success it seems */ + DEBUG ("%s: ejectable media change reply: %s", vm->def->name, reply); + if (strstr(reply, "\ndevice ")) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + _("could not eject media on %s: %s"), devname, reply); + goto cleanup; + } + + ret = 0; + +cleanup: + VIR_FREE(reply); + VIR_FREE(cmd); + return ret; +} + + +int qemuMonitorChangeMedia(const virDomainObjPtr vm, + const char *devname, + const char *newmedia) +{ + char *cmd = NULL; + char *reply = NULL; + char *safepath = NULL; + int ret = -1; + + if (!(safepath = qemudEscapeMonitorArg(newmedia))) { + virReportOOMError(NULL); + goto cleanup; + } + + if (virAsprintf(&cmd, "change %s \"%s\"", devname, safepath) < 0) { + virReportOOMError(NULL); + goto cleanup; + } + + if (qemudMonitorCommand(vm, cmd, &reply) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + _("could not eject media on %s"), devname); + goto cleanup; + } + + /* If the command failed qemu prints: + * device not found, device is locked ... + * No message is printed on success it seems */ + DEBUG ("%s: ejectable media change reply: %s", vm->def->name, reply); + if (strstr(reply, "\ndevice ")) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + _("could not eject media on %s: %s"), devname, reply); + goto cleanup; + } + + ret = 0; + +cleanup: + VIR_FREE(reply); + VIR_FREE(cmd); + VIR_FREE(safepath); + return ret; +} + diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index e115791..d05dea1 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -81,4 +81,14 @@ int qemuMonitorSetVNCPassword(const virDomainObjPtr vm, int qemuMonitorSetBalloon(const virDomainObjPtr vm, unsigned long newmem); +/* XXX should we pass the virDomainDiskDefPtr instead + * and hide devname details inside monitor. Reconsider + * this when doing the QMP implementation + */ +int qemuMonitorEjectMedia(const virDomainObjPtr vm, + const char *devname); +int qemuMonitorChangeMedia(const virDomainObjPtr vm, + const char *devname, + const char *newmedia); + #endif /* QEMU_MONITOR_TEXT_H */ -- 1.6.2.5

On Thu, 2009-09-24 at 16:00 +0100, Daniel P. Berrange wrote:
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add new APis qemuMonitorChangeMedia and qemuMonitorEjectMedia. Pull in code for qemudEscape * src/qemu/qemu_driver.c: Remove code that directly issues 'eject' and 'change' commands in favour of API calls. --- src/qemu/qemu_driver.c | 52 +++----------- src/qemu/qemu_monitor_text.c | 159 ++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 10 +++ 3 files changed, 178 insertions(+), 43 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index a0b5e49..b15dc03 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4573,9 +4573,9 @@ static int qemudDomainChangeEjectableMedia(virConnectPtr conn, unsigned int qemuCmdFlags) { virDomainDiskDefPtr origdisk = NULL, newdisk; - char *cmd, *reply, *safe_path; char *devname = NULL; int i; + int ret;
origdisk = NULL; newdisk = dev->data.disk; @@ -4621,52 +4621,18 @@ static int qemudDomainChangeEjectableMedia(virConnectPtr conn, }
if (newdisk->src) { - safe_path = qemudEscapeMonitorArg(newdisk->src); - if (!safe_path) { - virReportOOMError(conn); - VIR_FREE(devname); - return -1; - } - if (virAsprintf(&cmd, "change %s \"%s\"", devname, safe_path) == -1) { - virReportOOMError(conn); - VIR_FREE(safe_path); - VIR_FREE(devname); - return -1; - } - VIR_FREE(safe_path); - - } else if (virAsprintf(&cmd, "eject %s", devname) == -1) { - virReportOOMError(conn); - VIR_FREE(devname); - return -1; - } - VIR_FREE(devname); - - if (qemudMonitorCommand(vm, cmd, &reply) < 0) { - qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - "%s", _("could not change cdrom media")); - VIR_FREE(cmd); - return -1; + ret = qemuMonitorChangeMedia(vm, devname, newdisk->src); + } else { + ret = qemuMonitorEjectMedia(vm, devname); }
- /* If the command failed qemu prints: - * device not found, device is locked ... - * No message is printed on success it seems */ - DEBUG ("%s: ejectable media change reply: %s", vm->def->name, reply); - if (strstr(reply, "\ndevice ")) { - qemudReportError (conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - _("changing cdrom media failed: %s"), reply); - VIR_FREE(reply); - VIR_FREE(cmd); - return -1; + if (ret == 0) { + VIR_FREE(origdisk->src); + origdisk->src = newdisk->src; + newdisk->src = NULL; + origdisk->type = newdisk->type; } - VIR_FREE(reply); - VIR_FREE(cmd);
- VIR_FREE(origdisk->src); - origdisk->src = newdisk->src; - newdisk->src = NULL; - origdisk->type = newdisk->type; return 0;
Should return ret here
}
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index be13dce..8be8047 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -40,6 +40,84 @@
#define VIR_FROM_THIS VIR_FROM_QEMU
+static char *qemudEscape(const char *in, int shell) +{
Personally, rather than creating a copy of the code, I'd have moved it and exported it back to qemu_driver.c - end result is the same, but the way you've done it, I couldn't just look at the patch to confirm that the copy of the code was the same as the original ...
@@ -651,3 +729,84 @@ int qemuMonitorSetBalloon(const virDomainObjPtr vm, return ret; }
+int qemuMonitorEjectMedia(const virDomainObjPtr vm, + const char *devname) +{ + char *cmd = NULL; + char *reply = NULL; + int ret = -1; + + if (virAsprintf(&cmd, "eject %s", devname) < 0) { + virReportOOMError(NULL); + goto cleanup; + } + + if (qemudMonitorCommand(vm, cmd, &reply) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + _("could not eject media on %s"), devname); + goto cleanup; + } + + /* If the command failed qemu prints: + * device not found, device is locked ... + * No message is printed on success it seems */ + DEBUG ("%s: ejectable media change reply: %s", vm->def->name, reply); + if (strstr(reply, "\ndevice ")) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + _("could not eject media on %s: %s"), devname, reply); + goto cleanup; + } + + ret = 0; + +cleanup: + VIR_FREE(reply); + VIR_FREE(cmd); + return ret; +} + + +int qemuMonitorChangeMedia(const virDomainObjPtr vm, + const char *devname, + const char *newmedia) +{ + char *cmd = NULL; + char *reply = NULL; + char *safepath = NULL; + int ret = -1; + + if (!(safepath = qemudEscapeMonitorArg(newmedia))) { + virReportOOMError(NULL); + goto cleanup; + } + + if (virAsprintf(&cmd, "change %s \"%s\"", devname, safepath) < 0) { + virReportOOMError(NULL); + goto cleanup; + } + + if (qemudMonitorCommand(vm, cmd, &reply) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + _("could not eject media on %s"), devname); + goto cleanup; + } + + /* If the command failed qemu prints: + * device not found, device is locked ... + * No message is printed on success it seems */ + DEBUG ("%s: ejectable media change reply: %s", vm->def->name, reply); + if (strstr(reply, "\ndevice ")) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + _("could not eject media on %s: %s"), devname, reply); + goto cleanup; + }
Pity this code is duplicated Should be 'could not eject' here Otherwise, ACK Cheers, Mark.

* src/qemu/qemu_monitor.h, src/qemu/qemu_monitor.c: Add new APIs qemuMonitorSaveVirtualMemory() and qemuMonitorSavePhysicalMemory() * src/qemu/qemu_driver.c: Use the new qemuMonitorSaveVirtualMemory() and qemuMonitorSavePhysicalMemory() APIs --- src/qemu/qemu_driver.c | 21 ++++----------- src/qemu/qemu_monitor_text.c | 54 ++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 10 +++++++ 3 files changed, 70 insertions(+), 15 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index b15dc03..9c09024 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -6233,7 +6233,6 @@ qemudDomainMemoryPeek (virDomainPtr dom, { struct qemud_driver *driver = dom->conn->privateData; virDomainObjPtr vm; - char cmd[256], *info = NULL; char *tmp = NULL; int fd = -1, ret = -1; @@ -6273,21 +6272,14 @@ qemudDomainMemoryPeek (virDomainPtr dom, goto cleanup; } - if (flags == VIR_MEMORY_VIRTUAL) - /* Issue the memsave command. */ - snprintf (cmd, sizeof cmd, "memsave %llu %zi \"%s\"", offset, size, tmp); - else - /* Issue the pmemsave command. */ - snprintf (cmd, sizeof cmd, "pmemsave %llu %zi \"%s\"", offset, size, tmp); - - if (qemudMonitorCommand (vm, cmd, &info) < 0) { - qemudReportError (dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - "%s", _("'memsave' command failed")); - goto cleanup; + if (flags == VIR_MEMORY_VIRTUAL) { + if (qemuMonitorSaveVirtualMemory(vm, offset, size, tmp) < 0) + goto cleanup; + } else { + if (qemuMonitorSavePhysicalMemory(vm, offset, size, tmp) < 0) + goto cleanup; } - DEBUG ("%s: (p)memsave reply: %s", vm->def->name, info); - /* Read the memory file into buffer. */ if (saferead (fd, buffer, size) == (ssize_t) -1) { virReportSystemError (dom->conn, errno, @@ -6300,7 +6292,6 @@ qemudDomainMemoryPeek (virDomainPtr dom, cleanup: VIR_FREE(tmp); - VIR_FREE(info); if (fd >= 0) close (fd); unlink (tmp); if (vm) diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 8be8047..a5f43c5 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -810,3 +810,57 @@ cleanup: return ret; } +static int qemuMonitorSaveMemory(const virDomainObjPtr vm, + const char *cmdtype, + unsigned long long offset, + size_t length, + const char *path) +{ + char *cmd = NULL; + char *reply = NULL; + char *safepath = NULL; + int ret = -1; + + if (!(safepath = qemudEscapeMonitorArg(path))) { + virReportOOMError(NULL); + goto cleanup; + } + + if (virAsprintf(&cmd, "%s %llu %zi \"%s\"", cmdtype, offset, length, safepath) < 0) { + virReportOOMError(NULL); + goto cleanup; + } + + if (qemudMonitorCommand(vm, cmd, &reply) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + _("could save memory region to '%s'"), path); + goto cleanup; + } + + /* XXX what is printed on failure ? */ + + ret = 0; + +cleanup: + VIR_FREE(cmd); + VIR_FREE(reply); + VIR_FREE(safepath); + return ret; +} + + +int qemuMonitorSaveVirtualMemory(const virDomainObjPtr vm, + unsigned long long offset, + size_t length, + const char *path) +{ + return qemuMonitorSaveMemory(vm, "memsave", offset, length, path); +} + +int qemuMonitorSavePhysicalMemory(const virDomainObjPtr vm, + unsigned long long offset, + size_t length, + const char *path) +{ + return qemuMonitorSaveMemory(vm, "pmemsave", offset, length, path); +} diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index d05dea1..dfe3445 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -91,4 +91,14 @@ int qemuMonitorChangeMedia(const virDomainObjPtr vm, const char *devname, const char *newmedia); + +int qemuMonitorSaveVirtualMemory(const virDomainObjPtr vm, + unsigned long long offset, + size_t length, + const char *path); +int qemuMonitorSavePhysicalMemory(const virDomainObjPtr vm, + unsigned long long offset, + size_t length, + const char *path); + #endif /* QEMU_MONITOR_TEXT_H */ -- 1.6.2.5

On Thu, 2009-09-24 at 16:00 +0100, Daniel P. Berrange wrote:
* src/qemu/qemu_monitor.h, src/qemu/qemu_monitor.c: Add new APIs qemuMonitorSaveVirtualMemory() and qemuMonitorSavePhysicalMemory() * src/qemu/qemu_driver.c: Use the new qemuMonitorSaveVirtualMemory() and qemuMonitorSavePhysicalMemory() APIs --- src/qemu/qemu_driver.c | 21 ++++----------- src/qemu/qemu_monitor_text.c | 54 ++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 10 +++++++ 3 files changed, 70 insertions(+), 15 deletions(-)
...
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 8be8047..a5f43c5 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -810,3 +810,57 @@ cleanup: return ret; }
+static int qemuMonitorSaveMemory(const virDomainObjPtr vm, + const char *cmdtype, + unsigned long long offset, + size_t length, + const char *path) +{ + char *cmd = NULL; + char *reply = NULL; + char *safepath = NULL; + int ret = -1; + + if (!(safepath = qemudEscapeMonitorArg(path))) { + virReportOOMError(NULL); + goto cleanup; + }
That's new, would have made sense as a separate patch
+ + if (virAsprintf(&cmd, "%s %llu %zi \"%s\"", cmdtype, offset, length, safepath) < 0) { + virReportOOMError(NULL); + goto cleanup; + } + + if (qemudMonitorCommand(vm, cmd, &reply) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + _("could save memory region to '%s'"), path); + goto cleanup; + } + + /* XXX what is printed on failure ? */
No debug, but I assume that's fixed in 26/27 ACK Cheers, Mark.

* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add a new qemuMonitorGetBlockStatsInfo() command * src/qemu/qemu_driver.c: Remove directly use of blockstats in favour of calling qemuMonitorGetBlockStatsInfo() --- src/qemu/qemu_driver.c | 95 +++---------------------------------- src/qemu/qemu_monitor_text.c | 105 ++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 8 +++ 3 files changed, 121 insertions(+), 87 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 9c09024..f95c473 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -5958,10 +5958,7 @@ qemudDomainBlockStats (virDomainPtr dom, struct _virDomainBlockStats *stats) { struct qemud_driver *driver = dom->conn->privateData; - char *dummy, *info = NULL; - const char *p, *eol; const char *qemu_dev_name = NULL; - size_t len; int i, ret = -1; virDomainObjPtr vm; virDomainDiskDefPtr disk = NULL; @@ -5998,95 +5995,19 @@ qemudDomainBlockStats (virDomainPtr dom, qemu_dev_name = qemudDiskDeviceName(dom->conn, disk); if (!qemu_dev_name) goto cleanup; - len = strlen (qemu_dev_name); - if (qemudMonitorCommand (vm, "info blockstats", &info) < 0) { - qemudReportError (dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - "%s", _("'info blockstats' command failed")); - goto cleanup; - } - DEBUG ("%s: info blockstats reply: %s", vm->def->name, info); - - /* If the command isn't supported then qemu prints the supported - * info commands, so the output starts "info ". Since this is - * unlikely to be the name of a block device, we can use this - * to detect if qemu supports the command. - */ - if (strstr(info, "\ninfo ")) { - qemudReportError (dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT, - "%s", - _("'info blockstats' not supported by this qemu")); + if (qemuMonitorGetBlockStatsInfo(vm, qemu_dev_name, + &stats->rd_req, + &stats->rd_bytes, + &stats->wr_req, + &stats->wr_bytes, + &stats->errs) < 0) goto cleanup; - } - - stats->rd_req = -1; - stats->rd_bytes = -1; - stats->wr_req = -1; - stats->wr_bytes = -1; - stats->errs = -1; - - /* The output format for both qemu & KVM is: - * blockdevice: rd_bytes=% wr_bytes=% rd_operations=% wr_operations=% - * (repeated for each block device) - * where '%' is a 64 bit number. - */ - p = info; - - while (*p) { - if (STREQLEN (p, qemu_dev_name, len) - && p[len] == ':' && p[len+1] == ' ') { - - eol = strchr (p, '\n'); - if (!eol) - eol = p + strlen (p); - - p += len+2; /* Skip to first label. */ - - while (*p) { - if (STRPREFIX (p, "rd_bytes=")) { - p += 9; - if (virStrToLong_ll (p, &dummy, 10, &stats->rd_bytes) == -1) - DEBUG ("%s: error reading rd_bytes: %s", - vm->def->name, p); - } else if (STRPREFIX (p, "wr_bytes=")) { - p += 9; - if (virStrToLong_ll (p, &dummy, 10, &stats->wr_bytes) == -1) - DEBUG ("%s: error reading wr_bytes: %s", - vm->def->name, p); - } else if (STRPREFIX (p, "rd_operations=")) { - p += 14; - if (virStrToLong_ll (p, &dummy, 10, &stats->rd_req) == -1) - DEBUG ("%s: error reading rd_req: %s", - vm->def->name, p); - } else if (STRPREFIX (p, "wr_operations=")) { - p += 14; - if (virStrToLong_ll (p, &dummy, 10, &stats->wr_req) == -1) - DEBUG ("%s: error reading wr_req: %s", - vm->def->name, p); - } else - DEBUG ("%s: unknown block stat near %s", vm->def->name, p); - - /* 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++; - } + ret = 0; - /* If we reach here then the device was not found. */ - qemudReportError (dom->conn, dom, NULL, VIR_ERR_INVALID_ARG, - _("device not found: %s (%s)"), path, qemu_dev_name); - cleanup: +cleanup: VIR_FREE(qemu_dev_name); - VIR_FREE(info); if (vm) virDomainObjUnlock(vm); return ret; diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index a5f43c5..f35b1ef 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -671,6 +671,111 @@ cleanup: } +int qemuMonitorGetBlockStatsInfo(const virDomainObjPtr vm, + const char *devname, + long long *rd_req, + long long *rd_bytes, + long long *wr_req, + long long *wr_bytes, + long long *errs) +{ + char *info = NULL; + int ret = -1; + char *dummy; + const char *p, *eol; + int devnamelen = strlen(devname); + + if (qemudMonitorCommand (vm, "info blockstats", &info) < 0) { + qemudReportError (NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + "%s", _("'info blockstats' command failed")); + goto cleanup; + } + DEBUG ("%s: info blockstats reply: %s", vm->def->name, info); + + /* If the command isn't supported then qemu prints the supported + * info commands, so the output starts "info ". Since this is + * unlikely to be the name of a block device, we can use this + * to detect if qemu supports the command. + */ + if (strstr(info, "\ninfo ")) { + qemudReportError (NULL, NULL, NULL, VIR_ERR_NO_SUPPORT, + "%s", + _("'info blockstats' not supported by this qemu")); + goto cleanup; + } + + *rd_req = -1; + *rd_bytes = -1; + *wr_req = -1; + *wr_bytes = -1; + *errs = -1; + + /* The output format for both qemu & KVM is: + * blockdevice: rd_bytes=% wr_bytes=% rd_operations=% wr_operations=% + * (repeated for each block device) + * where '%' is a 64 bit number. + */ + p = info; + + while (*p) { + 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, "rd_bytes=")) { + p += 9; + if (virStrToLong_ll (p, &dummy, 10, rd_bytes) == -1) + DEBUG ("%s: error reading rd_bytes: %s", + vm->def->name, p); + } else if (STRPREFIX (p, "wr_bytes=")) { + p += 9; + if (virStrToLong_ll (p, &dummy, 10, wr_bytes) == -1) + DEBUG ("%s: error reading wr_bytes: %s", + vm->def->name, p); + } else if (STRPREFIX (p, "rd_operations=")) { + p += 14; + if (virStrToLong_ll (p, &dummy, 10, rd_req) == -1) + DEBUG ("%s: error reading rd_req: %s", + vm->def->name, p); + } else if (STRPREFIX (p, "wr_operations=")) { + p += 14; + if (virStrToLong_ll (p, &dummy, 10, wr_req) == -1) + DEBUG ("%s: error reading wr_req: %s", + vm->def->name, p); + } else + DEBUG ("%s: unknown block stat near %s", vm->def->name, p); + + /* 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++; + } + + /* If we reach here then the device was not found. */ + qemudReportError (NULL, NULL, NULL, VIR_ERR_INVALID_ARG, + _("no stats found for device %s"), devname); + + cleanup: + VIR_FREE(info); + return ret; +} + + int qemuMonitorSetVNCPassword(const virDomainObjPtr vm, const char *password) { diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index dfe3445..a047eba 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -75,6 +75,14 @@ int qemuMonitorGetCPUInfo(const virDomainObjPtr vm, int **pids); int qemuMonitorGetBalloonInfo(const virDomainObjPtr vm, unsigned long *currmem); +int qemuMonitorGetBlockStatsInfo(const virDomainObjPtr vm, + const char *devname, + long long *rd_req, + long long *rd_bytes, + long long *wr_req, + long long *wr_bytes, + long long *errs); + int qemuMonitorSetVNCPassword(const virDomainObjPtr vm, const char *password); -- 1.6.2.5

On Thu, 2009-09-24 at 16:00 +0100, Daniel P. Berrange wrote:
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add a new qemuMonitorGetBlockStatsInfo() command * src/qemu/qemu_driver.c: Remove directly use of blockstats in favour of calling qemuMonitorGetBlockStatsInfo() --- src/qemu/qemu_driver.c | 95 +++---------------------------------- src/qemu/qemu_monitor_text.c | 105 ++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 8 +++ 3 files changed, 121 insertions(+), 87 deletions(-)
... ACK Cheers, Mark.

* src/qemu/qemu_driver.c: Use new qemuMonitorSetMigrationSpeed() API during migration * src/qemu/qemu_monitor.h, src/qemu/qemu_monitor.c: Add new qemuMonitorSetMigrationSpeed() API --- src/qemu/qemu_driver.c | 11 +++-------- src/qemu/qemu_monitor_text.c | 28 ++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 3 +++ 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index f95c473..ccc13c4 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -6530,14 +6530,9 @@ qemudDomainMigratePerform (virDomainPtr dom, event = NULL; } - if (resource > 0) { - /* Issue migrate_set_speed command. Don't worry if it fails. */ - snprintf (cmd, sizeof cmd, "migrate_set_speed %lum", resource); - qemudMonitorCommand (vm, cmd, &info); - - DEBUG ("%s: migrate_set_speed reply: %s", vm->def->name, info); - VIR_FREE (info); - } + if (resource > 0 && + qemuMonitorSetMigrationSpeed(vm, resource) < 0) + goto cleanup; /* Issue the migrate command. */ safe_uri = qemudEscapeMonitorArg (uri); diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index f35b1ef..d9227a2 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -969,3 +969,31 @@ int qemuMonitorSavePhysicalMemory(const virDomainObjPtr vm, { return qemuMonitorSaveMemory(vm, "pmemsave", offset, length, path); } + + +int qemuMonitorSetMigrationSpeed(const virDomainObjPtr vm, + unsigned long bandwidth) +{ + char *cmd = NULL; + char *info = NULL; + int ret = -1; + + if (virAsprintf(&cmd, "migrate_set_speed %lum", bandwidth) < 0) { + virReportOOMError(NULL); + goto cleanup; + } + + if (qemudMonitorCommand (vm, cmd, &info) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + "%s", _("could restrict migration speed")); + goto cleanup; + } + + DEBUG ("%s: migrate_set_speed reply: %s", vm->def->name, info); + ret = 0; + +cleanup: + VIR_FREE (info); + VIR_FREE(cmd); + return ret; +} diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index a047eba..0591f3c 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -109,4 +109,7 @@ int qemuMonitorSavePhysicalMemory(const virDomainObjPtr vm, size_t length, const char *path); +int qemuMonitorSetMigrationSpeed(const virDomainObjPtr vm, + unsigned long bandwidth); + #endif /* QEMU_MONITOR_TEXT_H */ -- 1.6.2.5

On Thu, 2009-09-24 at 16:00 +0100, Daniel P. Berrange wrote:
* src/qemu/qemu_driver.c: Use new qemuMonitorSetMigrationSpeed() API during migration * src/qemu/qemu_monitor.h, src/qemu/qemu_monitor.c: Add new qemuMonitorSetMigrationSpeed() API --- src/qemu/qemu_driver.c | 11 +++-------- src/qemu/qemu_monitor_text.c | 28 ++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 3 +++ 3 files changed, 34 insertions(+), 8 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index f95c473..ccc13c4 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -6530,14 +6530,9 @@ qemudDomainMigratePerform (virDomainPtr dom, event = NULL; }
- if (resource > 0) { - /* Issue migrate_set_speed command. Don't worry if it fails. */ - snprintf (cmd, sizeof cmd, "migrate_set_speed %lum", resource); - qemudMonitorCommand (vm, cmd, &info); - - DEBUG ("%s: migrate_set_speed reply: %s", vm->def->name, info); - VIR_FREE (info); - } + if (resource > 0 && + qemuMonitorSetMigrationSpeed(vm, resource) < 0) + goto cleanup;
Checking for errors is new, but makes sense
/* Issue the migrate command. */ safe_uri = qemudEscapeMonitorArg (uri); diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index f35b1ef..d9227a2 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -969,3 +969,31 @@ int qemuMonitorSavePhysicalMemory(const virDomainObjPtr vm, { return qemuMonitorSaveMemory(vm, "pmemsave", offset, length, path); } + + +int qemuMonitorSetMigrationSpeed(const virDomainObjPtr vm, + unsigned long bandwidth) +{ + char *cmd = NULL; + char *info = NULL; + int ret = -1; + + if (virAsprintf(&cmd, "migrate_set_speed %lum", bandwidth) < 0) { + virReportOOMError(NULL); + goto cleanup; + } + + if (qemudMonitorCommand (vm, cmd, &info) < 0) {
^
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + "%s", _("could restrict migration speed")); + goto cleanup; + } + + DEBUG ("%s: migrate_set_speed reply: %s", vm->def->name, info); ^ + ret = 0; + +cleanup: + VIR_FREE (info); ^ Whitespace, no big deal
ACK Cheers, Mark.

* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add new qemuMonitorGetMigrationStatus() command. * src/qemu/qemu_driver.c: Use new qemuMonitorGetMigrationStatus() command to check completion status. --- src/qemu/qemu_driver.c | 15 +++++-- src/qemu/qemu_monitor_text.c | 91 ++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 16 +++++++ 3 files changed, 117 insertions(+), 5 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index ccc13c4..a6300c9 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -6499,6 +6499,8 @@ qemudDomainMigratePerform (virDomainPtr dom, char *info = NULL; int ret = -1; int paused = 0; + int status; + unsigned long long transferred, remaining, total; qemuDriverLock(driver); vm = virDomainFindByUUID(&driver->domains, dom->uuid); @@ -6562,14 +6564,17 @@ qemudDomainMigratePerform (virDomainPtr dom, * rather failed later on. Check the output of "info migrate" */ VIR_FREE(info); - if (qemudMonitorCommand(vm, "info migrate", &info) < 0) { - qemudReportError (dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - "%s", _("could not get info about migration")); + + if (qemuMonitorGetMigrationStatus(vm, &status, + &transferred, + &remaining, + &total) < 0) { goto cleanup; } - if (strstr(info, "fail") != NULL) { + + if (status != QEMU_MONITOR_MIGRATION_STATUS_COMPLETED) { qemudReportError (dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - _("migrate failed: %s"), info); + "%s", _("migrate did not successfully complete")); goto cleanup; } diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index d9227a2..0b746b9 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -28,6 +28,7 @@ #include <sys/un.h> #include <poll.h> #include <unistd.h> +#include <string.h> #include "qemu_monitor_text.h" #include "qemu_conf.h" @@ -997,3 +998,93 @@ cleanup: VIR_FREE(cmd); return ret; } + + +#define MIGRATION_PREFIX "Migration status: " +#define MIGRATION_TRANSFER_PREFIX "transferred ram: " +#define MIGRATION_REMAINING_PREFIX "remaining ram: " +#define MIGRATION_TOTAL_PREFIX "total ram: " + +VIR_ENUM_DECL(qemuMonitorMigrationStatus) +VIR_ENUM_IMPL(qemuMonitorMigrationStatus, + QEMU_MONITOR_MIGRATION_STATUS_LAST, + "inactive", "active", "completed", "failed", "cancelled") + +int qemuMonitorGetMigrationStatus(const virDomainObjPtr vm, + int *status, + unsigned long long *transferred, + unsigned long long *remaining, + unsigned long long *total) { + char *reply; + char *tmp; + char *end; + int ret = -1; + + *status = QEMU_MONITOR_MIGRATION_STATUS_INACTIVE; + *transferred = 0; + *remaining = 0; + *total = 0; + + if (qemudMonitorCommand(vm, "info migration", &reply) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + "%s", _("cannot query migration status")); + return -1; + } + + if ((tmp = strstr(reply, MIGRATION_PREFIX)) != NULL) { + tmp += strlen(MIGRATION_PREFIX); + end = strchr(tmp, '\n'); + *end = '\0'; + + if ((*status = qemuMonitorMigrationStatusTypeFromString(tmp)) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("unexpected migration status in %s"), reply); + goto cleanup; + } + + if (*status == QEMU_MONITOR_MIGRATION_STATUS_ACTIVE) { + tmp = end + 1; + + if (!(tmp = strstr(tmp, MIGRATION_TRANSFER_PREFIX))) + goto done; + tmp += strlen(MIGRATION_TRANSFER_PREFIX); + + if (virStrToLong_ull(tmp, NULL, 10, transferred) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("cannot parse migration data transferred statistic %s"), tmp); + goto cleanup; + } + *transferred *= 1024; + + if (!(tmp = strstr(tmp, MIGRATION_REMAINING_PREFIX))) + goto done; + tmp += strlen(MIGRATION_REMAINING_PREFIX); + + if (virStrToLong_ull(tmp, NULL, 10, remaining) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("cannot parse migration data remaining statistic %s"), tmp); + goto cleanup; + } + *remaining *= 1024; + + if (!(tmp = strstr(tmp, MIGRATION_TOTAL_PREFIX))) + goto done; + tmp += strlen(MIGRATION_TOTAL_PREFIX); + + if (virStrToLong_ull(tmp, NULL, 10, total) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("cannot parse migration data total statistic %s"), tmp); + goto cleanup; + } + *total *= 1024; + + } + } + +done: + ret = 0; + +cleanup: + VIR_FREE(reply); + return ret; +} diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index 0591f3c..c972672 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -112,4 +112,20 @@ int qemuMonitorSavePhysicalMemory(const virDomainObjPtr vm, int qemuMonitorSetMigrationSpeed(const virDomainObjPtr vm, unsigned long bandwidth); +enum { + QEMU_MONITOR_MIGRATION_STATUS_INACTIVE, + QEMU_MONITOR_MIGRATION_STATUS_ACTIVE, + QEMU_MONITOR_MIGRATION_STATUS_COMPLETED, + QEMU_MONITOR_MIGRATION_STATUS_ERROR, + QEMU_MONITOR_MIGRATION_STATUS_CANCELLED, + + QEMU_MONITOR_MIGRATION_STATUS_LAST +}; + +int qemuMonitorGetMigrationStatus(const virDomainObjPtr vm, + int *status, + unsigned long long *transferred, + unsigned long long *remaining, + unsigned long long *total); + #endif /* QEMU_MONITOR_TEXT_H */ -- 1.6.2.5

On Thu, 2009-09-24 at 16:00 +0100, Daniel P. Berrange wrote:
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add new qemuMonitorGetMigrationStatus() command. * src/qemu/qemu_driver.c: Use new qemuMonitorGetMigrationStatus() command to check completion status. --- src/qemu/qemu_driver.c | 15 +++++-- src/qemu/qemu_monitor_text.c | 91 ++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 16 +++++++ 3 files changed, 117 insertions(+), 5 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index ccc13c4..a6300c9 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -6499,6 +6499,8 @@ qemudDomainMigratePerform (virDomainPtr dom, char *info = NULL; int ret = -1; int paused = 0; + int status; + unsigned long long transferred, remaining, total;
qemuDriverLock(driver); vm = virDomainFindByUUID(&driver->domains, dom->uuid); @@ -6562,14 +6564,17 @@ qemudDomainMigratePerform (virDomainPtr dom, * rather failed later on. Check the output of "info migrate" */ VIR_FREE(info); - if (qemudMonitorCommand(vm, "info migrate", &info) < 0) { - qemudReportError (dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - "%s", _("could not get info about migration")); + + if (qemuMonitorGetMigrationStatus(vm, &status, + &transferred, + &remaining, + &total) < 0) { goto cleanup; } - if (strstr(info, "fail") != NULL) { + + if (status != QEMU_MONITOR_MIGRATION_STATUS_COMPLETED) { qemudReportError (dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - _("migrate failed: %s"), info); + "%s", _("migrate did not successfully complete")); goto cleanup; }
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index d9227a2..0b746b9 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -28,6 +28,7 @@ #include <sys/un.h> #include <poll.h> #include <unistd.h> +#include <string.h>
#include "qemu_monitor_text.h" #include "qemu_conf.h" @@ -997,3 +998,93 @@ cleanup: VIR_FREE(cmd); return ret; } + + +#define MIGRATION_PREFIX "Migration status: " +#define MIGRATION_TRANSFER_PREFIX "transferred ram: " +#define MIGRATION_REMAINING_PREFIX "remaining ram: " +#define MIGRATION_TOTAL_PREFIX "total ram: " + +VIR_ENUM_DECL(qemuMonitorMigrationStatus) +VIR_ENUM_IMPL(qemuMonitorMigrationStatus, + QEMU_MONITOR_MIGRATION_STATUS_LAST, + "inactive", "active", "completed", "failed", "cancelled") + +int qemuMonitorGetMigrationStatus(const virDomainObjPtr vm, + int *status, + unsigned long long *transferred, + unsigned long long *remaining, + unsigned long long *total) {
You went a bit crazy here! New code to parse a bunch of stuff that is then ignored ... Looks fine, but have you checked this format has always been the same? A comment showing the format being parsed would be good too ACK Cheers, Mark.

On Mon, Sep 28, 2009 at 02:26:36PM +0100, Mark McLoughlin wrote:
On Thu, 2009-09-24 at 16:00 +0100, Daniel P. Berrange wrote:
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add new qemuMonitorGetMigrationStatus() command. * src/qemu/qemu_driver.c: Use new qemuMonitorGetMigrationStatus() command to check completion status. --- src/qemu/qemu_driver.c | 15 +++++-- src/qemu/qemu_monitor_text.c | 91 ++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 16 +++++++ 3 files changed, 117 insertions(+), 5 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index ccc13c4..a6300c9 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -6499,6 +6499,8 @@ qemudDomainMigratePerform (virDomainPtr dom, char *info = NULL; int ret = -1; int paused = 0; + int status; + unsigned long long transferred, remaining, total;
qemuDriverLock(driver); vm = virDomainFindByUUID(&driver->domains, dom->uuid); @@ -6562,14 +6564,17 @@ qemudDomainMigratePerform (virDomainPtr dom, * rather failed later on. Check the output of "info migrate" */ VIR_FREE(info); - if (qemudMonitorCommand(vm, "info migrate", &info) < 0) { - qemudReportError (dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - "%s", _("could not get info about migration")); + + if (qemuMonitorGetMigrationStatus(vm, &status, + &transferred, + &remaining, + &total) < 0) { goto cleanup; } - if (strstr(info, "fail") != NULL) { + + if (status != QEMU_MONITOR_MIGRATION_STATUS_COMPLETED) { qemudReportError (dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - _("migrate failed: %s"), info); + "%s", _("migrate did not successfully complete")); goto cleanup; }
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index d9227a2..0b746b9 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -28,6 +28,7 @@ #include <sys/un.h> #include <poll.h> #include <unistd.h> +#include <string.h>
#include "qemu_monitor_text.h" #include "qemu_conf.h" @@ -997,3 +998,93 @@ cleanup: VIR_FREE(cmd); return ret; } + + +#define MIGRATION_PREFIX "Migration status: " +#define MIGRATION_TRANSFER_PREFIX "transferred ram: " +#define MIGRATION_REMAINING_PREFIX "remaining ram: " +#define MIGRATION_TOTAL_PREFIX "total ram: " + +VIR_ENUM_DECL(qemuMonitorMigrationStatus) +VIR_ENUM_IMPL(qemuMonitorMigrationStatus, + QEMU_MONITOR_MIGRATION_STATUS_LAST, + "inactive", "active", "completed", "failed", "cancelled") + +int qemuMonitorGetMigrationStatus(const virDomainObjPtr vm, + int *status, + unsigned long long *transferred, + unsigned long long *remaining, + unsigned long long *total) {
You went a bit crazy here! New code to parse a bunch of stuff that is then ignored ...
....for now There's an open RFE to support monitoring the progress of migration which this method will assist with. This whole series of refactoring is really to help with my work to allow migration to be done without blocking the application caller, via a forthcoming async-job API,as well as to allow easier integration of the new QMP protocol and detection of async monitor events from QEMU.
Looks fine, but have you checked this format has always been the same? A comment showing the format being parsed would be good too
Will add a comment. This data hasn't been around in QEMU for all that long, but I didn't see evidence of it having changed since its introduction Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add new API qemuMonitorMigrateToHost() for doing TCP migration * src/qemu/qemu_driver.c: Convert to use qemuMonitorMigrateToHost(). Also handle proper URIs (tcp:// as well as tcp:) --- src/qemu/qemu_driver.c | 40 ++++++++++++----------------- src/qemu/qemu_monitor_text.c | 56 ++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 4 +++ 3 files changed, 77 insertions(+), 23 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index a6300c9..f234639 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -6494,12 +6494,10 @@ qemudDomainMigratePerform (virDomainPtr dom, struct qemud_driver *driver = dom->conn->privateData; virDomainObjPtr vm; virDomainEventPtr event = NULL; - char *safe_uri; - char cmd[HOST_NAME_MAX+50]; - char *info = NULL; int ret = -1; int paused = 0; int status; + xmlURIPtr uribits = NULL; unsigned long long transferred, remaining, total; qemuDriverLock(driver); @@ -6537,34 +6535,29 @@ qemudDomainMigratePerform (virDomainPtr dom, goto cleanup; /* Issue the migrate command. */ - safe_uri = qemudEscapeMonitorArg (uri); - if (!safe_uri) { - virReportOOMError (dom->conn); - goto cleanup; + if (STRPREFIX(uri, "tcp:") && !STRPREFIX(uri, "tcp://")) { + char *tmpuri; + if (virAsprintf(&tmpuri, "tcp://%s", uri + strlen("tcp:")) < 0) { + virReportOOMError(dom->conn); + goto cleanup; + } + uribits = xmlParseURI(tmpuri); + VIR_FREE(tmpuri); + } else { + uribits = xmlParseURI(uri); } - snprintf (cmd, sizeof cmd, "migrate \"%s\"", safe_uri); - VIR_FREE (safe_uri); - - if (qemudMonitorCommand (vm, cmd, &info) < 0) { - qemudReportError (dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - "%s", _("migrate operation failed")); + if (!uribits) { + qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR, + _("cannot parse URI %s"), uri); goto cleanup; } - DEBUG ("%s: migrate reply: %s", vm->def->name, info); - - /* Now check for "fail" in the output string */ - if (strstr(info, "fail") != NULL) { - qemudReportError (dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - _("migrate failed: %s"), info); + if (qemuMonitorMigrateToHost(vm, uribits->server, uribits->port) < 0) goto cleanup; - } /* it is also possible that the migrate didn't fail initially, but * rather failed later on. Check the output of "info migrate" */ - VIR_FREE(info); - if (qemuMonitorGetMigrationStatus(vm, &status, &transferred, &remaining, @@ -6608,7 +6601,8 @@ cleanup: VIR_DOMAIN_EVENT_RESUMED_MIGRATED); } - VIR_FREE(info); + if (uribits) + xmlFreeURI(uribits); if (vm) virDomainObjUnlock(vm); if (event) diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 0b746b9..4f8d72e 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -1088,3 +1088,59 @@ cleanup: VIR_FREE(reply); return ret; } + + +static int qemuMonitorMigrate(const virDomainObjPtr vm, + const char *dest) +{ + char *cmd = NULL; + char *info = NULL; + int ret = -1; + + if (virAsprintf(&cmd, "migrate %s", cmd) < 0) { + virReportOOMError(NULL); + return -1; + } + + if (qemudMonitorCommand(vm, cmd, &info) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("unable to start migration to %s"), dest); + goto cleanup; + } + + DEBUG ("%s: migrate reply: %s", vm->def->name, info); + + /* Now check for "fail" in the output string */ + if (strstr(info, "fail") != NULL) { + qemudReportError (NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + _("migration to '%s' failed: %s"), dest, info); + goto cleanup; + } + + + ret = 0; + +cleanup: + VIR_FREE(info); + VIR_FREE(cmd); + return ret; +} + +int qemuMonitorMigrateToHost(const virDomainObjPtr vm, + const char *hostname, + int port) +{ + char *uri; + int ret; + + if (virAsprintf(&uri, "tcp:%s:%d", hostname, port) < 0) { + virReportOOMError(NULL); + return -1; + } + + ret = qemuMonitorMigrate(vm, uri); + + VIR_FREE(uri); + + return ret; +} diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index c972672..0d34b6b 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -128,4 +128,8 @@ int qemuMonitorGetMigrationStatus(const virDomainObjPtr vm, unsigned long long *remaining, unsigned long long *total); +int qemuMonitorMigrateToHost(const virDomainObjPtr vm, + const char *hostname, + int port); + #endif /* QEMU_MONITOR_TEXT_H */ -- 1.6.2.5

On Thu, 2009-09-24 at 16:00 +0100, Daniel P. Berrange wrote:
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add new API qemuMonitorMigrateToHost() for doing TCP migration * src/qemu/qemu_driver.c: Convert to use qemuMonitorMigrateToHost(). Also handle proper URIs (tcp:// as well as tcp:) --- src/qemu/qemu_driver.c | 40 ++++++++++++----------------- src/qemu/qemu_monitor_text.c | 56 ++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 4 +++ 3 files changed, 77 insertions(+), 23 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index a6300c9..f234639 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -6494,12 +6494,10 @@ qemudDomainMigratePerform (virDomainPtr dom, struct qemud_driver *driver = dom->conn->privateData; virDomainObjPtr vm; virDomainEventPtr event = NULL; - char *safe_uri; - char cmd[HOST_NAME_MAX+50]; - char *info = NULL; int ret = -1; int paused = 0; int status; + xmlURIPtr uribits = NULL; unsigned long long transferred, remaining, total;
qemuDriverLock(driver); @@ -6537,34 +6535,29 @@ qemudDomainMigratePerform (virDomainPtr dom, goto cleanup;
/* Issue the migrate command. */ - safe_uri = qemudEscapeMonitorArg (uri); - if (!safe_uri) { - virReportOOMError (dom->conn); - goto cleanup; + if (STRPREFIX(uri, "tcp:") && !STRPREFIX(uri, "tcp://")) { + char *tmpuri; + if (virAsprintf(&tmpuri, "tcp://%s", uri + strlen("tcp:")) < 0) { + virReportOOMError(dom->conn); + goto cleanup; + } + uribits = xmlParseURI(tmpuri); + VIR_FREE(tmpuri); + } else { + uribits = xmlParseURI(uri);
This is all new stuff and there's no explanation in the ChangeLog; not sure why you're so keen to split up the URI only to re-construct it again It looks okay, though, just made it harder to review the patch
} - snprintf (cmd, sizeof cmd, "migrate \"%s\"", safe_uri); - VIR_FREE (safe_uri); - - if (qemudMonitorCommand (vm, cmd, &info) < 0) { - qemudReportError (dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - "%s", _("migrate operation failed")); + if (!uribits) { + qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR, + _("cannot parse URI %s"), uri); goto cleanup; }
- DEBUG ("%s: migrate reply: %s", vm->def->name, info); - - /* Now check for "fail" in the output string */ - if (strstr(info, "fail") != NULL) { - qemudReportError (dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - _("migrate failed: %s"), info); + if (qemuMonitorMigrateToHost(vm, uribits->server, uribits->port) < 0) goto cleanup; - }
/* it is also possible that the migrate didn't fail initially, but * rather failed later on. Check the output of "info migrate" */ - VIR_FREE(info); - if (qemuMonitorGetMigrationStatus(vm, &status, &transferred, &remaining, @@ -6608,7 +6601,8 @@ cleanup: VIR_DOMAIN_EVENT_RESUMED_MIGRATED); }
- VIR_FREE(info); + if (uribits) + xmlFreeURI(uribits); if (vm) virDomainObjUnlock(vm); if (event) diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 0b746b9..4f8d72e 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -1088,3 +1088,59 @@ cleanup: VIR_FREE(reply); return ret; } + + +static int qemuMonitorMigrate(const virDomainObjPtr vm, + const char *dest) +{ + char *cmd = NULL; + char *info = NULL; + int ret = -1; + + if (virAsprintf(&cmd, "migrate %s", cmd) < 0) {
Should be passing dest here Fixed in the next patch, but would be good to get it right for bisectability Otherwise, ACK Cheers, Mark.

On Mon, Sep 28, 2009 at 02:22:59PM +0100, Mark McLoughlin wrote:
On Thu, 2009-09-24 at 16:00 +0100, Daniel P. Berrange wrote:
@@ -6537,34 +6535,29 @@ qemudDomainMigratePerform (virDomainPtr dom, goto cleanup;
/* Issue the migrate command. */ - safe_uri = qemudEscapeMonitorArg (uri); - if (!safe_uri) { - virReportOOMError (dom->conn); - goto cleanup; + if (STRPREFIX(uri, "tcp:") && !STRPREFIX(uri, "tcp://")) { + char *tmpuri; + if (virAsprintf(&tmpuri, "tcp://%s", uri + strlen("tcp:")) < 0) { + virReportOOMError(dom->conn); + goto cleanup; + } + uribits = xmlParseURI(tmpuri); + VIR_FREE(tmpuri); + } else { + uribits = xmlParseURI(uri);
This is all new stuff and there's no explanation in the ChangeLog; not sure why you're so keen to split up the URI only to re-construct it again
We're calling this parameter a URI but doing zero validation that it is actually correctly formated as a URI, and just passing it straight down to QEMU. The application caller could have appended all sorts of junk onto the URI. In fact the QEMU Prepare() method wasn't even generating valid URIs, which rather justifies why we should have been doing validation in the first place. So this code fixes the broken tcp:hostname:port URIs to actually be tcp://hostname:port Unfortunately we cna't fix the original Prepare() method since that would break compatability with older libvirt. The whole thing is a giant mess because it was directly exposing the QEMU monitor syntax for TCP migration :-(
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 0b746b9..4f8d72e 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -1088,3 +1088,59 @@ cleanup: VIR_FREE(reply); return ret; } + + +static int qemuMonitorMigrate(const virDomainObjPtr vm, + const char *dest) +{ + char *cmd = NULL; + char *info = NULL; + int ret = -1; + + if (virAsprintf(&cmd, "migrate %s", cmd) < 0) {
Should be passing dest here
Fixed in the next patch, but would be good to get it right for bisectability
Ahh I knew there was one place where I screwed up / missed a rebase. Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add new qemuMonitorMigrateToCommand() API * src/qemu/qemu_driver.c: Switch over to using the qemuMonitorMigrateToCommand() API for core dumps and save to file APIs --- src/libvirt_private.syms | 1 + src/qemu/qemu_driver.c | 119 ++++++++---------------------------------- src/qemu/qemu_monitor_text.c | 63 +++++++++++++++++++++-- src/qemu/qemu_monitor_text.h | 4 ++ 4 files changed, 86 insertions(+), 101 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index a6668f3..f8598c7 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -453,6 +453,7 @@ virGetGroupID; virFileFindMountPoint; virFileWaitForDevices; virFileMatchesNameSuffix; +virArgvToString; # usb.h diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index f234639..da08af9 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -3170,11 +3170,6 @@ static char *qemudEscapeMonitorArg(const char *in) return qemudEscape(in, 0); } -static char *qemudEscapeShellArg(const char *in) -{ - return qemudEscape(in, 1); -} - #define QEMUD_SAVE_MAGIC "LibvirtQemudSave" #define QEMUD_SAVE_VERSION 2 @@ -3217,15 +3212,11 @@ static int qemudDomainSave(virDomainPtr dom, { struct qemud_driver *driver = dom->conn->privateData; virDomainObjPtr vm = NULL; - char *command = NULL; - char *info = NULL; int fd = -1; - char *safe_path = NULL; char *xml = NULL; struct qemud_save_header header; int ret = -1; virDomainEventPtr event = NULL; - int internalret; memset(&header, 0, sizeof(header)); memcpy(header.magic, QEMUD_SAVE_MAGIC, sizeof(header.magic)); @@ -3267,7 +3258,6 @@ static int qemudDomainSave(virDomainPtr dom, if (qemuMonitorStopCPUs(vm) < 0) goto cleanup; vm->state = VIR_DOMAIN_PAUSED; - VIR_FREE(info); } /* Get XML for the domain */ @@ -3306,55 +3296,21 @@ static int qemudDomainSave(virDomainPtr dom, } fd = -1; - /* Migrate to file */ - safe_path = qemudEscapeShellArg(path); - if (!safe_path) { - virReportOOMError(dom->conn); - goto cleanup; - } - - { + if (header.compressed == QEMUD_SAVE_FORMAT_RAW) { + const char *args[] = { "cat", NULL }; + ret = qemuMonitorMigrateToCommand(vm, args, path); + } else { const char *prog = qemudSaveCompressionTypeToString(header.compressed); - const char *args; - - if (prog == NULL) { - qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR, - _("Invalid compress format %d"), header.compressed); - goto cleanup; - } - - if (STREQ (prog, "raw")) { - prog = "cat"; - args = ""; - } else { - args = "-c"; - } - internalret = virAsprintf(&command, "migrate \"exec:" - "%s %s >> '%s' 2>/dev/null\"", prog, args, - safe_path); - } - - if (internalret < 0) { - virReportOOMError(dom->conn); - goto cleanup; - } - - if (qemudMonitorCommand(vm, command, &info) < 0) { - qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - "%s", _("migrate operation failed")); - goto cleanup; + const char *args[] = { + prog, + "-c", + NULL + }; + ret = qemuMonitorMigrateToCommand(vm, args, path); } - DEBUG ("%s: migrate reply: %s", vm->def->name, info); - - /* If the command isn't supported then qemu prints: - * unknown command: migrate" */ - if (strstr(info, "unknown command:")) { - qemudReportError (dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT, - "%s", - _("'migrate' not supported by this qemu")); + if (ret < 0) goto cleanup; - } /* Shut it down */ qemudShutdownVMDaemon(dom->conn, driver, vm); @@ -3366,15 +3322,11 @@ static int qemudDomainSave(virDomainPtr dom, vm); vm = NULL; } - ret = 0; cleanup: if (fd != -1) close(fd); VIR_FREE(xml); - VIR_FREE(safe_path); - VIR_FREE(command); - VIR_FREE(info); if (ret != 0) unlink(path); if (vm) @@ -3391,11 +3343,12 @@ static int qemudDomainCoreDump(virDomainPtr dom, int flags ATTRIBUTE_UNUSED) { struct qemud_driver *driver = dom->conn->privateData; virDomainObjPtr vm; - char *command = NULL; - char *info = NULL; - char *safe_path = NULL; int resume = 0, paused = 0; int ret = -1; + const char *args[] = { + "cat", + NULL, + }; qemuDriverLock(driver); vm = virDomainFindByUUID(&driver->domains, dom->uuid); @@ -3427,43 +3380,9 @@ static int qemudDomainCoreDump(virDomainPtr dom, paused = 1; } - /* Migrate to file */ - safe_path = qemudEscapeShellArg(path); - if (!safe_path) { - virReportOOMError(dom->conn); - goto cleanup; - } - if (virAsprintf(&command, "migrate \"exec:" - "dd of='%s' 2>/dev/null" - "\"", safe_path) == -1) { - virReportOOMError(dom->conn); - command = NULL; - goto cleanup; - } - - if (qemudMonitorCommand(vm, command, &info) < 0) { - qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - "%s", _("migrate operation failed")); - goto cleanup; - } - - DEBUG ("%s: migrate reply: %s", vm->def->name, info); - - /* If the command isn't supported then qemu prints: - * unknown command: migrate" */ - if (strstr(info, "unknown command:")) { - qemudReportError (dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT, - "%s", - _("'migrate' not supported by this qemu")); - goto cleanup; - } - + ret = qemuMonitorMigrateToCommand(vm, args, path); paused = 1; - ret = 0; cleanup: - VIR_FREE(safe_path); - VIR_FREE(command); - VIR_FREE(info); /* Since the monitor is always attached to a pty for libvirt, it will support synchronous operations so we always get here after @@ -6370,6 +6289,11 @@ qemudDomainMigratePrepare2 (virConnectPtr dconn, goto cleanup; } + /* XXX this really should have been a properly well-formed + * URI, but we can't add in tcp:// now without breaking + * compatability with old targets. We at least make the + * new targets accept both syntaxes though. + */ /* Caller frees */ internalret = virAsprintf(uri_out, "tcp:%s:%d", hostname, this_port); VIR_FREE(hostname); @@ -6536,6 +6460,7 @@ qemudDomainMigratePerform (virDomainPtr dom, /* Issue the migrate command. */ if (STRPREFIX(uri, "tcp:") && !STRPREFIX(uri, "tcp://")) { + /* HACK: source host generates bogus URIs, so fix them up */ char *tmpuri; if (virAsprintf(&tmpuri, "tcp://%s", uri + strlen("tcp:")) < 0) { virReportOOMError(dom->conn); diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 4f8d72e..c154019 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -118,6 +118,10 @@ static char *qemudEscapeMonitorArg(const char *in) return qemudEscape(in, 0); } +static char *qemudEscapeShellArg(const char *in) +{ + return qemudEscape(in, 1); +} /* Throw away any data available on the monitor * This is done before executing a command, in order @@ -1096,12 +1100,18 @@ static int qemuMonitorMigrate(const virDomainObjPtr vm, char *cmd = NULL; char *info = NULL; int ret = -1; + char *safedest = qemudEscapeMonitorArg(dest); - if (virAsprintf(&cmd, "migrate %s", cmd) < 0) { + if (!safedest) { virReportOOMError(NULL); return -1; } + if (virAsprintf(&cmd, "migrate \"%s\"", safedest) < 0) { + virReportOOMError(NULL); + goto cleanup; + } + if (qemudMonitorCommand(vm, cmd, &info) < 0) { qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("unable to start migration to %s"), dest); @@ -1112,8 +1122,15 @@ static int qemuMonitorMigrate(const virDomainObjPtr vm, /* Now check for "fail" in the output string */ if (strstr(info, "fail") != NULL) { - qemudReportError (NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, - _("migration to '%s' failed: %s"), dest, info); + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + _("migration to '%s' failed: %s"), dest, info); + goto cleanup; + } + /* If the command isn't supported then qemu prints: + * unknown command: migrate" */ + if (strstr(info, "unknown command:")) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_NO_SUPPORT, + _("migration to '%s' not supported by this qemu: %s"), dest, info); goto cleanup; } @@ -1121,6 +1138,7 @@ static int qemuMonitorMigrate(const virDomainObjPtr vm, ret = 0; cleanup: + VIR_FREE(safedest); VIR_FREE(info); VIR_FREE(cmd); return ret; @@ -1130,7 +1148,7 @@ int qemuMonitorMigrateToHost(const virDomainObjPtr vm, const char *hostname, int port) { - char *uri; + char *uri = NULL; int ret; if (virAsprintf(&uri, "tcp:%s:%d", hostname, port) < 0) { @@ -1144,3 +1162,40 @@ int qemuMonitorMigrateToHost(const virDomainObjPtr vm, return ret; } + + +int qemuMonitorMigrateToCommand(const virDomainObjPtr vm, + const char * const *argv, + const char *target) +{ + char *argstr; + char *dest = NULL; + int ret = -1; + char *safe_target = NULL; + + argstr = virArgvToString(argv); + if (!argstr) { + virReportOOMError(NULL); + goto cleanup; + } + + /* Migrate to file */ + safe_target = qemudEscapeShellArg(target); + if (!safe_target) { + virReportOOMError(NULL); + goto cleanup; + } + + if (virAsprintf(&dest, "exec:%s >>%s 2>/dev/null", argstr, safe_target) < 0) { + virReportOOMError(NULL); + goto cleanup; + } + + ret = qemuMonitorMigrate(vm, dest); + +cleanup: + VIR_FREE(safe_target); + VIR_FREE(argstr); + VIR_FREE(dest); + return ret; +} diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index 0d34b6b..ffed049 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -132,4 +132,8 @@ int qemuMonitorMigrateToHost(const virDomainObjPtr vm, const char *hostname, int port); +int qemuMonitorMigrateToCommand(const virDomainObjPtr vm, + const char * const *argv, + const char *target); + #endif /* QEMU_MONITOR_TEXT_H */ -- 1.6.2.5

Subject typo - "issugin" On Thu, 2009-09-24 at 16:00 +0100, Daniel P. Berrange wrote:
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add new qemuMonitorMigrateToCommand() API * src/qemu/qemu_driver.c: Switch over to using the qemuMonitorMigrateToCommand() API for core dumps and save to file APIs --- src/libvirt_private.syms | 1 + src/qemu/qemu_driver.c | 119 ++++++++---------------------------------- src/qemu/qemu_monitor_text.c | 63 +++++++++++++++++++++-- src/qemu/qemu_monitor_text.h | 4 ++ 4 files changed, 86 insertions(+), 101 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index a6668f3..f8598c7 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -453,6 +453,7 @@ virGetGroupID; virFileFindMountPoint; virFileWaitForDevices; virFileMatchesNameSuffix; +virArgvToString;
# usb.h diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index f234639..da08af9 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -3170,11 +3170,6 @@ static char *qemudEscapeMonitorArg(const char *in) return qemudEscape(in, 0); }
-static char *qemudEscapeShellArg(const char *in) -{ - return qemudEscape(in, 1); -} - #define QEMUD_SAVE_MAGIC "LibvirtQemudSave" #define QEMUD_SAVE_VERSION 2
@@ -3217,15 +3212,11 @@ static int qemudDomainSave(virDomainPtr dom, { struct qemud_driver *driver = dom->conn->privateData; virDomainObjPtr vm = NULL; - char *command = NULL; - char *info = NULL; int fd = -1; - char *safe_path = NULL; char *xml = NULL; struct qemud_save_header header; int ret = -1; virDomainEventPtr event = NULL; - int internalret;
memset(&header, 0, sizeof(header)); memcpy(header.magic, QEMUD_SAVE_MAGIC, sizeof(header.magic)); @@ -3267,7 +3258,6 @@ static int qemudDomainSave(virDomainPtr dom, if (qemuMonitorStopCPUs(vm) < 0) goto cleanup; vm->state = VIR_DOMAIN_PAUSED; - VIR_FREE(info); }
/* Get XML for the domain */ @@ -3306,55 +3296,21 @@ static int qemudDomainSave(virDomainPtr dom, } fd = -1;
- /* Migrate to file */ - safe_path = qemudEscapeShellArg(path); - if (!safe_path) { - virReportOOMError(dom->conn); - goto cleanup; - } - - { + if (header.compressed == QEMUD_SAVE_FORMAT_RAW) { + const char *args[] = { "cat", NULL }; + ret = qemuMonitorMigrateToCommand(vm, args, path); + } else { const char *prog = qemudSaveCompressionTypeToString(header.compressed); - const char *args; - - if (prog == NULL) { - qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR, - _("Invalid compress format %d"), header.compressed); - goto cleanup; - } - - if (STREQ (prog, "raw")) { - prog = "cat"; - args = ""; - } else { - args = "-c"; - }
Using the enum value to catch the raw case rather than the "raw" string is a sensible change
- internalret = virAsprintf(&command, "migrate \"exec:" - "%s %s >> '%s' 2>/dev/null\"", prog, args, - safe_path); - } - - if (internalret < 0) { - virReportOOMError(dom->conn); - goto cleanup; - } - - if (qemudMonitorCommand(vm, command, &info) < 0) { - qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - "%s", _("migrate operation failed")); - goto cleanup; + const char *args[] = { + prog, + "-c", + NULL + }; + ret = qemuMonitorMigrateToCommand(vm, args, path); }
- DEBUG ("%s: migrate reply: %s", vm->def->name, info); - - /* If the command isn't supported then qemu prints: - * unknown command: migrate" */ - if (strstr(info, "unknown command:")) { - qemudReportError (dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT, - "%s", - _("'migrate' not supported by this qemu")); + if (ret < 0) goto cleanup; - }
/* Shut it down */ qemudShutdownVMDaemon(dom->conn, driver, vm); @@ -3366,15 +3322,11 @@ static int qemudDomainSave(virDomainPtr dom, vm); vm = NULL; } - ret = 0;
cleanup: if (fd != -1) close(fd); VIR_FREE(xml); - VIR_FREE(safe_path); - VIR_FREE(command); - VIR_FREE(info); if (ret != 0) unlink(path); if (vm) @@ -3391,11 +3343,12 @@ static int qemudDomainCoreDump(virDomainPtr dom, int flags ATTRIBUTE_UNUSED) { struct qemud_driver *driver = dom->conn->privateData; virDomainObjPtr vm; - char *command = NULL; - char *info = NULL; - char *safe_path = NULL; int resume = 0, paused = 0; int ret = -1; + const char *args[] = { + "cat", + NULL, + };
qemuDriverLock(driver); vm = virDomainFindByUUID(&driver->domains, dom->uuid); @@ -3427,43 +3380,9 @@ static int qemudDomainCoreDump(virDomainPtr dom, paused = 1; }
- /* Migrate to file */ - safe_path = qemudEscapeShellArg(path); - if (!safe_path) { - virReportOOMError(dom->conn); - goto cleanup; - } - if (virAsprintf(&command, "migrate \"exec:" - "dd of='%s' 2>/dev/null" - "\"", safe_path) == -1) {
Would have like to see switch from dd to cat as a separate patch with an explanation in the changelog
- virReportOOMError(dom->conn); - command = NULL; - goto cleanup; - } - - if (qemudMonitorCommand(vm, command, &info) < 0) { - qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - "%s", _("migrate operation failed")); - goto cleanup; - } - - DEBUG ("%s: migrate reply: %s", vm->def->name, info); - - /* If the command isn't supported then qemu prints: - * unknown command: migrate" */ - if (strstr(info, "unknown command:")) { - qemudReportError (dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT, - "%s", - _("'migrate' not supported by this qemu")); - goto cleanup; - } - + ret = qemuMonitorMigrateToCommand(vm, args, path); paused = 1; - ret = 0; cleanup: - VIR_FREE(safe_path); - VIR_FREE(command); - VIR_FREE(info);
/* Since the monitor is always attached to a pty for libvirt, it will support synchronous operations so we always get here after @@ -6370,6 +6289,11 @@ qemudDomainMigratePrepare2 (virConnectPtr dconn, goto cleanup; }
+ /* XXX this really should have been a properly well-formed + * URI, but we can't add in tcp:// now without breaking + * compatability with old targets. We at least make the + * new targets accept both syntaxes though. + */ /* Caller frees */ internalret = virAsprintf(uri_out, "tcp:%s:%d", hostname, this_port); VIR_FREE(hostname); @@ -6536,6 +6460,7 @@ qemudDomainMigratePerform (virDomainPtr dom,
/* Issue the migrate command. */ if (STRPREFIX(uri, "tcp:") && !STRPREFIX(uri, "tcp://")) { + /* HACK: source host generates bogus URIs, so fix them up */ char *tmpuri; if (virAsprintf(&tmpuri, "tcp://%s", uri + strlen("tcp:")) < 0) { virReportOOMError(dom->conn);
Two unrelated comments - looks like it's more related to the URI changes you made in the previous patch
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 4f8d72e..c154019 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -118,6 +118,10 @@ static char *qemudEscapeMonitorArg(const char *in) return qemudEscape(in, 0); }
+static char *qemudEscapeShellArg(const char *in) +{ + return qemudEscape(in, 1); +}
/* Throw away any data available on the monitor * This is done before executing a command, in order @@ -1096,12 +1100,18 @@ static int qemuMonitorMigrate(const virDomainObjPtr vm, char *cmd = NULL; char *info = NULL; int ret = -1; + char *safedest = qemudEscapeMonitorArg(dest);
- if (virAsprintf(&cmd, "migrate %s", cmd) < 0) { + if (!safedest) { virReportOOMError(NULL); return -1; }
+ if (virAsprintf(&cmd, "migrate \"%s\"", safedest) < 0) { + virReportOOMError(NULL); + goto cleanup; + }
Little bit worried that the introduction of escaping will break other usages, but it should be fine
+ if (qemudMonitorCommand(vm, cmd, &info) < 0) { qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("unable to start migration to %s"), dest); @@ -1112,8 +1122,15 @@ static int qemuMonitorMigrate(const virDomainObjPtr vm,
/* Now check for "fail" in the output string */ if (strstr(info, "fail") != NULL) { - qemudReportError (NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, - _("migration to '%s' failed: %s"), dest, info); + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + _("migration to '%s' failed: %s"), dest, info);
Unrelated
+ goto cleanup; + } + /* If the command isn't supported then qemu prints: + * unknown command: migrate" */ + if (strstr(info, "unknown command:")) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_NO_SUPPORT, + _("migration to '%s' not supported by this qemu: %s"), dest, info); goto cleanup; }
@@ -1121,6 +1138,7 @@ static int qemuMonitorMigrate(const virDomainObjPtr vm, ret = 0;
cleanup: + VIR_FREE(safedest); VIR_FREE(info); VIR_FREE(cmd); return ret; @@ -1130,7 +1148,7 @@ int qemuMonitorMigrateToHost(const virDomainObjPtr vm, const char *hostname, int port) { - char *uri; + char *uri = NULL;
Unrelated ACK Cheers, Mark.

* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add new qemuMonitorAddUSBDisk() API * src/qemu/qemu_driver.c: Switch USB disk hotplug to the new src/qemu/qemu_driver.c API. --- src/qemu/qemu_driver.c | 41 ++++++--------------------------------- src/qemu/qemu_monitor_text.c | 43 ++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 4 +++ 3 files changed, 54 insertions(+), 34 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index da08af9..635fb84 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4698,59 +4698,32 @@ static int qemudDomainAttachUsbMassstorageDevice(virConnectPtr conn, virDomainObjPtr vm, virDomainDeviceDefPtr dev) { - int ret, i; - char *safe_path; - char *cmd, *reply; + int i; for (i = 0 ; i < vm->def->ndisks ; i++) { if (STREQ(vm->def->disks[i]->dst, dev->data.disk->dst)) { - qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED, + qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED, _("target %s already exists"), dev->data.disk->dst); return -1; } } - if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0) { - virReportOOMError(conn); - return -1; - } - - safe_path = qemudEscapeMonitorArg(dev->data.disk->src); - if (!safe_path) { - virReportOOMError(conn); + if (!dev->data.disk->src) { + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + "%s", _("disk source path is missing")); return -1; } - ret = virAsprintf(&cmd, "usb_add disk:%s", safe_path); - VIR_FREE(safe_path); - if (ret == -1) { + if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0) { virReportOOMError(conn); - return ret; - } - - if (qemudMonitorCommand(vm, cmd, &reply) < 0) { - qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - "%s", _("cannot attach usb disk")); - VIR_FREE(cmd); return -1; } - DEBUG ("%s: attach_usb reply: %s",vm->def->name, reply); - /* If the command failed qemu prints: - * Could not add ... */ - if (strstr(reply, "Could not add ")) { - qemudReportError (conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - "%s", - _("adding usb disk failed")); - VIR_FREE(reply); - VIR_FREE(cmd); + if (qemuMonitorAddUSBDisk(vm, dev->data.disk->src) < 0) return -1; - } virDomainDiskInsertPreAlloced(vm->def, dev->data.disk); - VIR_FREE(reply); - VIR_FREE(cmd); return 0; } diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index c154019..fd50cf2 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -1199,3 +1199,46 @@ cleanup: VIR_FREE(dest); return ret; } + + +int qemuMonitorAddUSBDisk(const virDomainObjPtr vm, + const char *path) +{ + char *cmd = NULL; + char *safepath; + int ret = -1; + char *info = NULL; + + safepath = qemudEscapeMonitorArg(path); + if (!safepath) { + virReportOOMError(NULL); + return -1; + } + + if (virAsprintf(&cmd, "usb_add disk:%s", safepath) < 0) { + virReportOOMError(NULL); + goto cleanup; + } + + if (qemudMonitorCommand(vm, cmd, &info) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + "%s", _("cannot run monitor command to add usb disk")); + goto cleanup; + } + + DEBUG ("%s: usb_add reply: %s", vm->def->name, info); + /* If the command failed qemu prints: + * Could not add ... */ + if (strstr(info, "Could not add ")) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + _("unable to add USB disk %s: %s"), path, info); + goto cleanup; + } + + ret = 0; + +cleanup: + VIR_FREE(cmd); + VIR_FREE(safepath); + return ret; +} diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index ffed049..138e7a0 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -136,4 +136,8 @@ int qemuMonitorMigrateToCommand(const virDomainObjPtr vm, const char * const *argv, const char *target); + +int qemuMonitorAddUSBDisk(const virDomainObjPtr vm, + const char *path); + #endif /* QEMU_MONITOR_TEXT_H */ -- 1.6.2.5

On Thu, 2009-09-24 at 16:00 +0100, Daniel P. Berrange wrote:
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add new qemuMonitorAddUSBDisk() API * src/qemu/qemu_driver.c: Switch USB disk hotplug to the new src/qemu/qemu_driver.c API. --- src/qemu/qemu_driver.c | 41 ++++++--------------------------------- src/qemu/qemu_monitor_text.c | 43 ++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 4 +++ 3 files changed, 54 insertions(+), 34 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index da08af9..635fb84 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4698,59 +4698,32 @@ static int qemudDomainAttachUsbMassstorageDevice(virConnectPtr conn, virDomainObjPtr vm, virDomainDeviceDefPtr dev) { - int ret, i; - char *safe_path; - char *cmd, *reply; + int i;
for (i = 0 ; i < vm->def->ndisks ; i++) { if (STREQ(vm->def->disks[i]->dst, dev->data.disk->dst)) { - qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED, + qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED, _("target %s already exists"), dev->data.disk->dst); return -1; } }
- if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0) { - virReportOOMError(conn); - return -1; - } - - safe_path = qemudEscapeMonitorArg(dev->data.disk->src); - if (!safe_path) { - virReportOOMError(conn); + if (!dev->data.disk->src) { + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + "%s", _("disk source path is missing"));
That check is new, but okay ACK Cheers, Mark.

One API adds an exact device based on bus+dev, the other adds any device matching vendor+product * src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add new qemuMonitorAddUSBDeviceExact() and qemuMonitorAddUSBDeviceMatch() commands. * src/qemu/qemu_driver.c: Switch over to using the new qemuMonitorAddUSBDeviceExact() and qemuMonitorAddUSBDeviceMatch() --- src/qemu/qemu_driver.c | 43 +++++------------------- src/qemu/qemu_monitor_text.c | 73 ++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 7 ++++ 3 files changed, 89 insertions(+), 34 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 635fb84..f33c24e 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4984,7 +4984,6 @@ static int qemudDomainAttachHostUsbDevice(virConnectPtr conn, virDomainDeviceDefPtr dev) { int ret; - char *cmd, *reply; if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+1) < 0) { virReportOOMError(conn); @@ -4992,43 +4991,19 @@ static int qemudDomainAttachHostUsbDevice(virConnectPtr conn, } if (dev->data.hostdev->source.subsys.u.usb.vendor) { - ret = virAsprintf(&cmd, "usb_add host:%.4x:%.4x", - dev->data.hostdev->source.subsys.u.usb.vendor, - dev->data.hostdev->source.subsys.u.usb.product); + ret = qemuMonitorAddUSBDeviceMatch(vm, + dev->data.hostdev->source.subsys.u.usb.vendor, + dev->data.hostdev->source.subsys.u.usb.product); } else { - ret = virAsprintf(&cmd, "usb_add host:%.3d.%.3d", - dev->data.hostdev->source.subsys.u.usb.bus, - dev->data.hostdev->source.subsys.u.usb.device); - } - if (ret == -1) { - virReportOOMError(conn); - return -1; - } - - if (qemudMonitorCommand(vm, cmd, &reply) < 0) { - qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - "%s", _("cannot attach usb device")); - VIR_FREE(cmd); - return -1; + ret = qemuMonitorAddUSBDeviceExact(vm, + dev->data.hostdev->source.subsys.u.usb.bus, + dev->data.hostdev->source.subsys.u.usb.device); } - DEBUG ("%s: attach_usb reply: %s", vm->def->name, reply); - /* If the command failed qemu prints: - * Could not add ... */ - if (strstr(reply, "Could not add ")) { - qemudReportError (conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - "%s", - _("adding usb device failed")); - VIR_FREE(reply); - VIR_FREE(cmd); - return -1; - } - - vm->def->hostdevs[vm->def->nhostdevs++] = dev->data.hostdev; + if (ret != -1) + vm->def->hostdevs[vm->def->nhostdevs++] = dev->data.hostdev; - VIR_FREE(reply); - VIR_FREE(cmd); - return 0; + return ret; } static int qemudDomainAttachHostDevice(virConnectPtr conn, diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index fd50cf2..0e0334c 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -1242,3 +1242,76 @@ cleanup: VIR_FREE(safepath); return ret; } + + +static int qemuMonitorAddUSBDevice(const virDomainObjPtr vm, + const char *addr) +{ + char *cmd; + char *reply = NULL; + int ret = -1; + + if (virAsprintf(&cmd, "usb_add %s", addr) < 0) { + virReportOOMError(NULL); + return -1; + } + + if (qemudMonitorCommand(vm, cmd, &reply) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + "%s", _("cannot attach usb device")); + goto cleanup; + } + + DEBUG ("%s: attach_usb reply: %s", vm->def->name, reply); + /* If the command failed qemu prints: + * Could not add ... */ + if (strstr(reply, "Could not add ")) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + "%s", _("adding usb device failed")); + goto cleanup; + } + + ret = 0; + +cleanup: + VIR_FREE(cmd); + VIR_FREE(reply); + return ret; +} + + +int qemuMonitorAddUSBDeviceExact(const virDomainObjPtr vm, + int bus, + int dev) +{ + int ret; + char *addr; + + if (virAsprintf(&addr, "host:%.3d.%.3d", bus, dev) < 0) { + virReportOOMError(NULL); + return -1; + } + + ret = qemuMonitorAddUSBDevice(vm, addr); + + VIR_FREE(addr); + return ret; +} + +int qemuMonitorAddUSBDeviceMatch(const virDomainObjPtr vm, + int vendor, + int product) +{ + int ret; + char *addr; + + if (virAsprintf(&addr, "host:%.4x:%.4x", vendor, product) < 0) { + virReportOOMError(NULL); + return -1; + } + + ret = qemuMonitorAddUSBDevice(vm, addr); + + VIR_FREE(addr); + return ret; +} diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index 138e7a0..4153090 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -140,4 +140,11 @@ int qemuMonitorMigrateToCommand(const virDomainObjPtr vm, int qemuMonitorAddUSBDisk(const virDomainObjPtr vm, const char *path); +int qemuMonitorAddUSBDeviceExact(const virDomainObjPtr vm, + int bus, + int dev); +int qemuMonitorAddUSBDeviceMatch(const virDomainObjPtr vm, + int vendor, + int product); + #endif /* QEMU_MONITOR_TEXT_H */ -- 1.6.2.5

On Thu, 2009-09-24 at 16:00 +0100, Daniel P. Berrange wrote:
One API adds an exact device based on bus+dev, the other adds any device matching vendor+product
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add new qemuMonitorAddUSBDeviceExact() and qemuMonitorAddUSBDeviceMatch() commands. * src/qemu/qemu_driver.c: Switch over to using the new qemuMonitorAddUSBDeviceExact() and qemuMonitorAddUSBDeviceMatch() --- src/qemu/qemu_driver.c | 43 +++++------------------- src/qemu/qemu_monitor_text.c | 73 ++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 7 ++++ 3 files changed, 89 insertions(+), 34 deletions(-) ...
ACK Cheers, Mark.

* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add new API qemuMonitorAddPCIHostDevice() * src/qemu/qemu_driver.c: Switch to using qemuMonitorAddPCIHostDevice() for PCI host device hotplug --- src/qemu/qemu_driver.c | 46 +++------------- src/qemu/qemu_monitor_text.c | 121 ++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 11 ++++ 3 files changed, 140 insertions(+), 38 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index f33c24e..e9e7543 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4903,8 +4903,6 @@ static int qemudDomainAttachHostPciDevice(virConnectPtr conn, virDomainDeviceDefPtr dev) { virDomainHostdevDefPtr hostdev = dev->data.hostdev; - char *cmd, *reply; - unsigned domain, bus, slot; pciDevice *pci; if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+1) < 0) { @@ -4931,51 +4929,23 @@ static int qemudDomainAttachHostPciDevice(virConnectPtr conn, return -1; } - cmd = reply = NULL; - - if (virAsprintf(&cmd, "pci_add pci_addr=auto host host=%.2x:%.2x.%.1x", - hostdev->source.subsys.u.pci.bus, - hostdev->source.subsys.u.pci.slot, - hostdev->source.subsys.u.pci.function) < 0) { - virReportOOMError(conn); - goto error; - } - - if (qemudMonitorCommand(vm, cmd, &reply) < 0) { - qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - "%s", _("cannot attach host pci device")); + if (qemuMonitorAddPCIHostDevice(vm, + hostdev->source.subsys.u.pci.domain, + hostdev->source.subsys.u.pci.bus, + hostdev->source.subsys.u.pci.slot, + hostdev->source.subsys.u.pci.function, + &hostdev->source.subsys.u.pci.guest_addr.domain, + &hostdev->source.subsys.u.pci.guest_addr.bus, + &hostdev->source.subsys.u.pci.guest_addr.slot) < 0) goto error; - } - - if (strstr(reply, "invalid type: host")) { - qemudReportError(conn, dom, NULL, VIR_ERR_NO_SUPPORT, "%s", - _("PCI device assignment is not supported by this version of qemu")); - goto error; - } - - if (qemudParsePciAddReply(vm, reply, &domain, &bus, &slot) < 0) { - qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - _("parsing pci_add reply failed: %s"), reply); - goto error; - } - - hostdev->source.subsys.u.pci.guest_addr.domain = domain; - hostdev->source.subsys.u.pci.guest_addr.bus = bus; - hostdev->source.subsys.u.pci.guest_addr.slot = slot; vm->def->hostdevs[vm->def->nhostdevs++] = hostdev; - VIR_FREE(reply); - VIR_FREE(cmd); - return 0; error: pciDeviceListDel(conn, driver->activePciHostdevs, pci); - VIR_FREE(reply); - VIR_FREE(cmd); - return -1; } diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 0e0334c..ca84fc6 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -1315,3 +1315,124 @@ int qemuMonitorAddUSBDeviceMatch(const virDomainObjPtr vm, VIR_FREE(addr); return ret; } + + +static int +qemuMonitorParsePciAddReply(virDomainObjPtr vm, + const char *reply, + unsigned *domain, + unsigned *bus, + unsigned *slot) +{ + char *s, *e; + + DEBUG("%s: pci_add reply: %s", vm->def->name, reply); + + /* If the command succeeds qemu prints: + * OK bus 0, slot XXX... + * or + * OK domain 0, bus 0, slot XXX + */ + if (!(s = strstr(reply, "OK "))) + return -1; + + s += 3; + + if (STRPREFIX(s, "domain ")) { + s += strlen("domain "); + + if (virStrToLong_ui(s, &e, 10, domain) == -1) { + VIR_WARN(_("Unable to parse domain number '%s'\n"), s); + return -1; + } + + if (!STRPREFIX(e, ", ")) { + VIR_WARN(_("Expected ', ' parsing pci_add reply '%s'\n"), s); + return -1; + } + s = e + 2; + } + + if (!STRPREFIX(s, "bus ")) { + VIR_WARN(_("Expected 'bus ' parsing pci_add reply '%s'\n"), s); + return -1; + } + s += strlen("bus "); + + if (virStrToLong_ui(s, &e, 10, bus) == -1) { + VIR_WARN(_("Unable to parse bus number '%s'\n"), s); + return -1; + } + + if (!STRPREFIX(e, ", ")) { + VIR_WARN(_("Expected ', ' parsing pci_add reply '%s'\n"), s); + return -1; + } + s = e + 2; + + if (!STRPREFIX(s, "slot ")) { + VIR_WARN(_("Expected 'slot ' parsing pci_add reply '%s'\n"), s); + return -1; + } + s += strlen("slot "); + + if (virStrToLong_ui(s, &e, 10, slot) == -1) { + VIR_WARN(_("Unable to parse slot number '%s'\n"), s); + return -1; + } + + return 0; +} + + +int qemuMonitorAddPCIHostDevice(const virDomainObjPtr vm, + unsigned hostDomain ATTRIBUTE_UNUSED, + unsigned hostBus, + unsigned hostSlot, + unsigned hostFunction, + unsigned *guestDomain, + unsigned *guestBus, + unsigned *guestSlot) +{ + char *cmd; + char *reply = NULL; + int ret = -1; + + *guestDomain = *guestBus = *guestSlot = 0; + + /* XXX hostDomain */ + if (virAsprintf(&cmd, "pci_add pci_addr=auto host host=%.2x:%.2x.%.1x", + hostBus, hostSlot, hostFunction) < 0) { + virReportOOMError(NULL); + goto cleanup; + } + + if (qemudMonitorCommand(vm, cmd, &reply) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + "%s", _("cannot attach host pci device")); + goto cleanup; + } + + if (strstr(reply, "invalid type: host")) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_NO_SUPPORT, "%s", + _("PCI device assignment is not supported by this version of qemu")); + goto cleanup; + } + + if (qemuMonitorParsePciAddReply(vm, reply, + guestDomain, + guestBus, + guestSlot) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + _("parsing pci_add reply failed: %s"), reply); + goto cleanup; + } + + ret = 0; + +cleanup: + VIR_FREE(cmd); + VIR_FREE(reply); + return ret; +} + diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index 4153090..0e1b27b 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -147,4 +147,15 @@ int qemuMonitorAddUSBDeviceMatch(const virDomainObjPtr vm, int vendor, int product); + +int qemuMonitorAddPCIHostDevice(const virDomainObjPtr vm, + unsigned hostDomain, + unsigned hostBus, + unsigned hostSlot, + unsigned hostFunction, + unsigned *guestDomain, + unsigned *guestBus, + unsigned *guestSlot); + + #endif /* QEMU_MONITOR_TEXT_H */ -- 1.6.2.5

Subject typo - 'issugin' On Thu, 2009-09-24 at 16:00 +0100, Daniel P. Berrange wrote:
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add new API qemuMonitorAddPCIHostDevice() * src/qemu/qemu_driver.c: Switch to using qemuMonitorAddPCIHostDevice() for PCI host device hotplug --- src/qemu/qemu_driver.c | 46 +++------------- src/qemu/qemu_monitor_text.c | 121 ++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 11 ++++ 3 files changed, 140 insertions(+), 38 deletions(-)
...
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 0e0334c..ca84fc6 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -1315,3 +1315,124 @@ int qemuMonitorAddUSBDeviceMatch(const virDomainObjPtr vm, VIR_FREE(addr); return ret; } + + +static int +qemuMonitorParsePciAddReply(virDomainObjPtr vm, + const char *reply, + unsigned *domain, + unsigned *bus, + unsigned *slot)
Again, had to look outside the patch to verify that this was a straight copy ACK Cheers, Mark.

* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add new API qemuMonitorRemovePCIDevice() for removing PCI device * src/qemu/qemu_driver.c: Convert all places removing PCI devices over to new qemuMonitorRemovePCIDevice() API --- src/qemu/qemu_driver.c | 120 ++++------------------------------------- src/qemu/qemu_monitor_text.c | 60 +++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 6 ++ 3 files changed, 78 insertions(+), 108 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index e9e7543..10fc09a 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -5138,10 +5138,7 @@ static int qemudDomainDetachPciDiskDevice(virConnectPtr conn, virDomainObjPtr vm, virDomainDeviceDefPtr dev) { int i, ret = -1; - char *cmd = NULL; - char *reply = NULL; virDomainDiskDefPtr detach = NULL; - int tryOldSyntax = 0; for (i = 0 ; i < vm->def->ndisks ; i++) { if (STREQ(vm->def->disks[i]->dst, dev->data.disk->dst)) { @@ -5163,48 +5160,11 @@ static int qemudDomainDetachPciDiskDevice(virConnectPtr conn, goto cleanup; } -try_command: - if (tryOldSyntax) { - if (virAsprintf(&cmd, "pci_del 0 %.2x", detach->pci_addr.slot) < 0) { - virReportOOMError(conn); - goto cleanup; - } - } else { - if (virAsprintf(&cmd, "pci_del pci_addr=%.4x:%.2x:%.2x", - detach->pci_addr.domain, - detach->pci_addr.bus, - detach->pci_addr.slot) < 0) { - virReportOOMError(conn); - goto cleanup; - } - } - - if (qemudMonitorCommand(vm, cmd, &reply) < 0) { - qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED, - _("failed to execute detach disk %s command"), detach->dst); + if (qemuMonitorRemovePCIDevice(vm, + detach->pci_addr.domain, + detach->pci_addr.bus, + detach->pci_addr.slot) < 0) goto cleanup; - } - - DEBUG ("%s: pci_del reply: %s",vm->def->name, reply); - - if (!tryOldSyntax && - strstr(reply, "extraneous characters")) { - tryOldSyntax = 1; - goto try_command; - } - /* If the command fails due to a wrong slot qemu prints: invalid slot, - * nothing is printed on success */ - if (strstr(reply, "invalid slot") || - strstr(reply, "Invalid pci address")) { - qemudReportError (conn, NULL, NULL, VIR_ERR_OPERATION_FAILED, - _("failed to detach disk %s: invalid PCI address %.4x:%.2x:%.2x: %s"), - detach->dst, - detach->pci_addr.domain, - detach->pci_addr.bus, - detach->pci_addr.slot, - reply); - goto cleanup; - } if (vm->def->ndisks > 1) { memmove(vm->def->disks + i, @@ -5224,8 +5184,6 @@ try_command: ret = 0; cleanup: - VIR_FREE(reply); - VIR_FREE(cmd); return ret; } @@ -5263,36 +5221,11 @@ qemudDomainDetachNetDevice(virConnectPtr conn, goto cleanup; } - if (virAsprintf(&cmd, "pci_del pci_addr=%.4x:%.2x:%.2x", - detach->pci_addr.domain, - detach->pci_addr.bus, - detach->pci_addr.slot) < 0) { - virReportOOMError(conn); - goto cleanup; - } - - if (qemudMonitorCommand(vm, cmd, &reply) < 0) { - qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED, - _("network device dettach command '%s' failed"), cmd); - goto cleanup; - } - - DEBUG("%s: pci_del reply: %s", vm->def->name, reply); - - /* If the command fails due to a wrong PCI address qemu prints - * 'invalid pci address'; nothing is printed on success */ - if (strstr(reply, "Invalid pci address")) { - qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED, - _("failed to detach network device: invalid PCI address %.4x:%.2x:%.2x: %s"), - detach->pci_addr.domain, - detach->pci_addr.bus, - detach->pci_addr.slot, - reply); + if (qemuMonitorRemovePCIDevice(vm, + detach->pci_addr.domain, + detach->pci_addr.bus, + detach->pci_addr.slot) < 0) goto cleanup; - } - - VIR_FREE(reply); - VIR_FREE(cmd); if (virAsprintf(&cmd, "host_net_remove %d %s", detach->vlan, detach->hostnet_name) < 0) { @@ -5337,7 +5270,6 @@ static int qemudDomainDetachHostPciDevice(virConnectPtr conn, virDomainDeviceDefPtr dev) { virDomainHostdevDefPtr detach = NULL; - char *cmd, *reply; int i, ret; pciDevice *pci; @@ -5372,39 +5304,11 @@ static int qemudDomainDetachHostPciDevice(virConnectPtr conn, return -1; } - if (virAsprintf(&cmd, "pci_del pci_addr=%.4x:%.2x:%.2x", - detach->source.subsys.u.pci.guest_addr.domain, - detach->source.subsys.u.pci.guest_addr.bus, - detach->source.subsys.u.pci.guest_addr.slot) < 0) { - virReportOOMError(conn); + if (qemuMonitorRemovePCIDevice(vm, + detach->source.subsys.u.pci.guest_addr.domain, + detach->source.subsys.u.pci.guest_addr.bus, + detach->source.subsys.u.pci.guest_addr.slot) < 0) return -1; - } - - if (qemudMonitorCommand(vm, cmd, &reply) < 0) { - qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - "%s", _("cannot detach host pci device")); - VIR_FREE(cmd); - return -1; - } - - DEBUG("%s: pci_del reply: %s", vm->def->name, reply); - - /* If the command fails due to a wrong PCI address qemu prints - * 'invalid pci address'; nothing is printed on success */ - if (strstr(reply, "Invalid pci address")) { - qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED, - _("failed to detach host pci device: invalid PCI address %.4x:%.2x:%.2x: %s"), - detach->source.subsys.u.pci.guest_addr.domain, - detach->source.subsys.u.pci.guest_addr.bus, - detach->source.subsys.u.pci.guest_addr.slot, - reply); - VIR_FREE(reply); - VIR_FREE(cmd); - return -1; - } - - VIR_FREE(reply); - VIR_FREE(cmd); ret = 0; diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index ca84fc6..290dcce 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -1436,3 +1436,63 @@ cleanup: return ret; } + +int qemuMonitorRemovePCIDevice(const virDomainObjPtr vm, + unsigned guestDomain, + unsigned guestBus, + unsigned guestSlot) +{ + char *cmd = NULL; + char *reply = NULL; + int tryOldSyntax = 0; + int ret = -1; + +try_command: + if (tryOldSyntax) { + if (virAsprintf(&cmd, "pci_del 0 %.2x", guestSlot) < 0) { + virReportOOMError(NULL); + goto cleanup; + } + } else { + if (virAsprintf(&cmd, "pci_del pci_addr=%.4x:%.2x:%.2x", + guestDomain, guestBus, guestSlot) < 0) { + virReportOOMError(NULL); + goto cleanup; + } + } + + if (qemudMonitorCommand(vm, cmd, &reply) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + "%s", _("failed to remove PCI device")); + goto cleanup; + } + + DEBUG ("%s: pci_del reply: %s",vm->def->name, reply); + + /* Syntax changed when KVM merged PCI hotplug upstream to QEMU, + * so check for an error message from old KVM indicating the + * need to try the old syntax */ + if (!tryOldSyntax && + strstr(reply, "extraneous characters")) { + tryOldSyntax = 1; + VIR_FREE(reply); + VIR_FREE(cmd); + goto try_command; + } + /* If the command fails due to a wrong slot qemu prints: invalid slot, + * nothing is printed on success */ + if (strstr(reply, "invalid slot") || + strstr(reply, "Invalid pci address")) { + qemudReportError (NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + _("failed to detach PCI device, invalid address %.4x:%.2x:%.2x: %s"), + guestDomain, guestBus, guestSlot, reply); + goto cleanup; + } + + ret = 0; + +cleanup: + VIR_FREE(cmd); + VIR_FREE(reply); + return ret; +} diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index 0e1b27b..342e71e 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -157,5 +157,11 @@ int qemuMonitorAddPCIHostDevice(const virDomainObjPtr vm, unsigned *guestBus, unsigned *guestSlot); +int qemuMonitorRemovePCIDevice(const virDomainObjPtr vm, + unsigned guestDomain, + unsigned guestBus, + unsigned guestSlot); + + #endif /* QEMU_MONITOR_TEXT_H */ -- 1.6.2.5

On Thu, 2009-09-24 at 16:00 +0100, Daniel P. Berrange wrote:
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add new API qemuMonitorRemovePCIDevice() for removing PCI device * src/qemu/qemu_driver.c: Convert all places removing PCI devices over to new qemuMonitorRemovePCIDevice() API --- src/qemu/qemu_driver.c | 120 ++++------------------------------------- src/qemu/qemu_monitor_text.c | 60 +++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 6 ++ 3 files changed, 78 insertions(+), 108 deletions(-)
...
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index ca84fc6..290dcce 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -1436,3 +1436,63 @@ cleanup: return ret; }
+ +int qemuMonitorRemovePCIDevice(const virDomainObjPtr vm, + unsigned guestDomain, + unsigned guestBus, + unsigned guestSlot) +{ + char *cmd = NULL; + char *reply = NULL; + int tryOldSyntax = 0; + int ret = -1; + +try_command: + if (tryOldSyntax) { + if (virAsprintf(&cmd, "pci_del 0 %.2x", guestSlot) < 0) { + virReportOOMError(NULL); + goto cleanup; + } + } else { + if (virAsprintf(&cmd, "pci_del pci_addr=%.4x:%.2x:%.2x", + guestDomain, guestBus, guestSlot) < 0) { + virReportOOMError(NULL); + goto cleanup; + } + } + + if (qemudMonitorCommand(vm, cmd, &reply) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + "%s", _("failed to remove PCI device")); + goto cleanup; + } + + DEBUG ("%s: pci_del reply: %s",vm->def->name, reply); + + /* Syntax changed when KVM merged PCI hotplug upstream to QEMU, + * so check for an error message from old KVM indicating the + * need to try the old syntax */ + if (!tryOldSyntax && + strstr(reply, "extraneous characters")) { + tryOldSyntax = 1; + VIR_FREE(reply); + VIR_FREE(cmd); + goto try_command;
This fixes a leak in the old code, would have been nice to have as a separate patch ACK Cheers, Mark.

* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add new API qemuMonitorAddPCIDisk() * src/qemu/qemu_driver.c: Convert over to using the new qemuMonitorAddPCIDisk() method, and remove now obsolete qemudEscape() method --- src/qemu/qemu_driver.c | 130 ++--------------------------------------- src/qemu/qemu_monitor_text.c | 55 ++++++++++++++++++ src/qemu/qemu_monitor_text.h | 13 ++++ 3 files changed, 75 insertions(+), 123 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 10fc09a..b447a87 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -3093,83 +3093,6 @@ cleanup: } -static char *qemudEscape(const char *in, int shell) -{ - int len = 0; - int i, j; - char *out; - - /* To pass through the QEMU monitor, we need to use escape - sequences: \r, \n, \", \\ - - To pass through both QEMU + the shell, we need to escape - the single character ' as the five characters '\\'' - */ - - for (i = 0; in[i] != '\0'; i++) { - switch(in[i]) { - case '\r': - case '\n': - case '"': - case '\\': - len += 2; - break; - case '\'': - if (shell) - len += 5; - else - len += 1; - break; - default: - len += 1; - break; - } - } - - if (VIR_ALLOC_N(out, len + 1) < 0) - return NULL; - - for (i = j = 0; in[i] != '\0'; i++) { - switch(in[i]) { - case '\r': - out[j++] = '\\'; - out[j++] = 'r'; - break; - case '\n': - out[j++] = '\\'; - out[j++] = 'n'; - break; - case '"': - case '\\': - out[j++] = '\\'; - out[j++] = in[i]; - break; - case '\'': - if (shell) { - out[j++] = '\''; - out[j++] = '\\'; - out[j++] = '\\'; - out[j++] = '\''; - out[j++] = '\''; - } else { - out[j++] = in[i]; - } - break; - default: - out[j++] = in[i]; - break; - } - } - out[j] = '\0'; - - return out; -} - -static char *qemudEscapeMonitorArg(const char *in) -{ - return qemudEscape(in, 0); -} - #define QEMUD_SAVE_MAGIC "LibvirtQemudSave" #define QEMUD_SAVE_VERSION 2 @@ -4626,12 +4549,8 @@ static int qemudDomainAttachPciDiskDevice(virConnectPtr conn, virDomainObjPtr vm, virDomainDeviceDefPtr dev) { - int ret, i; - char *cmd, *reply; - char *safe_path; + int i; const char* type = virDomainDiskBusTypeToString(dev->data.disk->bus); - int tryOldSyntax = 0; - unsigned domain, bus, slot; for (i = 0 ; i < vm->def->ndisks ; i++) { if (STREQ(vm->def->disks[i]->dst, dev->data.disk->dst)) { @@ -4646,48 +4565,13 @@ static int qemudDomainAttachPciDiskDevice(virConnectPtr conn, return -1; } -try_command: - safe_path = qemudEscapeMonitorArg(dev->data.disk->src); - if (!safe_path) { - virReportOOMError(conn); - return -1; - } - - ret = virAsprintf(&cmd, "pci_add %s storage file=%s,if=%s", - (tryOldSyntax ? "0": "pci_addr=auto"), safe_path, type); - VIR_FREE(safe_path); - if (ret == -1) { - virReportOOMError(conn); - return ret; - } - - if (qemudMonitorCommand(vm, cmd, &reply) < 0) { - qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - _("cannot attach %s disk"), type); - VIR_FREE(cmd); + if (qemuMonitorAddPCIDisk(vm, + dev->data.disk->src, + type, + &dev->data.disk->pci_addr.domain, + &dev->data.disk->pci_addr.bus, + &dev->data.disk->pci_addr.slot) < 0) return -1; - } - - VIR_FREE(cmd); - - if (qemudParsePciAddReply(vm, reply, &domain, &bus, &slot) < 0) { - if (!tryOldSyntax && strstr(reply, "invalid char in expression")) { - VIR_FREE(reply); - tryOldSyntax = 1; - goto try_command; - } - - qemudReportError (conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - _("adding %s disk failed: %s"), type, reply); - VIR_FREE(reply); - return -1; - } - - VIR_FREE(reply); - - dev->data.disk->pci_addr.domain = domain; - dev->data.disk->pci_addr.bus = bus; - dev->data.disk->pci_addr.slot = slot; virDomainDiskInsertPreAlloced(vm->def, dev->data.disk); diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 290dcce..765a482 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -1437,6 +1437,61 @@ cleanup: } +int qemuMonitorAddPCIDisk(const virDomainObjPtr vm, + const char *path, + const char *bus, + unsigned *guestDomain, + unsigned *guestBus, + unsigned *guestSlot) { + char *cmd = NULL; + char *reply = NULL; + char *safe_path = NULL; + int tryOldSyntax = 0; + int ret = -1; + + safe_path = qemudEscapeMonitorArg(path); + if (!safe_path) { + virReportOOMError(NULL); + return -1; + } + +try_command: + if (virAsprintf(&cmd, "pci_add %s storage file=%s,if=%s", + (tryOldSyntax ? "0": "pci_addr=auto"), safe_path, bus) < 0) { + virReportOOMError(NULL); + goto cleanup; + } + + if (qemudMonitorCommand(vm, cmd, &reply) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + _("cannot attach %s disk %s"), bus, path); + goto cleanup; + } + + if (qemuMonitorParsePciAddReply(vm, reply, + guestDomain, guestBus, guestSlot) < 0) { + if (!tryOldSyntax && strstr(reply, "invalid char in expression")) { + VIR_FREE(reply); + VIR_FREE(cmd); + tryOldSyntax = 1; + goto try_command; + } + + qemudReportError (NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + _("adding %s disk failed %s: %s"), bus, path, reply); + goto cleanup; + } + + ret = 0; + +cleanup: + VIR_FREE(cmd); + VIR_FREE(reply); + return ret; +} + + + int qemuMonitorRemovePCIDevice(const virDomainObjPtr vm, unsigned guestDomain, unsigned guestBus, diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index 342e71e..f3c1e62 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -137,6 +137,9 @@ int qemuMonitorMigrateToCommand(const virDomainObjPtr vm, const char *target); +/* XXX disk driver type eg, qcow/etc. + * XXX cache mode + */ int qemuMonitorAddUSBDisk(const virDomainObjPtr vm, const char *path); @@ -157,6 +160,16 @@ int qemuMonitorAddPCIHostDevice(const virDomainObjPtr vm, unsigned *guestBus, unsigned *guestSlot); +/* XXX disk driver type eg, qcow/etc. + * XXX cache mode + */ +int qemuMonitorAddPCIDisk(const virDomainObjPtr vm, + const char *path, + const char *bus, + unsigned *guestDomain, + unsigned *guestBus, + unsigned *guestSlot); + int qemuMonitorRemovePCIDevice(const virDomainObjPtr vm, unsigned guestDomain, unsigned guestBus, -- 1.6.2.5

On Thu, 2009-09-24 at 16:00 +0100, Daniel P. Berrange wrote:
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add new API qemuMonitorAddPCIDisk() * src/qemu/qemu_driver.c: Convert over to using the new qemuMonitorAddPCIDisk() method, and remove now obsolete qemudEscape() method --- src/qemu/qemu_driver.c | 130 ++--------------------------------------- src/qemu/qemu_monitor_text.c | 55 ++++++++++++++++++ src/qemu/qemu_monitor_text.h | 13 ++++ 3 files changed, 75 insertions(+), 123 deletions(-)
...
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 290dcce..765a482 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -1437,6 +1437,61 @@ cleanup: }
+int qemuMonitorAddPCIDisk(const virDomainObjPtr vm, + const char *path, + const char *bus, + unsigned *guestDomain, + unsigned *guestBus, + unsigned *guestSlot) { + char *cmd = NULL; + char *reply = NULL; + char *safe_path = NULL; + int tryOldSyntax = 0; + int ret = -1; + + safe_path = qemudEscapeMonitorArg(path); + if (!safe_path) { + virReportOOMError(NULL); + return -1; + } + +try_command: + if (virAsprintf(&cmd, "pci_add %s storage file=%s,if=%s", + (tryOldSyntax ? "0": "pci_addr=auto"), safe_path, bus) < 0) { + virReportOOMError(NULL); + goto cleanup; + } + + if (qemudMonitorCommand(vm, cmd, &reply) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + _("cannot attach %s disk %s"), bus, path); + goto cleanup; + } + + if (qemuMonitorParsePciAddReply(vm, reply, + guestDomain, guestBus, guestSlot) < 0) { + if (!tryOldSyntax && strstr(reply, "invalid char in expression")) { + VIR_FREE(reply); + VIR_FREE(cmd); + tryOldSyntax = 1; + goto try_command; + } + + qemudReportError (NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + _("adding %s disk failed %s: %s"), bus, path, reply); + goto cleanup; + } + + ret = 0; + +cleanup: + VIR_FREE(cmd); + VIR_FREE(reply); + return ret; +}
safe_path is leaked Otherwise ACK Cheers, Mark.

* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add new qemuMonitorCloseFileHandle and qemuMonitorSendFileHandle APIs for processing file handles * src/qemu/qemu_driver.c: Convert NIC hotplug method over to use qemuMonitorCloseFileHandle and qemuMonitorSendFileHandle --- src/qemu/qemu_driver.c | 40 +++------------------ src/qemu/qemu_monitor_text.c | 78 ++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 6 +++ 3 files changed, 90 insertions(+), 34 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index b447a87..f8710a6 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4619,7 +4619,7 @@ static int qemudDomainAttachNetDevice(virConnectPtr conn, { virDomainNetDefPtr net = dev->data.net; char *cmd = NULL, *reply = NULL, *remove_cmd = NULL; - char *tapfd_name = NULL, *tapfd_close = NULL; + char *tapfd_name = NULL; int i, tapfd = -1; unsigned domain, bus, slot; @@ -4662,32 +4662,8 @@ static int qemudDomainAttachNetDevice(virConnectPtr conn, if (virAsprintf(&tapfd_name, "fd-%s", net->hostnet_name) < 0) goto no_memory; - if (virAsprintf(&tapfd_close, "closefd %s", tapfd_name) < 0) - goto no_memory; - - if (virAsprintf(&cmd, "getfd %s", tapfd_name) < 0) - goto no_memory; - - if (qemudMonitorCommandWithFd(vm, cmd, tapfd, &reply) < 0) { - qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - _("failed to pass fd to qemu with '%s'"), cmd); + if (qemuMonitorSendFileHandle(vm, tapfd_name, tapfd) < 0) goto cleanup; - } - - DEBUG("%s: getfd reply: %s", vm->def->name, reply); - - /* If the command isn't supported then qemu prints: - * unknown command: getfd" */ - if (strstr(reply, "unknown command:")) { - qemudReportError(conn, dom, NULL, VIR_ERR_NO_SUPPORT, - "%s", - _("bridge/network interface attach not supported: " - "qemu 'getfd' monitor command not available")); - goto cleanup; - } - - VIR_FREE(reply); - VIR_FREE(cmd); } if (qemuBuildHostNetStr(conn, net, "host_net_add ", ' ', @@ -4713,7 +4689,6 @@ static int qemudDomainAttachNetDevice(virConnectPtr conn, VIR_FREE(reply); VIR_FREE(cmd); VIR_FREE(tapfd_name); - VIR_FREE(tapfd_close); if (tapfd != -1) close(tapfd); tapfd = -1; @@ -4760,12 +4735,10 @@ try_remove: try_tapfd_close: VIR_FREE(reply); - if (tapfd_close) { - if (qemudMonitorCommand(vm, tapfd_close, &reply) < 0) - VIR_WARN(_("Failed to close tapfd with '%s'\n"), tapfd_close); - else - VIR_DEBUG("%s: closefd: %s\n", vm->def->name, reply); - } + if (tapfd_name && + qemuMonitorCloseFileHandle(vm, tapfd_name) < 0) + VIR_WARN(_("Failed to close tapfd with '%s'\n"), tapfd_name); + goto cleanup; no_memory: @@ -4774,7 +4747,6 @@ cleanup: VIR_FREE(cmd); VIR_FREE(reply); VIR_FREE(remove_cmd); - VIR_FREE(tapfd_close); VIR_FREE(tapfd_name); if (tapfd != -1) close(tapfd); diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 765a482..92a2dbd 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -1551,3 +1551,81 @@ cleanup: VIR_FREE(reply); return ret; } + + +int qemuMonitorSendFileHandle(const virDomainObjPtr vm, + const char *fdname, + int fd) +{ + char *cmd; + char *reply = NULL; + int ret = -1; + + if (virAsprintf(&cmd, "getfd %s", fdname) < 0) { + virReportOOMError(NULL); + return -1; + } + + if (qemudMonitorCommandWithFd(vm, cmd, fd, &reply) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + _("failed to pass fd to qemu with '%s'"), cmd); + goto cleanup; + } + + DEBUG("%s: getfd reply: %s", vm->def->name, reply); + + /* If the command isn't supported then qemu prints: + * unknown command: getfd" */ + if (strstr(reply, "unknown command:")) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_NO_SUPPORT, + _("qemu does not support sending of file handles: %s"), + reply); + goto cleanup; + } + + ret = 0; + +cleanup: + VIR_FREE(cmd); + VIR_FREE(reply); + return ret; +} + + +int qemuMonitorCloseFileHandle(const virDomainObjPtr vm, + const char *fdname) +{ + char *cmd; + char *reply = NULL; + int ret = -1; + + if (virAsprintf(&cmd, "closefd %s", fdname) < 0) { + virReportOOMError(NULL); + return -1; + } + + if (qemudMonitorCommand(vm, cmd, &reply) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + _("failed to close fd in qemu with '%s'"), cmd); + goto cleanup; + } + + DEBUG("%s: closefd reply: %s", vm->def->name, reply); + + /* If the command isn't supported then qemu prints: + * unknown command: getfd" */ + if (strstr(reply, "unknown command:")) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_NO_SUPPORT, + _("qemu does not support closing of file handles: %s"), + reply); + goto cleanup; + } + + ret = 0; + +cleanup: + VIR_FREE(cmd); + VIR_FREE(reply); + return ret; +} + diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index f3c1e62..b6dae52 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -176,5 +176,11 @@ int qemuMonitorRemovePCIDevice(const virDomainObjPtr vm, unsigned guestSlot); +int qemuMonitorSendFileHandle(const virDomainObjPtr vm, + const char *fdname, + int fd); + +int qemuMonitorCloseFileHandle(const virDomainObjPtr vm, + const char *fdname); #endif /* QEMU_MONITOR_TEXT_H */ -- 1.6.2.5

On Thu, 2009-09-24 at 16:00 +0100, Daniel P. Berrange wrote:
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add new qemuMonitorCloseFileHandle and qemuMonitorSendFileHandle APIs for processing file handles * src/qemu/qemu_driver.c: Convert NIC hotplug method over to use qemuMonitorCloseFileHandle and qemuMonitorSendFileHandle --- src/qemu/qemu_driver.c | 40 +++------------------ src/qemu/qemu_monitor_text.c | 78 ++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 6 +++ 3 files changed, 90 insertions(+), 34 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index b447a87..f8710a6 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4619,7 +4619,7 @@ static int qemudDomainAttachNetDevice(virConnectPtr conn, { virDomainNetDefPtr net = dev->data.net; char *cmd = NULL, *reply = NULL, *remove_cmd = NULL; - char *tapfd_name = NULL, *tapfd_close = NULL; + char *tapfd_name = NULL; int i, tapfd = -1; unsigned domain, bus, slot;
@@ -4662,32 +4662,8 @@ static int qemudDomainAttachNetDevice(virConnectPtr conn, if (virAsprintf(&tapfd_name, "fd-%s", net->hostnet_name) < 0) goto no_memory;
- if (virAsprintf(&tapfd_close, "closefd %s", tapfd_name) < 0) - goto no_memory;
You're dropping the pre-allocation of the closefd command meaning the code is less likely to actually work under OOM, but we're fantasising if we think our OOM handling is that good anyway :-) ACK Cheers, Mark.

On Mon, Sep 28, 2009 at 02:23:05PM +0100, Mark McLoughlin wrote:
On Thu, 2009-09-24 at 16:00 +0100, Daniel P. Berrange wrote:
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add new qemuMonitorCloseFileHandle and qemuMonitorSendFileHandle APIs for processing file handles * src/qemu/qemu_driver.c: Convert NIC hotplug method over to use qemuMonitorCloseFileHandle and qemuMonitorSendFileHandle --- src/qemu/qemu_driver.c | 40 +++------------------ src/qemu/qemu_monitor_text.c | 78 ++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 6 +++ 3 files changed, 90 insertions(+), 34 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index b447a87..f8710a6 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4619,7 +4619,7 @@ static int qemudDomainAttachNetDevice(virConnectPtr conn, { virDomainNetDefPtr net = dev->data.net; char *cmd = NULL, *reply = NULL, *remove_cmd = NULL; - char *tapfd_name = NULL, *tapfd_close = NULL; + char *tapfd_name = NULL; int i, tapfd = -1; unsigned domain, bus, slot;
@@ -4662,32 +4662,8 @@ static int qemudDomainAttachNetDevice(virConnectPtr conn, if (virAsprintf(&tapfd_name, "fd-%s", net->hostnet_name) < 0) goto no_memory;
- if (virAsprintf(&tapfd_close, "closefd %s", tapfd_name) < 0) - goto no_memory;
You're dropping the pre-allocation of the closefd command meaning the code is less likely to actually work under OOM, but we're fantasising if we think our OOM handling is that good anyway :-)
I observed that the 'qemudMonitorCommandWithHandler' method which we then invoke, has several calls to VIR_REALLOC, ergo pre-allocating the command string won't save us in an OOM scenario. Regards, Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

* src/qemu/qemu_conf.c: Remove separator from qemuBuildNicStr() args, and remove hardcoded 'nic' prefix. Leave it upto callers instead * src/qemu/qemu_driver.c: Switch over to using the new qemuMonitorAddPCINetwork() method for NIC hotplug * src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add new qemuMonitorAddPCINetwork API for PCI network device hotplug --- src/qemu/qemu_conf.c | 6 +-- src/qemu/qemu_conf.h | 1 - src/qemu/qemu_driver.c | 93 ++++-------------------------------------- src/qemu/qemu_monitor_text.c | 36 ++++++++++++++++ src/qemu/qemu_monitor_text.h | 9 ++++ 5 files changed, 55 insertions(+), 90 deletions(-) diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index 309f171..c531454 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -1263,14 +1263,12 @@ int qemuBuildNicStr(virConnectPtr conn, virDomainNetDefPtr net, const char *prefix, - char type_sep, int vlan, char **str) { if (virAsprintf(str, - "%snic%cmacaddr=%02x:%02x:%02x:%02x:%02x:%02x,vlan=%d%s%s%s%s", + "%smacaddr=%02x:%02x:%02x:%02x:%02x:%02x,vlan=%d%s%s%s%s", prefix ? prefix : "", - type_sep, net->mac[0], net->mac[1], net->mac[2], net->mac[3], net->mac[4], net->mac[5], @@ -1988,7 +1986,7 @@ int qemudBuildCommandLine(virConnectPtr conn, qemuAssignNetNames(def, net) < 0) goto no_memory; - if (qemuBuildNicStr(conn, net, NULL, ',', net->vlan, &nic) < 0) + if (qemuBuildNicStr(conn, net, "nic,", net->vlan, &nic) < 0) goto error; if ((qargv[qargc++] = strdup("-net")) == NULL) { diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index 82eb89f..6ff5f0d 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -179,7 +179,6 @@ int qemuBuildHostNetStr (virConnectPtr conn, int qemuBuildNicStr (virConnectPtr conn, virDomainNetDefPtr net, const char *prefix, - char type_sep, int vlan, char **str); diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index f8710a6..6363edc 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4478,72 +4478,6 @@ static int qemudDomainChangeEjectableMedia(virConnectPtr conn, return 0; } -static int -qemudParsePciAddReply(virDomainObjPtr vm, - const char *reply, - unsigned *domain, - unsigned *bus, - unsigned *slot) -{ - char *s, *e; - - DEBUG("%s: pci_add reply: %s", vm->def->name, reply); - - /* If the command succeeds qemu prints: - * OK bus 0, slot XXX... - * or - * OK domain 0, bus 0, slot XXX - */ - if (!(s = strstr(reply, "OK "))) - return -1; - - s += 3; - - if (STRPREFIX(s, "domain ")) { - s += strlen("domain "); - - if (virStrToLong_ui(s, &e, 10, domain) == -1) { - VIR_WARN(_("Unable to parse domain number '%s'\n"), s); - return -1; - } - - if (!STRPREFIX(e, ", ")) { - VIR_WARN(_("Expected ', ' parsing pci_add reply '%s'\n"), s); - return -1; - } - s = e + 2; - } - - if (!STRPREFIX(s, "bus ")) { - VIR_WARN(_("Expected 'bus ' parsing pci_add reply '%s'\n"), s); - return -1; - } - s += strlen("bus "); - - if (virStrToLong_ui(s, &e, 10, bus) == -1) { - VIR_WARN(_("Unable to parse bus number '%s'\n"), s); - return -1; - } - - if (!STRPREFIX(e, ", ")) { - VIR_WARN(_("Expected ', ' parsing pci_add reply '%s'\n"), s); - return -1; - } - s = e + 2; - - if (!STRPREFIX(s, "slot ")) { - VIR_WARN(_("Expected 'slot ' parsing pci_add reply '%s'\n"), s); - return -1; - } - s += strlen("slot "); - - if (virStrToLong_ui(s, &e, 10, slot) == -1) { - VIR_WARN(_("Unable to parse slot number '%s'\n"), s); - return -1; - } - - return 0; -} static int qemudDomainAttachPciDiskDevice(virConnectPtr conn, virDomainObjPtr vm, @@ -4621,7 +4555,7 @@ static int qemudDomainAttachNetDevice(virConnectPtr conn, char *cmd = NULL, *reply = NULL, *remove_cmd = NULL; char *tapfd_name = NULL; int i, tapfd = -1; - unsigned domain, bus, slot; + char *nicstr = NULL; if (!(qemuCmdFlags & QEMUD_CMD_FLAG_HOST_NET_ADD)) { qemudReportError(conn, dom, NULL, VIR_ERR_NO_SUPPORT, "%s", @@ -4693,30 +4627,18 @@ static int qemudDomainAttachNetDevice(virConnectPtr conn, close(tapfd); tapfd = -1; - if (qemuBuildNicStr(conn, net, - "pci_add pci_addr=auto ", ' ', net->vlan, &cmd) < 0) + if (qemuBuildNicStr(conn, net, NULL, net->vlan, &nicstr) < 0) goto try_remove; - if (qemudMonitorCommand(vm, cmd, &reply) < 0) { - qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - _("failed to add NIC with '%s'"), cmd); - goto try_remove; - } - - if (qemudParsePciAddReply(vm, reply, &domain, &bus, &slot) < 0) { - qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - _("parsing pci_add reply failed: %s"), reply); + if (qemuMonitorAddPCINetwork(vm, nicstr, + &net->pci_addr.domain, + &net->pci_addr.bus, + &net->pci_addr.slot) < 0) goto try_remove; - } - VIR_FREE(cmd); - VIR_FREE(reply); + VIR_FREE(nicstr); VIR_FREE(remove_cmd); - net->pci_addr.domain = domain; - net->pci_addr.bus = bus; - net->pci_addr.slot = slot; - vm->def->nets[vm->def->nnets++] = net; return 0; @@ -4744,6 +4666,7 @@ try_tapfd_close: no_memory: virReportOOMError(conn); cleanup: + VIR_FREE(nicstr); VIR_FREE(cmd); VIR_FREE(reply); VIR_FREE(remove_cmd); diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 92a2dbd..c6ffd33 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -1491,6 +1491,42 @@ cleanup: } +int qemuMonitorAddPCINetwork(const virDomainObjPtr vm, + const char *nicstr, + unsigned *guestDomain, + unsigned *guestBus, + unsigned *guestSlot) +{ + char *cmd; + char *reply = NULL; + int ret = -1; + + if (virAsprintf(&cmd, "pci_add pci_addr=auto nic %s", nicstr) < 0) { + virReportOOMError(NULL); + return -1; + } + + if (qemudMonitorCommand(vm, cmd, &reply) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + _("failed to add NIC with '%s'"), cmd); + goto cleanup; + } + + if (qemuMonitorParsePciAddReply(vm, reply, + guestDomain, guestBus, guestSlot) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + _("parsing pci_add reply failed: %s"), reply); + goto cleanup; + } + + ret = 0; + +cleanup: + VIR_FREE(reply); + VIR_FREE(cmd); + return ret; +} + int qemuMonitorRemovePCIDevice(const virDomainObjPtr vm, unsigned guestDomain, diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index b6dae52..1bd9d6d 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -170,6 +170,15 @@ int qemuMonitorAddPCIDisk(const virDomainObjPtr vm, unsigned *guestBus, unsigned *guestSlot); +/* XXX do we really want to hardcode 'nicstr' as the + * sendable item here + */ +int qemuMonitorAddPCINetwork(const virDomainObjPtr vm, + const char *nicstr, + unsigned *guestDomain, + unsigned *guestBus, + unsigned *guestSlot); + int qemuMonitorRemovePCIDevice(const virDomainObjPtr vm, unsigned guestDomain, unsigned guestBus, -- 1.6.2.5

On Thu, 2009-09-24 at 16:00 +0100, Daniel P. Berrange wrote:
* src/qemu/qemu_conf.c: Remove separator from qemuBuildNicStr() args, and remove hardcoded 'nic' prefix. Leave it upto callers instead * src/qemu/qemu_driver.c: Switch over to using the new qemuMonitorAddPCINetwork() method for NIC hotplug * src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add new qemuMonitorAddPCINetwork API for PCI network device hotplug --- src/qemu/qemu_conf.c | 6 +-- src/qemu/qemu_conf.h | 1 - src/qemu/qemu_driver.c | 93 ++++-------------------------------------- src/qemu/qemu_monitor_text.c | 36 ++++++++++++++++ src/qemu/qemu_monitor_text.h | 9 ++++ 5 files changed, 55 insertions(+), 90 deletions(-)
...
diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index b6dae52..1bd9d6d 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -170,6 +170,15 @@ int qemuMonitorAddPCIDisk(const virDomainObjPtr vm, unsigned *guestBus, unsigned *guestSlot);
+/* XXX do we really want to hardcode 'nicstr' as the + * sendable item here + */ +int qemuMonitorAddPCINetwork(const virDomainObjPtr vm, + const char *nicstr, + unsigned *guestDomain, + unsigned *guestBus, + unsigned *guestSlot);
Could split nicstr into vlan/macaddr ACK Cheers, Mark.

* src/qemu/qemu_conf.h, src/qemu/qemu_conf.c: Remove prefix arg from qemuBuildHostNetStr which is no longer required * src/qemu/qemu_driver.c: Refactor to use qemuMonitorAddHostNetwork() API for adding host network * src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add new qemuMonitorAddHostNetwork() method for adding host networks --- src/qemu/qemu_conf.c | 14 ++++---------- src/qemu/qemu_conf.h | 1 - src/qemu/qemu_driver.c | 16 ++++++---------- src/qemu/qemu_monitor_text.c | 30 ++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 7 +++++++ 5 files changed, 47 insertions(+), 21 deletions(-) diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index c531454..1d98637 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -1287,7 +1287,6 @@ qemuBuildNicStr(virConnectPtr conn, int qemuBuildHostNetStr(virConnectPtr conn, virDomainNetDefPtr net, - const char *prefix, char type_sep, int vlan, const char *tapfd, @@ -1296,8 +1295,7 @@ qemuBuildHostNetStr(virConnectPtr conn, switch (net->type) { case VIR_DOMAIN_NET_TYPE_NETWORK: case VIR_DOMAIN_NET_TYPE_BRIDGE: - if (virAsprintf(str, "%stap%cfd=%s,vlan=%d%s%s", - prefix ? prefix : "", + if (virAsprintf(str, "tap%cfd=%s,vlan=%d%s%s", type_sep, tapfd, vlan, (net->hostnet_name ? ",name=" : ""), (net->hostnet_name ? net->hostnet_name : "")) < 0) { @@ -1310,8 +1308,6 @@ qemuBuildHostNetStr(virConnectPtr conn, { virBuffer buf = VIR_BUFFER_INITIALIZER; - if (prefix) - virBufferAdd(&buf, prefix, strlen(prefix)); virBufferAddLit(&buf, "tap"); if (net->ifname) { virBufferVSprintf(&buf, "%cifname=%s", type_sep, net->ifname); @@ -1355,8 +1351,7 @@ qemuBuildHostNetStr(virConnectPtr conn, break; } - if (virAsprintf(str, "%ssocket%c%s=%s:%d,vlan=%d%s%s", - prefix ? prefix : "", + if (virAsprintf(str, "socket%c%s=%s:%d,vlan=%d%s%s", type_sep, mode, net->data.socket.address, net->data.socket.port, @@ -1371,8 +1366,7 @@ qemuBuildHostNetStr(virConnectPtr conn, case VIR_DOMAIN_NET_TYPE_USER: default: - if (virAsprintf(str, "%suser%cvlan=%d%s%s", - prefix ? prefix : "", + if (virAsprintf(str, "user%cvlan=%d%s%s", type_sep, vlan, (net->hostnet_name ? ",name=" : ""), (net->hostnet_name ? net->hostnet_name : "")) < 0) { @@ -2014,7 +2008,7 @@ int qemudBuildCommandLine(virConnectPtr conn, goto no_memory; } - if (qemuBuildHostNetStr(conn, net, NULL, ',', + if (qemuBuildHostNetStr(conn, net, ',', net->vlan, tapfd_name, &host) < 0) { VIR_FREE(tapfd_name); goto error; diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index 6ff5f0d..96b7c0c 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -170,7 +170,6 @@ int qemudBuildCommandLine (virConnectPtr conn, int qemuBuildHostNetStr (virConnectPtr conn, virDomainNetDefPtr net, - const char *prefix, char type_sep, int vlan, const char *tapfd, diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 6363edc..dfd5359 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4556,6 +4556,7 @@ static int qemudDomainAttachNetDevice(virConnectPtr conn, char *tapfd_name = NULL; int i, tapfd = -1; char *nicstr = NULL; + char *netstr = NULL; if (!(qemuCmdFlags & QEMUD_CMD_FLAG_HOST_NET_ADD)) { qemudReportError(conn, dom, NULL, VIR_ERR_NO_SUPPORT, "%s", @@ -4600,8 +4601,8 @@ static int qemudDomainAttachNetDevice(virConnectPtr conn, goto cleanup; } - if (qemuBuildHostNetStr(conn, net, "host_net_add ", ' ', - net->vlan, tapfd_name, &cmd) < 0) + if (qemuBuildHostNetStr(conn, net, ' ', + net->vlan, tapfd_name, &netstr) < 0) goto try_tapfd_close; remove_cmd = NULL; @@ -4612,16 +4613,9 @@ static int qemudDomainAttachNetDevice(virConnectPtr conn, goto try_tapfd_close; } - if (qemudMonitorCommand(vm, cmd, &reply) < 0) { - qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - _("failed to add network backend with '%s'"), cmd); + if (qemuMonitorAddHostNetwork(vm, netstr) < 0) goto try_tapfd_close; - } - - DEBUG("%s: host_net_add reply: %s", vm->def->name, reply); - VIR_FREE(reply); - VIR_FREE(cmd); VIR_FREE(tapfd_name); if (tapfd != -1) close(tapfd); @@ -4636,6 +4630,7 @@ static int qemudDomainAttachNetDevice(virConnectPtr conn, &net->pci_addr.slot) < 0) goto try_remove; + VIR_FREE(netstr); VIR_FREE(nicstr); VIR_FREE(remove_cmd); @@ -4667,6 +4662,7 @@ no_memory: virReportOOMError(conn); cleanup: VIR_FREE(nicstr); + VIR_FREE(netstr); VIR_FREE(cmd); VIR_FREE(reply); VIR_FREE(remove_cmd); diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index c6ffd33..5bff427 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -1665,3 +1665,33 @@ cleanup: return ret; } + +int qemuMonitorAddHostNetwork(const virDomainObjPtr vm, + const char *netstr) +{ + char *cmd; + char *reply = NULL; + int ret = -1; + + if (virAsprintf(&cmd, "host_net_add %s", netstr) < 0) { + virReportOOMError(NULL); + return -1; + } + + if (qemudMonitorCommand(vm, cmd, &reply) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + _("failed to close fd in qemu with '%s'"), cmd); + goto cleanup; + } + + DEBUG("%s: host_net_add reply: %s", vm->def->name, reply); + + /* XXX error messages here ? */ + + ret = 0; + +cleanup: + VIR_FREE(cmd); + VIR_FREE(reply); + return ret; +} diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index 1bd9d6d..d97baaf 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -192,4 +192,11 @@ int qemuMonitorSendFileHandle(const virDomainObjPtr vm, int qemuMonitorCloseFileHandle(const virDomainObjPtr vm, const char *fdname); + +/* XXX do we relaly want to hardcode 'netstr' as the + * sendable item here + */ +int qemuMonitorAddHostNetwork(const virDomainObjPtr vm, + const char *netstr); + #endif /* QEMU_MONITOR_TEXT_H */ -- 1.6.2.5

On Thu, 2009-09-24 at 16:00 +0100, Daniel P. Berrange wrote:
* src/qemu/qemu_conf.h, src/qemu/qemu_conf.c: Remove prefix arg from qemuBuildHostNetStr which is no longer required * src/qemu/qemu_driver.c: Refactor to use qemuMonitorAddHostNetwork() API for adding host network * src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add new qemuMonitorAddHostNetwork() method for adding host networks --- src/qemu/qemu_conf.c | 14 ++++---------- src/qemu/qemu_conf.h | 1 - src/qemu/qemu_driver.c | 16 ++++++---------- src/qemu/qemu_monitor_text.c | 30 ++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 7 +++++++ 5 files changed, 47 insertions(+), 21 deletions(-)
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index c531454..1d98637 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -1287,7 +1287,6 @@ qemuBuildNicStr(virConnectPtr conn, int qemuBuildHostNetStr(virConnectPtr conn, virDomainNetDefPtr net, - const char *prefix, char type_sep, int vlan, const char *tapfd,
Funny that you removed the prefix arg in this patch, but the type_sep arg in the previous patch. I see why, though ACK Cheers, Mark.

* src/qemu/qemu_monitor.h, src/qemu/qemu_monitor.c: Add new qemuMonitorRemoveHostNetwork() command for removing host networks * src/qemu/qemu_driver.c: Convert NIC hotplug methods over to use qemuMonitorRemoveHostNetwork() --- src/qemu/qemu_driver.c | 65 ++++++++++------------------------------- src/qemu/qemu_monitor_text.c | 32 ++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 4 ++ 3 files changed, 52 insertions(+), 49 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index dfd5359..da72913 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4552,11 +4552,11 @@ static int qemudDomainAttachNetDevice(virConnectPtr conn, unsigned int qemuCmdFlags) { virDomainNetDefPtr net = dev->data.net; - char *cmd = NULL, *reply = NULL, *remove_cmd = NULL; char *tapfd_name = NULL; int i, tapfd = -1; char *nicstr = NULL; char *netstr = NULL; + int ret = -1; if (!(qemuCmdFlags & QEMUD_CMD_FLAG_HOST_NET_ADD)) { qemudReportError(conn, dom, NULL, VIR_ERR_NO_SUPPORT, "%s", @@ -4605,18 +4605,9 @@ static int qemudDomainAttachNetDevice(virConnectPtr conn, net->vlan, tapfd_name, &netstr) < 0) goto try_tapfd_close; - remove_cmd = NULL; - if (net->vlan >= 0 && net->hostnet_name && - virAsprintf(&remove_cmd, "host_net_remove %d %s", - net->vlan, net->hostnet_name) < 0) { - virReportOOMError(conn); - goto try_tapfd_close; - } - if (qemuMonitorAddHostNetwork(vm, netstr) < 0) goto try_tapfd_close; - VIR_FREE(tapfd_name); if (tapfd != -1) close(tapfd); tapfd = -1; @@ -4630,28 +4621,28 @@ static int qemudDomainAttachNetDevice(virConnectPtr conn, &net->pci_addr.slot) < 0) goto try_remove; - VIR_FREE(netstr); - VIR_FREE(nicstr); - VIR_FREE(remove_cmd); + ret = 0; vm->def->nets[vm->def->nnets++] = net; - return 0; +cleanup: + VIR_FREE(nicstr); + VIR_FREE(netstr); + VIR_FREE(tapfd_name); + if (tapfd != -1) + close(tapfd); -try_remove: - VIR_FREE(reply); + return ret; - if (!remove_cmd) +try_remove: + if (!net->hostnet_name || net->vlan == 0) VIR_WARN0(_("Unable to remove network backend\n")); - else if (qemudMonitorCommand(vm, remove_cmd, &reply) < 0) - VIR_WARN(_("Failed to remove network backend with '%s'\n"), remove_cmd); - else - VIR_DEBUG("%s: host_net_remove reply: %s\n", vm->def->name, reply); + else if (qemuMonitorRemoveHostNetwork(vm, net->vlan, net->hostnet_name) < 0) + VIR_WARN(_("Failed to remove network backend for vlan %d, net %s"), + net->vlan, net->hostnet_name); goto cleanup; try_tapfd_close: - VIR_FREE(reply); - if (tapfd_name && qemuMonitorCloseFileHandle(vm, tapfd_name) < 0) VIR_WARN(_("Failed to close tapfd with '%s'\n"), tapfd_name); @@ -4660,16 +4651,7 @@ try_tapfd_close: no_memory: virReportOOMError(conn); -cleanup: - VIR_FREE(nicstr); - VIR_FREE(netstr); - VIR_FREE(cmd); - VIR_FREE(reply); - VIR_FREE(remove_cmd); - VIR_FREE(tapfd_name); - if (tapfd != -1) - close(tapfd); - return -1; + goto cleanup; } static int qemudDomainAttachHostPciDevice(virConnectPtr conn, @@ -4968,8 +4950,6 @@ qemudDomainDetachNetDevice(virConnectPtr conn, virDomainDeviceDefPtr dev) { int i, ret = -1; - char *cmd = NULL; - char *reply = NULL; virDomainNetDefPtr detach = NULL; for (i = 0 ; i < vm->def->nnets ; i++) { @@ -5002,19 +4982,8 @@ qemudDomainDetachNetDevice(virConnectPtr conn, detach->pci_addr.slot) < 0) goto cleanup; - if (virAsprintf(&cmd, "host_net_remove %d %s", - detach->vlan, detach->hostnet_name) < 0) { - virReportOOMError(conn); + if (qemuMonitorRemoveHostNetwork(vm, detach->vlan, detach->hostnet_name) < 0) goto cleanup; - } - - if (qemudMonitorCommand(vm, cmd, &reply) < 0) { - qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED, - _("network device dettach command '%s' failed"), cmd); - goto cleanup; - } - - DEBUG("%s: host_net_remove reply: %s", vm->def->name, reply); if (vm->def->nnets > 1) { memmove(vm->def->nets + i, @@ -5034,8 +5003,6 @@ qemudDomainDetachNetDevice(virConnectPtr conn, ret = 0; cleanup: - VIR_FREE(reply); - VIR_FREE(cmd); return ret; } diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 5bff427..0675bf5 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -1695,3 +1695,35 @@ cleanup: VIR_FREE(reply); return ret; } + + +int qemuMonitorRemoveHostNetwork(const virDomainObjPtr vm, + int vlan, + const char *netname) +{ + char *cmd; + char *reply = NULL; + int ret = -1; + + if (virAsprintf(&cmd, "host_net_remove %d %s", vlan, netname) < 0) { + virReportOOMError(NULL); + return -1; + } + + if (qemudMonitorCommand(vm, cmd, &reply) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + _("failed to close fd in qemu with '%s'"), cmd); + goto cleanup; + } + + DEBUG("%s: host_net_add reply: %s", vm->def->name, reply); + + /* XXX error messages here ? */ + + ret = 0; + +cleanup: + VIR_FREE(cmd); + VIR_FREE(reply); + return ret; +} diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index d97baaf..2c8cfda 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -199,4 +199,8 @@ int qemuMonitorCloseFileHandle(const virDomainObjPtr vm, int qemuMonitorAddHostNetwork(const virDomainObjPtr vm, const char *netstr); +int qemuMonitorRemoveHostNetwork(const virDomainObjPtr vm, + int vlan, + const char *netname); + #endif /* QEMU_MONITOR_TEXT_H */ -- 1.6.2.5

On Thu, 2009-09-24 at 16:00 +0100, Daniel P. Berrange wrote:
* src/qemu/qemu_monitor.h, src/qemu/qemu_monitor.c: Add new qemuMonitorRemoveHostNetwork() command for removing host networks * src/qemu/qemu_driver.c: Convert NIC hotplug methods over to use qemuMonitorRemoveHostNetwork() --- src/qemu/qemu_driver.c | 65 ++++++++++------------------------------- src/qemu/qemu_monitor_text.c | 32 ++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 4 ++ 3 files changed, 52 insertions(+), 49 deletions(-)
...
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 5bff427..0675bf5 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -1695,3 +1695,35 @@ cleanup: VIR_FREE(reply); return ret; } + + +int qemuMonitorRemoveHostNetwork(const virDomainObjPtr vm, + int vlan, + const char *netname) +{ + char *cmd; + char *reply = NULL; + int ret = -1; + + if (virAsprintf(&cmd, "host_net_remove %d %s", vlan, netname) < 0) { + virReportOOMError(NULL); + return -1; + } + + if (qemudMonitorCommand(vm, cmd, &reply) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + _("failed to close fd in qemu with '%s'"), cmd); + goto cleanup; + }
Wrong error
+ + DEBUG("%s: host_net_add reply: %s", vm->def->name, reply);
Wrong debug Otherwise fine, ACK Cheers, Mark.

* src/qemu/qemu_monitor.h: Remove qemudMonitorCommand, qemudMonitorCommandWithFd, qemudMonitorCommandWithHandler, qemudMonitorCommandExtra low level APIs * src/qemu/qemu_monitor.c: Replace s/qemud/qemuMonitor/ --- src/qemu/qemu_monitor_text.c | 166 ++++++++++++++++++++++-------------------- src/qemu/qemu_monitor_text.h | 33 -------- 2 files changed, 88 insertions(+), 111 deletions(-) diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 0675bf5..2c41288 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -41,7 +41,17 @@ #define VIR_FROM_THIS VIR_FROM_QEMU -static char *qemudEscape(const char *in, int shell) +#define QEMU_CMD_PROMPT "\n(qemu) " +#define QEMU_PASSWD_PROMPT "Password: " + +/* Return -1 for error, 0 for success */ +typedef int qemuMonitorExtraPromptHandler(const virDomainObjPtr vm, + const char *buf, + const char *prompt, + void *data); + + +static char *qemuMonitorEscape(const char *in, int shell) { int len = 0; int i, j; @@ -113,14 +123,14 @@ static char *qemudEscape(const char *in, int shell) return out; } -static char *qemudEscapeMonitorArg(const char *in) +static char *qemuMonitorEscapeArg(const char *in) { - return qemudEscape(in, 0); + return qemuMonitorEscape(in, 0); } -static char *qemudEscapeShellArg(const char *in) +static char *qemuMonitorEscapeShell(const char *in) { - return qemudEscape(in, 1); + return qemuMonitorEscape(in, 1); } /* Throw away any data available on the monitor @@ -144,10 +154,10 @@ qemuMonitorDiscardPendingData(virDomainObjPtr vm) { } static int -qemudMonitorSendUnix(const virDomainObjPtr vm, - const char *cmd, - size_t cmdlen, - int scm_fd) +qemuMonitorSendUnix(const virDomainObjPtr vm, + const char *cmd, + size_t cmdlen, + int scm_fd) { struct msghdr msg; struct iovec iov[1]; @@ -183,9 +193,9 @@ qemudMonitorSendUnix(const virDomainObjPtr vm, } static int -qemudMonitorSend(const virDomainObjPtr vm, - const char *cmd, - int scm_fd) +qemuMonitorSend(const virDomainObjPtr vm, + const char *cmd, + int scm_fd) { char *full; size_t len; @@ -198,7 +208,7 @@ qemudMonitorSend(const virDomainObjPtr vm, switch (vm->monitor_chr->type) { case VIR_DOMAIN_CHR_TYPE_UNIX: - if (qemudMonitorSendUnix(vm, full, len, scm_fd) < 0) + if (qemuMonitorSendUnix(vm, full, len, scm_fd) < 0) goto out; break; default: @@ -214,14 +224,14 @@ out: return ret; } -int -qemudMonitorCommandWithHandler(const virDomainObjPtr vm, - const char *cmd, - const char *extraPrompt, - qemudMonitorExtraPromptHandler extraHandler, - void *handlerData, - int scm_fd, - char **reply) { +static int +qemuMonitorCommandWithHandler(const virDomainObjPtr vm, + const char *cmd, + const char *extraPrompt, + qemuMonitorExtraPromptHandler extraHandler, + void *handlerData, + int scm_fd, + char **reply) { int size = 0; char *buf = NULL; @@ -233,7 +243,7 @@ qemudMonitorCommandWithHandler(const virDomainObjPtr vm, qemuMonitorDiscardPendingData(vm); VIR_DEBUG("Send '%s'", cmd); - if (qemudMonitorSend(vm, cmd, scm_fd) < 0) + if (qemuMonitorSend(vm, cmd, scm_fd) < 0) return -1; *reply = NULL; @@ -324,23 +334,23 @@ struct extraHandlerData }; static int -qemudMonitorCommandSimpleExtraHandler(const virDomainObjPtr vm, - const char *buf ATTRIBUTE_UNUSED, - const char *prompt ATTRIBUTE_UNUSED, - void *data_) +qemuMonitorCommandSimpleExtraHandler(const virDomainObjPtr vm, + const char *buf ATTRIBUTE_UNUSED, + const char *prompt ATTRIBUTE_UNUSED, + void *data_) { struct extraHandlerData *data = data_; if (!data->first) return 0; - if (qemudMonitorSend(vm, data->reply, -1) < 0) + if (qemuMonitorSend(vm, data->reply, -1) < 0) return -1; data->first = false; return 0; } -int -qemudMonitorCommandExtra(const virDomainObjPtr vm, +static int +qemuMonitorCommandExtra(const virDomainObjPtr vm, const char *cmd, const char *extra, const char *extraPrompt, @@ -350,24 +360,24 @@ qemudMonitorCommandExtra(const virDomainObjPtr vm, data.reply = extra; data.first = true; - return qemudMonitorCommandWithHandler(vm, cmd, extraPrompt, - qemudMonitorCommandSimpleExtraHandler, - &data, scm_fd, reply); + return qemuMonitorCommandWithHandler(vm, cmd, extraPrompt, + qemuMonitorCommandSimpleExtraHandler, + &data, scm_fd, reply); } -int -qemudMonitorCommandWithFd(const virDomainObjPtr vm, +static int +qemuMonitorCommandWithFd(const virDomainObjPtr vm, const char *cmd, int scm_fd, char **reply) { - return qemudMonitorCommandExtra(vm, cmd, NULL, NULL, scm_fd, reply); + return qemuMonitorCommandExtra(vm, cmd, NULL, NULL, scm_fd, reply); } -int -qemudMonitorCommand(const virDomainObjPtr vm, +static int +qemuMonitorCommand(const virDomainObjPtr vm, const char *cmd, char **reply) { - return qemudMonitorCommandWithFd(vm, cmd, -1, reply); + return qemuMonitorCommandWithFd(vm, cmd, -1, reply); } @@ -467,10 +477,10 @@ findVolumeQcowPassphrase(virConnectPtr conn, virDomainObjPtr vm, } static int -qemudMonitorSendVolumePassphrase(const virDomainObjPtr vm, - const char *buf, - const char *prompt, - void *data) +qemuMonitorSendVolumePassphrase(const virDomainObjPtr vm, + const char *buf, + const char *prompt, + void *data) { virConnectPtr conn = data; char *passphrase, *path; @@ -498,7 +508,7 @@ qemudMonitorSendVolumePassphrase(const virDomainObjPtr vm, if (passphrase == NULL) return -1; - res = qemudMonitorSend(vm, passphrase, -1); + res = qemuMonitorSend(vm, passphrase, -1); memset(passphrase, 0, passphrase_len); VIR_FREE(passphrase); @@ -511,9 +521,9 @@ qemuMonitorStartCPUs(virConnectPtr conn, const virDomainObjPtr vm) { char *reply; - if (qemudMonitorCommandWithHandler(vm, "cont", ") is encrypted.", - qemudMonitorSendVolumePassphrase, conn, - -1, &reply) < 0) + if (qemuMonitorCommandWithHandler(vm, "cont", ") is encrypted.", + qemuMonitorSendVolumePassphrase, conn, + -1, &reply) < 0) return -1; qemudDebug ("%s: cont reply: %s", vm->def->name, info); VIR_FREE(reply); @@ -525,7 +535,7 @@ int qemuMonitorStopCPUs(const virDomainObjPtr vm) { char *info; - if (qemudMonitorCommand(vm, "stop", &info) < 0) { + if (qemuMonitorCommand(vm, "stop", &info) < 0) { qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, "%s", _("cannot stop CPU execution")); return -1; @@ -538,7 +548,7 @@ qemuMonitorStopCPUs(const virDomainObjPtr vm) { int qemuMonitorSystemPowerdown(const virDomainObjPtr vm) { char *info; - if (qemudMonitorCommand(vm, "system_powerdown", &info) < 0) { + if (qemuMonitorCommand(vm, "system_powerdown", &info) < 0) { qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, "%s", _("system shutdown operation failed")); return -1; @@ -557,7 +567,7 @@ int qemuMonitorGetCPUInfo(const virDomainObjPtr vm, pid_t *cpupids = NULL; size_t ncpupids = 0; - if (qemudMonitorCommand(vm, "info cpus", &qemucpus) < 0) { + if (qemuMonitorCommand(vm, "info cpus", &qemucpus) < 0) { qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s", _("cannot run monitor command to fetch CPU thread info")); return -1; @@ -645,7 +655,7 @@ int qemuMonitorGetBalloonInfo(const virDomainObjPtr vm, int ret = -1; char *offset; - if (qemudMonitorCommand(vm, "info balloon", &reply) < 0) { + if (qemuMonitorCommand(vm, "info balloon", &reply) < 0) { qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, "%s", _("could not query memory balloon allocation")); return -1; @@ -690,7 +700,7 @@ int qemuMonitorGetBlockStatsInfo(const virDomainObjPtr vm, const char *p, *eol; int devnamelen = strlen(devname); - if (qemudMonitorCommand (vm, "info blockstats", &info) < 0) { + if (qemuMonitorCommand (vm, "info blockstats", &info) < 0) { qemudReportError (NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, "%s", _("'info blockstats' command failed")); goto cleanup; @@ -785,10 +795,10 @@ int qemuMonitorSetVNCPassword(const virDomainObjPtr vm, const char *password) { char *info = NULL; - if (qemudMonitorCommandExtra(vm, "change vnc password", - password, - QEMU_PASSWD_PROMPT, - -1, &info) < 0) { + if (qemuMonitorCommandExtra(vm, "change vnc password", + password, + QEMU_PASSWD_PROMPT, + -1, &info) < 0) { qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s", _("setting VNC password failed")); return -1; @@ -817,7 +827,7 @@ int qemuMonitorSetBalloon(const virDomainObjPtr vm, return -1; } - if (qemudMonitorCommand(vm, cmd, &reply) < 0) { + if (qemuMonitorCommand(vm, cmd, &reply) < 0) { qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, "%s", _("could not balloon memory allocation")); VIR_FREE(cmd); @@ -851,7 +861,7 @@ int qemuMonitorEjectMedia(const virDomainObjPtr vm, goto cleanup; } - if (qemudMonitorCommand(vm, cmd, &reply) < 0) { + if (qemuMonitorCommand(vm, cmd, &reply) < 0) { qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, _("could not eject media on %s"), devname); goto cleanup; @@ -885,7 +895,7 @@ int qemuMonitorChangeMedia(const virDomainObjPtr vm, char *safepath = NULL; int ret = -1; - if (!(safepath = qemudEscapeMonitorArg(newmedia))) { + if (!(safepath = qemuMonitorEscapeArg(newmedia))) { virReportOOMError(NULL); goto cleanup; } @@ -895,7 +905,7 @@ int qemuMonitorChangeMedia(const virDomainObjPtr vm, goto cleanup; } - if (qemudMonitorCommand(vm, cmd, &reply) < 0) { + if (qemuMonitorCommand(vm, cmd, &reply) < 0) { qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, _("could not eject media on %s"), devname); goto cleanup; @@ -931,7 +941,7 @@ static int qemuMonitorSaveMemory(const virDomainObjPtr vm, char *safepath = NULL; int ret = -1; - if (!(safepath = qemudEscapeMonitorArg(path))) { + if (!(safepath = qemuMonitorEscapeArg(path))) { virReportOOMError(NULL); goto cleanup; } @@ -941,7 +951,7 @@ static int qemuMonitorSaveMemory(const virDomainObjPtr vm, goto cleanup; } - if (qemudMonitorCommand(vm, cmd, &reply) < 0) { + if (qemuMonitorCommand(vm, cmd, &reply) < 0) { qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, _("could save memory region to '%s'"), path); goto cleanup; @@ -988,7 +998,7 @@ int qemuMonitorSetMigrationSpeed(const virDomainObjPtr vm, goto cleanup; } - if (qemudMonitorCommand (vm, cmd, &info) < 0) { + if (qemuMonitorCommand (vm, cmd, &info) < 0) { qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, "%s", _("could restrict migration speed")); goto cleanup; @@ -1029,7 +1039,7 @@ int qemuMonitorGetMigrationStatus(const virDomainObjPtr vm, *remaining = 0; *total = 0; - if (qemudMonitorCommand(vm, "info migration", &reply) < 0) { + if (qemuMonitorCommand(vm, "info migration", &reply) < 0) { qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, "%s", _("cannot query migration status")); return -1; @@ -1100,7 +1110,7 @@ static int qemuMonitorMigrate(const virDomainObjPtr vm, char *cmd = NULL; char *info = NULL; int ret = -1; - char *safedest = qemudEscapeMonitorArg(dest); + char *safedest = qemuMonitorEscapeArg(dest); if (!safedest) { virReportOOMError(NULL); @@ -1112,7 +1122,7 @@ static int qemuMonitorMigrate(const virDomainObjPtr vm, goto cleanup; } - if (qemudMonitorCommand(vm, cmd, &info) < 0) { + if (qemuMonitorCommand(vm, cmd, &info) < 0) { qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("unable to start migration to %s"), dest); goto cleanup; @@ -1180,7 +1190,7 @@ int qemuMonitorMigrateToCommand(const virDomainObjPtr vm, } /* Migrate to file */ - safe_target = qemudEscapeShellArg(target); + safe_target = qemuMonitorEscapeShell(target); if (!safe_target) { virReportOOMError(NULL); goto cleanup; @@ -1209,7 +1219,7 @@ int qemuMonitorAddUSBDisk(const virDomainObjPtr vm, int ret = -1; char *info = NULL; - safepath = qemudEscapeMonitorArg(path); + safepath = qemuMonitorEscapeArg(path); if (!safepath) { virReportOOMError(NULL); return -1; @@ -1220,7 +1230,7 @@ int qemuMonitorAddUSBDisk(const virDomainObjPtr vm, goto cleanup; } - if (qemudMonitorCommand(vm, cmd, &info) < 0) { + if (qemuMonitorCommand(vm, cmd, &info) < 0) { qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s", _("cannot run monitor command to add usb disk")); goto cleanup; @@ -1256,7 +1266,7 @@ static int qemuMonitorAddUSBDevice(const virDomainObjPtr vm, return -1; } - if (qemudMonitorCommand(vm, cmd, &reply) < 0) { + if (qemuMonitorCommand(vm, cmd, &reply) < 0) { qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, "%s", _("cannot attach usb device")); goto cleanup; @@ -1407,7 +1417,7 @@ int qemuMonitorAddPCIHostDevice(const virDomainObjPtr vm, goto cleanup; } - if (qemudMonitorCommand(vm, cmd, &reply) < 0) { + if (qemuMonitorCommand(vm, cmd, &reply) < 0) { qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, "%s", _("cannot attach host pci device")); goto cleanup; @@ -1449,7 +1459,7 @@ int qemuMonitorAddPCIDisk(const virDomainObjPtr vm, int tryOldSyntax = 0; int ret = -1; - safe_path = qemudEscapeMonitorArg(path); + safe_path = qemuMonitorEscapeArg(path); if (!safe_path) { virReportOOMError(NULL); return -1; @@ -1462,7 +1472,7 @@ try_command: goto cleanup; } - if (qemudMonitorCommand(vm, cmd, &reply) < 0) { + if (qemuMonitorCommand(vm, cmd, &reply) < 0) { qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, _("cannot attach %s disk %s"), bus, path); goto cleanup; @@ -1506,7 +1516,7 @@ int qemuMonitorAddPCINetwork(const virDomainObjPtr vm, return -1; } - if (qemudMonitorCommand(vm, cmd, &reply) < 0) { + if (qemuMonitorCommand(vm, cmd, &reply) < 0) { qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, _("failed to add NIC with '%s'"), cmd); goto cleanup; @@ -1552,7 +1562,7 @@ try_command: } } - if (qemudMonitorCommand(vm, cmd, &reply) < 0) { + if (qemuMonitorCommand(vm, cmd, &reply) < 0) { qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, "%s", _("failed to remove PCI device")); goto cleanup; @@ -1602,7 +1612,7 @@ int qemuMonitorSendFileHandle(const virDomainObjPtr vm, return -1; } - if (qemudMonitorCommandWithFd(vm, cmd, fd, &reply) < 0) { + if (qemuMonitorCommandWithFd(vm, cmd, fd, &reply) < 0) { qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, _("failed to pass fd to qemu with '%s'"), cmd); goto cleanup; @@ -1640,7 +1650,7 @@ int qemuMonitorCloseFileHandle(const virDomainObjPtr vm, return -1; } - if (qemudMonitorCommand(vm, cmd, &reply) < 0) { + if (qemuMonitorCommand(vm, cmd, &reply) < 0) { qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, _("failed to close fd in qemu with '%s'"), cmd); goto cleanup; @@ -1678,7 +1688,7 @@ int qemuMonitorAddHostNetwork(const virDomainObjPtr vm, return -1; } - if (qemudMonitorCommand(vm, cmd, &reply) < 0) { + if (qemuMonitorCommand(vm, cmd, &reply) < 0) { qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, _("failed to close fd in qemu with '%s'"), cmd); goto cleanup; @@ -1710,7 +1720,7 @@ int qemuMonitorRemoveHostNetwork(const virDomainObjPtr vm, return -1; } - if (qemudMonitorCommand(vm, cmd, &reply) < 0) { + if (qemuMonitorCommand(vm, cmd, &reply) < 0) { qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, _("failed to close fd in qemu with '%s'"), cmd); goto cleanup; diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index 2c8cfda..25e43d4 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -29,39 +29,6 @@ #include "domain_conf.h" -/* XXX remove these two from public header */ -#define QEMU_CMD_PROMPT "\n(qemu) " -#define QEMU_PASSWD_PROMPT "Password: " - -/* Return -1 for error, 0 for success */ -typedef int qemudMonitorExtraPromptHandler(const virDomainObjPtr vm, - const char *buf, - const char *prompt, - void *data); - -/* These first 4 APIs are generic monitor interaction. They will - * go away eventually - */ -int qemudMonitorCommand(const virDomainObjPtr vm, - const char *cmd, - char **reply); -int qemudMonitorCommandWithFd(const virDomainObjPtr vm, - const char *cmd, - int scm_fd, - char **reply); -int qemudMonitorCommandWithHandler(const virDomainObjPtr vm, - const char *cmd, - const char *extraPrompt, - qemudMonitorExtraPromptHandler extraHandler, - void *handlerData, - int scm_fd, - char **reply); -int qemudMonitorCommandExtra(const virDomainObjPtr vm, - const char *cmd, - const char *extra, - const char *extraPrompt, - int scm_fd, - char **reply); /* Formal APIs for each required monitor command */ -- 1.6.2.5

On Thu, 2009-09-24 at 16:00 +0100, Daniel P. Berrange wrote:
* src/qemu/qemu_monitor.h: Remove qemudMonitorCommand, qemudMonitorCommandWithFd, qemudMonitorCommandWithHandler, qemudMonitorCommandExtra low level APIs * src/qemu/qemu_monitor.c: Replace s/qemud/qemuMonitor/ --- src/qemu/qemu_monitor_text.c | 166 ++++++++++++++++++++++-------------------- src/qemu/qemu_monitor_text.h | 33 -------- 2 files changed, 88 insertions(+), 111 deletions(-) ...
Just a bunch of cleanups, ACK Cheers, Mark.

* src/qemu/qemu_monitor_text.c: Always print command and reply in qemuMonitorCommandWithHandler. Print all args in each monitor command API & remove redundant relpy printing --- src/qemu/qemu_monitor_text.c | 82 ++++++++++++++++++++++++++++++----------- 1 files changed, 60 insertions(+), 22 deletions(-) diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 2c41288..abb2c0a 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -242,7 +242,7 @@ qemuMonitorCommandWithHandler(const virDomainObjPtr vm, qemuMonitorDiscardPendingData(vm); - VIR_DEBUG("Send '%s'", cmd); + VIR_DEBUG("cmd='%s' extraPrompt='%s'", cmd, NULLSTR(extraPrompt)); if (qemuMonitorSend(vm, cmd, scm_fd) < 0) return -1; @@ -282,6 +282,7 @@ qemuMonitorCommandWithHandler(const virDomainObjPtr vm, (foundPrompt = strstr(buf, extraPrompt)) != NULL) { char *promptEnd; + DEBUG("prompt='%s' handler=%p", extraPrompt, extraHandler); if (extraHandler(vm, buf, foundPrompt, handlerData) < 0) return -1; /* Discard output so far, necessary to detect whether @@ -320,6 +321,7 @@ qemuMonitorCommandWithHandler(const virDomainObjPtr vm, } } *reply = buf; + DEBUG("reply='%s'", buf); return 0; error: @@ -521,11 +523,13 @@ qemuMonitorStartCPUs(virConnectPtr conn, const virDomainObjPtr vm) { char *reply; + DEBUG("vm=%p, pid=%d, id=%d, name=%s", vm, vm->pid, vm->def->id, vm->def->name); + if (qemuMonitorCommandWithHandler(vm, "cont", ") is encrypted.", qemuMonitorSendVolumePassphrase, conn, -1, &reply) < 0) return -1; - qemudDebug ("%s: cont reply: %s", vm->def->name, info); + VIR_FREE(reply); return 0; } @@ -535,6 +539,8 @@ int qemuMonitorStopCPUs(const virDomainObjPtr vm) { char *info; + DEBUG("vm=%p, pid=%d, id=%d, name=%s", vm, vm->pid, vm->def->id, vm->def->name); + if (qemuMonitorCommand(vm, "stop", &info) < 0) { qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, "%s", _("cannot stop CPU execution")); @@ -548,6 +554,8 @@ qemuMonitorStopCPUs(const virDomainObjPtr vm) { int qemuMonitorSystemPowerdown(const virDomainObjPtr vm) { char *info; + DEBUG("vm=%p, pid=%d, id=%d, name=%s", vm, vm->pid, vm->def->id, vm->def->name); + if (qemuMonitorCommand(vm, "system_powerdown", &info) < 0) { qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, "%s", _("system shutdown operation failed")); @@ -567,6 +575,8 @@ int qemuMonitorGetCPUInfo(const virDomainObjPtr vm, pid_t *cpupids = NULL; size_t ncpupids = 0; + DEBUG("vm=%p, pid=%d, id=%d, name=%s", vm, vm->pid, vm->def->id, vm->def->name); + if (qemuMonitorCommand(vm, "info cpus", &qemucpus) < 0) { qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s", _("cannot run monitor command to fetch CPU thread info")); @@ -614,6 +624,7 @@ int qemuMonitorGetCPUInfo(const virDomainObjPtr vm, if (VIR_REALLOC_N(cpupids, ncpupids+1) < 0) goto error; + DEBUG("vcpu=%d pid=%d", vcpu, tid); cpupids[ncpupids++] = tid; lastVcpu = vcpu; @@ -655,13 +666,14 @@ int qemuMonitorGetBalloonInfo(const virDomainObjPtr vm, int ret = -1; char *offset; + DEBUG("vm=%p, pid=%d, id=%d, name=%s", vm, vm->pid, vm->def->id, vm->def->name); + if (qemuMonitorCommand(vm, "info balloon", &reply) < 0) { qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, "%s", _("could not query memory balloon allocation")); return -1; } - DEBUG ("%s: balloon reply: '%s'", vm->def->name, reply); if ((offset = strstr(reply, BALLOON_PREFIX)) != NULL) { unsigned int memMB; char *end; @@ -700,12 +712,13 @@ int qemuMonitorGetBlockStatsInfo(const virDomainObjPtr vm, const char *p, *eol; int devnamelen = strlen(devname); + DEBUG("vm=%p, pid=%d, id=%d, name=%s dev=%s", vm, vm->pid, vm->def->id, vm->def->name, devname); + if (qemuMonitorCommand (vm, "info blockstats", &info) < 0) { qemudReportError (NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, "%s", _("'info blockstats' command failed")); goto cleanup; } - DEBUG ("%s: info blockstats reply: %s", vm->def->name, info); /* If the command isn't supported then qemu prints the supported * info commands, so the output starts "info ". Since this is @@ -795,6 +808,9 @@ int qemuMonitorSetVNCPassword(const virDomainObjPtr vm, const char *password) { char *info = NULL; + + DEBUG("vm=%p, pid=%d, id=%d, name=%s", vm, vm->pid, vm->def->id, vm->def->name); + if (qemuMonitorCommandExtra(vm, "change vnc password", password, QEMU_PASSWD_PROMPT, @@ -818,6 +834,8 @@ int qemuMonitorSetBalloon(const virDomainObjPtr vm, char *reply = NULL; int ret = -1; + DEBUG("vm=%p, pid=%d, id=%d, name=%s newmem=%lu", vm, vm->pid, vm->def->id, vm->def->name, newmem); + /* * 'newmem' is in KB, QEMU monitor works in MB, and we all wish * we just worked in bytes with unsigned long long everywhere. @@ -837,7 +855,6 @@ int qemuMonitorSetBalloon(const virDomainObjPtr vm, /* If the command failed qemu prints: 'unknown command' * No message is printed on success it seems */ - DEBUG ("%s: balloon reply: %s", vm->def->name, reply); if (strstr(reply, "\nunknown command:")) { /* Don't set error - it is expected memory balloon fails on many qemu */ ret = 0; @@ -856,6 +873,8 @@ int qemuMonitorEjectMedia(const virDomainObjPtr vm, char *reply = NULL; int ret = -1; + DEBUG("vm=%p, pid=%d, id=%d, name=%s devname=%s", vm, vm->pid, vm->def->id, vm->def->name, devname); + if (virAsprintf(&cmd, "eject %s", devname) < 0) { virReportOOMError(NULL); goto cleanup; @@ -870,7 +889,6 @@ int qemuMonitorEjectMedia(const virDomainObjPtr vm, /* If the command failed qemu prints: * device not found, device is locked ... * No message is printed on success it seems */ - DEBUG ("%s: ejectable media change reply: %s", vm->def->name, reply); if (strstr(reply, "\ndevice ")) { qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, _("could not eject media on %s: %s"), devname, reply); @@ -895,6 +913,8 @@ int qemuMonitorChangeMedia(const virDomainObjPtr vm, char *safepath = NULL; int ret = -1; + DEBUG("vm=%p, pid=%d, id=%d, name=%s devname=%s newmedia=%s", vm, vm->pid, vm->def->id, vm->def->name, devname, newmedia); + if (!(safepath = qemuMonitorEscapeArg(newmedia))) { virReportOOMError(NULL); goto cleanup; @@ -914,7 +934,6 @@ int qemuMonitorChangeMedia(const virDomainObjPtr vm, /* If the command failed qemu prints: * device not found, device is locked ... * No message is printed on success it seems */ - DEBUG ("%s: ejectable media change reply: %s", vm->def->name, reply); if (strstr(reply, "\ndevice ")) { qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, _("could not eject media on %s: %s"), devname, reply); @@ -974,6 +993,8 @@ int qemuMonitorSaveVirtualMemory(const virDomainObjPtr vm, size_t length, const char *path) { + DEBUG("vm=%p, pid=%d, id=%d, name=%s offset=%llu length=%zu path=%s", vm, vm->pid, vm->def->id, vm->def->name, offset, length, path); + return qemuMonitorSaveMemory(vm, "memsave", offset, length, path); } @@ -982,6 +1003,8 @@ int qemuMonitorSavePhysicalMemory(const virDomainObjPtr vm, size_t length, const char *path) { + DEBUG("vm=%p, pid=%d, id=%d, name=%s offset=%llu length=%zu path=%s", vm, vm->pid, vm->def->id, vm->def->name, offset, length, path); + return qemuMonitorSaveMemory(vm, "pmemsave", offset, length, path); } @@ -993,6 +1016,8 @@ int qemuMonitorSetMigrationSpeed(const virDomainObjPtr vm, char *info = NULL; int ret = -1; + DEBUG("vm=%p, pid=%d, id=%d, name=%s bandwidth=%lu", vm, vm->pid, vm->def->id, vm->def->name, bandwidth); + if (virAsprintf(&cmd, "migrate_set_speed %lum", bandwidth) < 0) { virReportOOMError(NULL); goto cleanup; @@ -1004,7 +1029,6 @@ int qemuMonitorSetMigrationSpeed(const virDomainObjPtr vm, goto cleanup; } - DEBUG ("%s: migrate_set_speed reply: %s", vm->def->name, info); ret = 0; cleanup: @@ -1034,6 +1058,8 @@ int qemuMonitorGetMigrationStatus(const virDomainObjPtr vm, char *end; int ret = -1; + DEBUG("vm=%p, pid=%d, id=%d, name=%s", vm, vm->pid, vm->def->id, vm->def->name); + *status = QEMU_MONITOR_MIGRATION_STATUS_INACTIVE; *transferred = 0; *remaining = 0; @@ -1128,8 +1154,6 @@ static int qemuMonitorMigrate(const virDomainObjPtr vm, goto cleanup; } - DEBUG ("%s: migrate reply: %s", vm->def->name, info); - /* Now check for "fail" in the output string */ if (strstr(info, "fail") != NULL) { qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, @@ -1161,6 +1185,8 @@ int qemuMonitorMigrateToHost(const virDomainObjPtr vm, char *uri = NULL; int ret; + DEBUG("vm=%p, pid=%d, id=%d, name=%s hostname=%s port=%d", vm, vm->pid, vm->def->id, vm->def->name, hostname, port); + if (virAsprintf(&uri, "tcp:%s:%d", hostname, port) < 0) { virReportOOMError(NULL); return -1; @@ -1183,6 +1209,8 @@ int qemuMonitorMigrateToCommand(const virDomainObjPtr vm, int ret = -1; char *safe_target = NULL; + DEBUG("vm=%p, pid=%d, id=%d, name=%s argv=%p target=%s", vm, vm->pid, vm->def->id, vm->def->name, argv, target); + argstr = virArgvToString(argv); if (!argstr) { virReportOOMError(NULL); @@ -1219,6 +1247,8 @@ int qemuMonitorAddUSBDisk(const virDomainObjPtr vm, int ret = -1; char *info = NULL; + DEBUG("vm=%p, pid=%d, id=%d, name=%s path=%s", vm, vm->pid, vm->def->id, vm->def->name, path); + safepath = qemuMonitorEscapeArg(path); if (!safepath) { virReportOOMError(NULL); @@ -1236,7 +1266,6 @@ int qemuMonitorAddUSBDisk(const virDomainObjPtr vm, goto cleanup; } - DEBUG ("%s: usb_add reply: %s", vm->def->name, info); /* If the command failed qemu prints: * Could not add ... */ if (strstr(info, "Could not add ")) { @@ -1272,7 +1301,6 @@ static int qemuMonitorAddUSBDevice(const virDomainObjPtr vm, goto cleanup; } - DEBUG ("%s: attach_usb reply: %s", vm->def->name, reply); /* If the command failed qemu prints: * Could not add ... */ if (strstr(reply, "Could not add ")) { @@ -1297,6 +1325,8 @@ int qemuMonitorAddUSBDeviceExact(const virDomainObjPtr vm, int ret; char *addr; + DEBUG("vm=%p, pid=%d, id=%d, name=%s bus=%d dev=%d", vm, vm->pid, vm->def->id, vm->def->name, bus, dev); + if (virAsprintf(&addr, "host:%.3d.%.3d", bus, dev) < 0) { virReportOOMError(NULL); return -1; @@ -1315,6 +1345,8 @@ int qemuMonitorAddUSBDeviceMatch(const virDomainObjPtr vm, int ret; char *addr; + DEBUG("vm=%p, pid=%d, id=%d, name=%s vendor=%d product=%d", vm, vm->pid, vm->def->id, vm->def->name, vendor, product); + if (virAsprintf(&addr, "host:%.4x:%.4x", vendor, product) < 0) { virReportOOMError(NULL); return -1; @@ -1408,6 +1440,8 @@ int qemuMonitorAddPCIHostDevice(const virDomainObjPtr vm, char *reply = NULL; int ret = -1; + DEBUG("vm=%p, pid=%d, id=%d, name=%s domain=%d bus=%d slot=%d function=%d", vm, vm->pid, vm->def->id, vm->def->name, hostDomain, hostBus, hostSlot, hostFunction); + *guestDomain = *guestBus = *guestSlot = 0; /* XXX hostDomain */ @@ -1459,6 +1493,8 @@ int qemuMonitorAddPCIDisk(const virDomainObjPtr vm, int tryOldSyntax = 0; int ret = -1; + DEBUG("vm=%p, pid=%d, id=%d, name=%s path=%s bus=%s", vm, vm->pid, vm->def->id, vm->def->name, path, bus); + safe_path = qemuMonitorEscapeArg(path); if (!safe_path) { virReportOOMError(NULL); @@ -1511,6 +1547,8 @@ int qemuMonitorAddPCINetwork(const virDomainObjPtr vm, char *reply = NULL; int ret = -1; + DEBUG("vm=%p, pid=%d, id=%d, name=%s nicstr=%s", vm, vm->pid, vm->def->id, vm->def->name, nicstr); + if (virAsprintf(&cmd, "pci_add pci_addr=auto nic %s", nicstr) < 0) { virReportOOMError(NULL); return -1; @@ -1548,6 +1586,8 @@ int qemuMonitorRemovePCIDevice(const virDomainObjPtr vm, int tryOldSyntax = 0; int ret = -1; + DEBUG("vm=%p, pid=%d, id=%d, name=%s domain=%d bus=%d slot=%d", vm, vm->pid, vm->def->id, vm->def->name, guestDomain, guestBus, guestSlot); + try_command: if (tryOldSyntax) { if (virAsprintf(&cmd, "pci_del 0 %.2x", guestSlot) < 0) { @@ -1568,8 +1608,6 @@ try_command: goto cleanup; } - DEBUG ("%s: pci_del reply: %s",vm->def->name, reply); - /* Syntax changed when KVM merged PCI hotplug upstream to QEMU, * so check for an error message from old KVM indicating the * need to try the old syntax */ @@ -1607,6 +1645,8 @@ int qemuMonitorSendFileHandle(const virDomainObjPtr vm, char *reply = NULL; int ret = -1; + DEBUG("vm=%p, pid=%d, id=%d, name=%s fdname=%s fd=%d", vm, vm->pid, vm->def->id, vm->def->name, fdname, fd); + if (virAsprintf(&cmd, "getfd %s", fdname) < 0) { virReportOOMError(NULL); return -1; @@ -1618,8 +1658,6 @@ int qemuMonitorSendFileHandle(const virDomainObjPtr vm, goto cleanup; } - DEBUG("%s: getfd reply: %s", vm->def->name, reply); - /* If the command isn't supported then qemu prints: * unknown command: getfd" */ if (strstr(reply, "unknown command:")) { @@ -1645,6 +1683,8 @@ int qemuMonitorCloseFileHandle(const virDomainObjPtr vm, char *reply = NULL; int ret = -1; + DEBUG("vm=%p, pid=%d, id=%d, name=%s fdname=%s", vm, vm->pid, vm->def->id, vm->def->name, fdname); + if (virAsprintf(&cmd, "closefd %s", fdname) < 0) { virReportOOMError(NULL); return -1; @@ -1656,8 +1696,6 @@ int qemuMonitorCloseFileHandle(const virDomainObjPtr vm, goto cleanup; } - DEBUG("%s: closefd reply: %s", vm->def->name, reply); - /* If the command isn't supported then qemu prints: * unknown command: getfd" */ if (strstr(reply, "unknown command:")) { @@ -1683,6 +1721,8 @@ int qemuMonitorAddHostNetwork(const virDomainObjPtr vm, char *reply = NULL; int ret = -1; + DEBUG("vm=%p, pid=%d, id=%d, name=%s netstr=%s", vm, vm->pid, vm->def->id, vm->def->name, netstr); + if (virAsprintf(&cmd, "host_net_add %s", netstr) < 0) { virReportOOMError(NULL); return -1; @@ -1694,8 +1734,6 @@ int qemuMonitorAddHostNetwork(const virDomainObjPtr vm, goto cleanup; } - DEBUG("%s: host_net_add reply: %s", vm->def->name, reply); - /* XXX error messages here ? */ ret = 0; @@ -1715,6 +1753,8 @@ int qemuMonitorRemoveHostNetwork(const virDomainObjPtr vm, char *reply = NULL; int ret = -1; + DEBUG("vm=%p, pid=%d, id=%d, name=%s netname=%s", vm, vm->pid, vm->def->id, vm->def->name, netname); + if (virAsprintf(&cmd, "host_net_remove %d %s", vlan, netname) < 0) { virReportOOMError(NULL); return -1; @@ -1726,8 +1766,6 @@ int qemuMonitorRemoveHostNetwork(const virDomainObjPtr vm, goto cleanup; } - DEBUG("%s: host_net_add reply: %s", vm->def->name, reply); - /* XXX error messages here ? */ ret = 0; -- 1.6.2.5

On Thu, 2009-09-24 at 16:00 +0100, Daniel P. Berrange wrote:
* src/qemu/qemu_monitor_text.c: Always print command and reply in qemuMonitorCommandWithHandler. Print all args in each monitor command API & remove redundant relpy printing --- src/qemu/qemu_monitor_text.c | 82 ++++++++++++++++++++++++++++++----------- 1 files changed, 60 insertions(+), 22 deletions(-)
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 2c41288..abb2c0a 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c ... @@ -1408,6 +1440,8 @@ int qemuMonitorAddPCIHostDevice(const virDomainObjPtr vm, char *reply = NULL; int ret = -1;
+ DEBUG("vm=%p, pid=%d, id=%d, name=%s domain=%d bus=%d slot=%d function=%d", vm, vm->pid, vm->def->id, vm->def->name, hostDomain, hostBus, hostSlot, hostFunction);
A 165 character line, impressive! "Line break please Carol". Looks fine otherwise, ACK Cheers, Mark.

* src/qemu/qemu_driver.c: Fix crash in scenario where XML parsing of hotplugged device failed & thus 'dev' is NULL --- src/qemu/qemu_driver.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index da72913..7dc9353 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4880,7 +4880,7 @@ cleanup: if (cgroup) virCgroupFree(&cgroup); - if (ret < 0) { + if (ret < 0 && dev != NULL) { if (qemuDomainSetDeviceOwnership(dom->conn, driver, dev, 1) < 0) VIR_WARN0("Fail to restore disk device ownership"); virDomainDeviceDefFree(dev); -- 1.6.2.5

On Thu, 2009-09-24 at 16:00 +0100, Daniel P. Berrange wrote:
* src/qemu/qemu_driver.c: Fix crash in scenario where XML parsing of hotplugged device failed & thus 'dev' is NULL --- src/qemu/qemu_driver.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index da72913..7dc9353 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4880,7 +4880,7 @@ cleanup: if (cgroup) virCgroupFree(&cgroup);
- if (ret < 0) { + if (ret < 0 && dev != NULL) { if (qemuDomainSetDeviceOwnership(dom->conn, driver, dev, 1) < 0) VIR_WARN0("Fail to restore disk device ownership"); virDomainDeviceDefFree(dev);
Nice; there's a good few changes I'd have liked to have seen split out and moved to the start of the series ACK Cheers, Mark.

On Thu, 2009-09-24 at 16:00 +0100, Daniel P. Berrange wrote:
This patch series is soooooo large, because I did it in many small steps, one command at a time.
I wouldn't apologize for there being so many patches ... it makes it easier to review. In fact, I'd have gone further - there are a number of changes which go beyond simple code re-factoring into real bugfix territory. I'd have like to see those changes as separate patches, allowing them to be reviewed carefully and then just glance over the re-factoring patches.
It is also now much easier to debug the monitor by just setting the env variables
LIBVIRT_LOG_OUTPUTS="1:stderr" LIBVIRT_LOG_FILTERS="1:qemu_monitor"
And you'll get the command & reply of each monitor interaction printed
Nice
I've tested basic handling of every new method with the exception of the migration ones, since I don't have a convenient target host when on my laptop.
Overall we get a small increase in code size, but huge increase in readability !
Yep, it's much nicer now Cheers, Mark.

On Thu, Sep 24, 2009 at 04:00:02PM +0100, Daniel P. Berrange wrote:
In the QEMU driver source code the methods which talk to the QEMU monitor currently all just call qemudMonitorCommand() directly with the raw command string, and then parse the raw reply.
In the not too distant future QEMU is introducing a new machine parsable monitor syntax. With the current way the code is structured supporting this new mode will be seriously unpleasant.
This large series of patches, moves all the monitor command formatting and parsing code out into a separate source file src/qemu/qemu_monitor_text.c. There is one API in that file for each logical monitor command we wish to issue, accepting (mostly) strongly typed arguments. The exception is the NIC hotplug method which still takes the raw NIC string for now.
The main qemu_driver.c file now directly calls the appropriate monitor command APIs, making logic there much cleaner.
When we add support for the new QEMU monitor syntax we'll gain another file src/qemu/qemu_monitor_json.c which implements all the same APIs as src/qemu/qemu_monitor_text.c, but using the new JSON syntax instead of raw text strings
This patch series is soooooo large, because I did it in many small steps, one command at a time.
It is also now much easier to debug the monitor by just setting the env variables
LIBVIRT_LOG_OUTPUTS="1:stderr" LIBVIRT_LOG_FILTERS="1:qemu_monitor"
And you'll get the command & reply of each monitor interaction printed
I've tested basic handling of every new method with the exception of the migration ones, since I don't have a convenient target host when on my laptop.
Overall we get a small increase in code size, but huge increase in readability !
ACK, I see that Mark made a detailed code review already, this all looks fine to me ! Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Tue, Sep 29, 2009 at 12:12:23PM +0200, Daniel Veillard wrote:
On Thu, Sep 24, 2009 at 04:00:02PM +0100, Daniel P. Berrange wrote:
In the QEMU driver source code the methods which talk to the QEMU monitor currently all just call qemudMonitorCommand() directly with the raw command string, and then parse the raw reply.
In the not too distant future QEMU is introducing a new machine parsable monitor syntax. With the current way the code is structured supporting this new mode will be seriously unpleasant.
This large series of patches, moves all the monitor command formatting and parsing code out into a separate source file src/qemu/qemu_monitor_text.c. There is one API in that file for each logical monitor command we wish to issue, accepting (mostly) strongly typed arguments. The exception is the NIC hotplug method which still takes the raw NIC string for now.
The main qemu_driver.c file now directly calls the appropriate monitor command APIs, making logic there much cleaner.
When we add support for the new QEMU monitor syntax we'll gain another file src/qemu/qemu_monitor_json.c which implements all the same APIs as src/qemu/qemu_monitor_text.c, but using the new JSON syntax instead of raw text strings
This patch series is soooooo large, because I did it in many small steps, one command at a time.
It is also now much easier to debug the monitor by just setting the env variables
LIBVIRT_LOG_OUTPUTS="1:stderr" LIBVIRT_LOG_FILTERS="1:qemu_monitor"
And you'll get the command & reply of each monitor interaction printed
I've tested basic handling of every new method with the exception of the migration ones, since I don't have a convenient target host when on my laptop.
Overall we get a small increase in code size, but huge increase in readability !
ACK, I see that Mark made a detailed code review already, this all looks fine to me !
Ok, I've pushed all this stuff Regards, Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
participants (4)
-
Daniel P. Berrange
-
Daniel Veillard
-
Mark McLoughlin
-
Paolo Bonzini