This patch add a -qmp parameter to the qemu-nbd command line in order to be able to manipulate the qemu-nbd block devices via qmp.
This could be used with containers to easily migrate from qemu to a container. Signed-off-by: Benoit Canet <ben...@irqsave.net> --- Makefile.objs | 3 +- include/monitor/monitor-init.h | 34 ++++++++++++ monitor-init.c | 121 +++++++++++++++++++++++++++++++++++++++++ monitor.c | 1 + qemu-nbd.c | 33 ++++++++++- vl.c | 88 +----------------------------- 6 files changed, 190 insertions(+), 90 deletions(-) create mode 100644 include/monitor/monitor-init.h create mode 100644 monitor-init.c diff --git a/Makefile.objs b/Makefile.objs index 6fe81e9..6116fb6 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -23,6 +23,7 @@ block-obj-m = block/ qapi-block-obj-y = block/qapi-generated/qmp-marshal.o blockdev.o qmp.o qapi-block-obj-y += monitor.o +qapi-block-obj-y += monitor-init.o qapi-block-obj-y += qemu-char.o qapi-block-obj-y += qemu-log.o qapi-block-obj-y += qom/ @@ -79,7 +80,7 @@ common-obj-y += bt-host.o bt-vhci.o bt-host.o-cflags := $(BLUEZ_CFLAGS) common-obj-y += dma-helpers.o -common-obj-y += vl.o +common-obj-y += vl.o monitor-init.o vl.o-cflags := $(GPROF_CFLAGS) $(SDL_CFLAGS) common-obj-y += tpm.o diff --git a/include/monitor/monitor-init.h b/include/monitor/monitor-init.h new file mode 100644 index 0000000..23be581 --- /dev/null +++ b/include/monitor/monitor-init.h @@ -0,0 +1,34 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MONITOR_INIT_H +#define MONITOR_INIT_H + +#include "qemu/option.h" + +int chardev_init_func(QemuOpts *opts, void *opaque); +int mon_init_func(QemuOpts *opts, void *opaque); +void monitor_parse(const char *optarg, const char *mode); + +#endif diff --git a/monitor-init.c b/monitor-init.c new file mode 100644 index 0000000..9888286 --- /dev/null +++ b/monitor-init.c @@ -0,0 +1,121 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "monitor/monitor-init.h" +#include "monitor/monitor.h" +#include "sysemu/char.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +int chardev_init_func(QemuOpts *opts, void *opaque) +{ + Error *local_err = NULL; + + qemu_chr_new_from_opts(opts, NULL, &local_err); + if (local_err) { + error_report("%s", error_get_pretty(local_err)); + error_free(local_err); + return -1; + } + return 0; +} + +int mon_init_func(QemuOpts *opts, void *opaque) +{ + CharDriverState *chr; + const char *chardev; + const char *mode; + int flags; + + mode = qemu_opt_get(opts, "mode"); + if (mode == NULL) { + mode = "readline"; + } + if (strcmp(mode, "readline") == 0) { + flags = MONITOR_USE_READLINE; + } else if (strcmp(mode, "control") == 0) { + flags = MONITOR_USE_CONTROL; + } else { + fprintf(stderr, "unknown monitor mode \"%s\"\n", mode); + exit(1); + } + + if (qemu_opt_get_bool(opts, "pretty", 0)) { + flags |= MONITOR_USE_PRETTY; + } + + if (qemu_opt_get_bool(opts, "default", 0)) { + flags |= MONITOR_IS_DEFAULT; + } + + chardev = qemu_opt_get(opts, "chardev"); + chr = qemu_chr_find(chardev); + if (chr == NULL) { + fprintf(stderr, "chardev \"%s\" not found\n", chardev); + exit(1); + } + + qemu_chr_fe_claim_no_fail(chr); + monitor_init(chr, flags); + return 0; +} + +void monitor_parse(const char *optarg, const char *mode) +{ + static int monitor_device_index; + QemuOpts *opts; + const char *p; + char label[32]; + int def = 0; + + if (strstart(optarg, "chardev:", &p)) { + snprintf(label, sizeof(label), "%s", p); + } else { + snprintf(label, sizeof(label), "compat_monitor%d", + monitor_device_index); + if (monitor_device_index == 0) { + def = 1; + } + opts = qemu_chr_parse_compat(label, optarg); + if (!opts) { + fprintf(stderr, "parse error: %s\n", optarg); + exit(1); + } + } + + opts = qemu_opts_create(qemu_find_opts("mon"), label, 1, NULL); + if (!opts) { + fprintf(stderr, "duplicate chardev: %s\n", label); + exit(1); + } + qemu_opt_set(opts, "mode", mode); + qemu_opt_set(opts, "chardev", label); + if (def) { + qemu_opt_set(opts, "default", "on"); + } + monitor_device_index++; +} + diff --git a/monitor.c b/monitor.c index bc7f3d3..bf7d9a3 100644 --- a/monitor.c +++ b/monitor.c @@ -149,6 +149,7 @@ static mon_cmd_t info_cmds[] = { }; size_t sizeof_info_cmds = sizeof(info_cmds); static const mon_cmd_t qmp_cmds[] = { +#include "block/qapi-generated/qmp-commands-old.h" { /* NULL */ }, }; #else diff --git a/qemu-nbd.c b/qemu-nbd.c index 626e584..324f029 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -16,13 +16,16 @@ * along with this program; if not, see <http://www.gnu.org/licenses/>. */ +#include "monitor/monitor-init.h" #include "qemu-common.h" #include "block/block.h" #include "block/nbd.h" +#include "qemu/config-file.h" #include "qemu/main-loop.h" #include "qemu/sockets.h" #include "qemu/error-report.h" #include "block/snapshot.h" +#include "sysemu/sysemu.h" #include <stdarg.h> #include <stdio.h> @@ -97,6 +100,9 @@ static void usage(const char *name) " --aio=MODE set AIO mode (native or threads)\n" #endif "\n" +"Management options:\n" +" -q, --qmp=DEV machine monitor listen on DEV\n" +"\n" "Report bugs to <qemu-devel@nongnu.org>\n" , name, NBD_DEFAULT_PORT, "DEVICE"); } @@ -390,7 +396,7 @@ int main(int argc, char **argv) off_t fd_size; QemuOpts *sn_opts = NULL; const char *sn_id_or_name = NULL; - const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:tl:"; + const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:tl:q:"; struct option lopt[] = { { "help", 0, NULL, 'h' }, { "version", 0, NULL, 'V' }, @@ -412,6 +418,7 @@ int main(int argc, char **argv) { "discard", 1, NULL, QEMU_NBD_OPT_DISCARD }, { "shared", 1, NULL, 'e' }, { "format", 1, NULL, 'f' }, + { "qmp", 1, NULL, 'q' }, { "persistent", 0, NULL, 't' }, { "verbose", 0, NULL, 'v' }, { NULL, 0, NULL, 0 } @@ -432,6 +439,11 @@ int main(int argc, char **argv) pthread_t client_thread; const char *fmt = NULL; Error *local_err = NULL; + bool has_qmp = false; + + module_call_init(MODULE_INIT_QOM); + qemu_add_opts(&qemu_mon_opts); + qemu_add_opts(&qemu_chardev_opts); /* The client thread uses SIGTERM to interrupt the server. A signal * handler ensures that "qemu-nbd -v -c" exits with a nice status code. @@ -553,6 +565,10 @@ int main(int argc, char **argv) case 't': persistent = 1; break; + case 'q': + monitor_parse(optarg, "control"); + has_qmp = true; + break; case 'v': verbose = 1; break; @@ -576,6 +592,15 @@ int main(int argc, char **argv) argv[0]); } + if (qemu_opts_foreach(qemu_find_opts("chardev"), chardev_init_func, + NULL, 1) != 0) { + exit(1); + } + + if (qemu_opts_foreach(qemu_find_opts("mon"), mon_init_func, NULL, 1) != 0) { + exit(1); + } + if (disconnect) { fd = open(argv[optind], O_RDWR); if (fd < 0) { @@ -725,8 +750,10 @@ int main(int argc, char **argv) (void *)(uintptr_t)fd); /* now when the initialization is (almost) complete, chdir("/") - * to free any busy filesystems */ - if (chdir("/") < 0) { + * to free any busy filesystems. We don't do this when QMP is used to avoid + * disturbing snapshot taking. + */ + if (!has_qmp && chdir("/") < 0) { err(EXIT_FAILURE, "Could not chdir to root directory"); } diff --git a/vl.c b/vl.c index fe451aa..fdfe246 100644 --- a/vl.c +++ b/vl.c @@ -119,6 +119,8 @@ int main(int argc, char **argv) #include "qom/object_interfaces.h" #include "qapi-event.h" +#include "monitor/monitor-init.h" + #define DEFAULT_RAM_SIZE 128 #define MAX_VIRTIO_CONSOLES 1 @@ -2351,19 +2353,6 @@ static int device_init_func(QemuOpts *opts, void *opaque) return 0; } -static int chardev_init_func(QemuOpts *opts, void *opaque) -{ - Error *local_err = NULL; - - qemu_chr_new_from_opts(opts, NULL, &local_err); - if (local_err) { - error_report("%s", error_get_pretty(local_err)); - error_free(local_err); - return -1; - } - return 0; -} - #ifdef CONFIG_VIRTFS static int fsdev_init_func(QemuOpts *opts, void *opaque) { @@ -2374,79 +2363,6 @@ static int fsdev_init_func(QemuOpts *opts, void *opaque) } #endif -static int mon_init_func(QemuOpts *opts, void *opaque) -{ - CharDriverState *chr; - const char *chardev; - const char *mode; - int flags; - - mode = qemu_opt_get(opts, "mode"); - if (mode == NULL) { - mode = "readline"; - } - if (strcmp(mode, "readline") == 0) { - flags = MONITOR_USE_READLINE; - } else if (strcmp(mode, "control") == 0) { - flags = MONITOR_USE_CONTROL; - } else { - fprintf(stderr, "unknown monitor mode \"%s\"\n", mode); - exit(1); - } - - if (qemu_opt_get_bool(opts, "pretty", 0)) - flags |= MONITOR_USE_PRETTY; - - if (qemu_opt_get_bool(opts, "default", 0)) - flags |= MONITOR_IS_DEFAULT; - - chardev = qemu_opt_get(opts, "chardev"); - chr = qemu_chr_find(chardev); - if (chr == NULL) { - fprintf(stderr, "chardev \"%s\" not found\n", chardev); - exit(1); - } - - qemu_chr_fe_claim_no_fail(chr); - monitor_init(chr, flags); - return 0; -} - -static void monitor_parse(const char *optarg, const char *mode) -{ - static int monitor_device_index = 0; - QemuOpts *opts; - const char *p; - char label[32]; - int def = 0; - - if (strstart(optarg, "chardev:", &p)) { - snprintf(label, sizeof(label), "%s", p); - } else { - snprintf(label, sizeof(label), "compat_monitor%d", - monitor_device_index); - if (monitor_device_index == 0) { - def = 1; - } - opts = qemu_chr_parse_compat(label, optarg); - if (!opts) { - fprintf(stderr, "parse error: %s\n", optarg); - exit(1); - } - } - - opts = qemu_opts_create(qemu_find_opts("mon"), label, 1, NULL); - if (!opts) { - fprintf(stderr, "duplicate chardev: %s\n", label); - exit(1); - } - qemu_opt_set(opts, "mode", mode); - qemu_opt_set(opts, "chardev", label); - if (def) - qemu_opt_set(opts, "default", "on"); - monitor_device_index++; -} - struct device_config { enum { DEV_USB, /* -usbdevice */ -- 2.0.1