diff mbox

[v1,24/24] qemu-nbd: Add --qmp option to qemu-nbd.

Message ID 1406870842-17988-25-git-send-email-benoit.canet@irqsave.net
State New
Headers show

Commit Message

BenoƮt Canet Aug. 1, 2014, 5:27 a.m. UTC
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 <benoit@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 mbox

Patch

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     */