qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Corey Bryant <coreyb@linux.vnet.ibm.com>
To: qemu-devel@nongnu.org
Cc: kwolf@redhat.com, aliguori@us.ibm.com,
	stefanha@linux.vnet.ibm.com, libvir-list@redhat.com,
	lcapitulino@redhat.com, pbonzini@redhat.com, eblake@redhat.com
Subject: [Qemu-devel] [PATCH v4 3/7] qapi: Add pass-fd QMP command
Date: Fri, 22 Jun 2012 14:36:10 -0400	[thread overview]
Message-ID: <1340390174-7493-4-git-send-email-coreyb@linux.vnet.ibm.com> (raw)
In-Reply-To: <1340390174-7493-1-git-send-email-coreyb@linux.vnet.ibm.com>

This patch adds the pass-fd QMP command using the QAPI framework.
Like the getfd command, it is used to pass a file descriptor via
SCM_RIGHTS and associate it with a name.  However, the pass-fd
command also returns the received file descriptor, which is a
difference in behavior from the getfd command, which returns
nothing.  pass-fd also supports a boolean "force" argument that
can be used to specify that an existing file descriptor is
associated with the specified name, and that it should become a
copy of the newly passed file descriptor.

The closefd command can be used to close a file descriptor that was
passed with the pass-fd command.

Note that when using getfd or pass-fd, there are some commands
(e.g. migrate with fd:name) that implicitly close the named fd.
When this is not the case, closefd must be used to avoid fd leaks.

Signed-off-by: Corey Bryant <coreyb@linux.vnet.ibm.com>
---
v2:
 -Introduce new QMP command to pass/return fd (lcapitulino@redhat.com)
 -Use passfd as command name (berrange@redhat.com)

v3:
 -Use pass-fd as command name (lcapitulino@redhat.com)
 -Fail pass-fd if fdname already exists (lcapitulino@redhat.com)
 -Add notes to QMP command describing behavior in more detail
  (lcapitulino@redhat.com, eblake@redhat.com)
 -Add note about fd leakage (eblake@redhat.com)

v4:
 -Don't return same error class twice (lcapitulino@redhat.com)
 -Share code for qmp_gefd and qmp_pass_fd (lcapitulino@redhat.com)
 -Update qmp_closefd to call monitor_get_fd
 -Add support for "force" argument to pass-fd (eblake@redhat.com)

 dump.c           |    3 +-
 migration-fd.c   |    2 +-
 monitor.c        |   96 +++++++++++++++++++++++++++++++++++-------------------
 monitor.h        |    2 +-
 net.c            |    6 ++--
 qapi-schema.json |   36 ++++++++++++++++++++
 qmp-commands.hx  |   42 +++++++++++++++++++++++-
 7 files changed, 146 insertions(+), 41 deletions(-)

diff --git a/dump.c b/dump.c
index 4412d7a..2fd8ced 100644
--- a/dump.c
+++ b/dump.c
@@ -836,9 +836,8 @@ void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin,
 
 #if !defined(WIN32)
     if (strstart(file, "fd:", &p)) {
-        fd = monitor_get_fd(cur_mon, p);
+        fd = monitor_get_fd(cur_mon, p, errp);
         if (fd == -1) {
-            error_set(errp, QERR_FD_NOT_FOUND, p);
             return;
         }
     }
diff --git a/migration-fd.c b/migration-fd.c
index 50138ed..7335167 100644
--- a/migration-fd.c
+++ b/migration-fd.c
@@ -75,7 +75,7 @@ static int fd_close(MigrationState *s)
 
 int fd_start_outgoing_migration(MigrationState *s, const char *fdname)
 {
-    s->fd = monitor_get_fd(cur_mon, fdname);
+    s->fd = monitor_get_fd(cur_mon, fdname, NULL);
     if (s->fd == -1) {
         DPRINTF("fd_migration: invalid file descriptor identifier\n");
         goto err_after_get_fd;
diff --git a/monitor.c b/monitor.c
index 1a7f7e7..3433c06 100644
--- a/monitor.c
+++ b/monitor.c
@@ -814,7 +814,7 @@ static int add_graphics_client(Monitor *mon, const QDict *qdict, QObject **ret_d
     CharDriverState *s;
 
     if (strcmp(protocol, "spice") == 0) {
-        int fd = monitor_get_fd(mon, fdname);
+        int fd = monitor_get_fd(mon, fdname, NULL);
         int skipauth = qdict_get_try_bool(qdict, "skipauth", 0);
         int tls = qdict_get_try_bool(qdict, "tls", 0);
         if (!using_spice) {
@@ -828,18 +828,18 @@ static int add_graphics_client(Monitor *mon, const QDict *qdict, QObject **ret_d
         return 0;
 #ifdef CONFIG_VNC
     } else if (strcmp(protocol, "vnc") == 0) {
-	int fd = monitor_get_fd(mon, fdname);
+        int fd = monitor_get_fd(mon, fdname, NULL);
         int skipauth = qdict_get_try_bool(qdict, "skipauth", 0);
-	vnc_display_add_client(NULL, fd, skipauth);
-	return 0;
+        vnc_display_add_client(NULL, fd, skipauth);
+        return 0;
 #endif
     } else if ((s = qemu_chr_find(protocol)) != NULL) {
-	int fd = monitor_get_fd(mon, fdname);
-	if (qemu_chr_add_client(s, fd) < 0) {
-	    qerror_report(QERR_ADD_CLIENT_FAILED);
-	    return -1;
-	}
-	return 0;
+        int fd = monitor_get_fd(mon, fdname, NULL);
+        if (qemu_chr_add_client(s, fd) < 0) {
+            qerror_report(QERR_ADD_CLIENT_FAILED);
+            return -1;
+        }
+        return 0;
     }
 
     qerror_report(QERR_INVALID_PARAMETER, "protocol");
@@ -2182,57 +2182,69 @@ static void do_inject_mce(Monitor *mon, const QDict *qdict)
 }
 #endif
 
-void qmp_getfd(const char *fdname, Error **errp)
+static int monitor_put_fd(Monitor *mon, const char *fdname, bool replace,
+                          bool copy, Error **errp)
 {
     mon_fd_t *monfd;
     int fd;
 
-    fd = qemu_chr_fe_get_msgfd(cur_mon->chr);
+    fd = qemu_chr_fe_get_msgfd(mon->chr);
     if (fd == -1) {
         error_set(errp, QERR_FD_NOT_SUPPLIED);
-        return;
+        return -1;
     }
 
     if (qemu_isdigit(fdname[0])) {
         error_set(errp, QERR_INVALID_PARAMETER_VALUE, "fdname",
                   "a name not starting with a digit");
-        return;
+        return -1;
     }
 
-    QLIST_FOREACH(monfd, &cur_mon->fds, next) {
+    QLIST_FOREACH(monfd, &mon->fds, next) {
         if (strcmp(monfd->name, fdname) != 0) {
             continue;
         }
 
-        close(monfd->fd);
-        monfd->fd = fd;
-        return;
+        if (replace) {
+            /* the existing fd is replaced with the new fd */
+            close(monfd->fd);
+            monfd->fd = fd;
+            return fd;
+        }
+
+        if (copy) {
+            /* the existing fd becomes a copy of the new fd */
+            if (dup2(fd, monfd->fd) == -1) {
+                error_set(errp, QERR_UNDEFINED_ERROR);
+                return -1;
+            }
+            close(fd);
+            return monfd->fd;
+        }
+
+        error_set(errp, QERR_INVALID_PARAMETER, "fdname");
+        return -1;
+    }
+
+    if (copy) {
+        error_set(errp, QERR_INVALID_PARAMETER, "fdname");
+        return -1;
     }
 
     monfd = g_malloc0(sizeof(mon_fd_t));
     monfd->name = g_strdup(fdname);
     monfd->fd = fd;
 
-    QLIST_INSERT_HEAD(&cur_mon->fds, monfd, next);
+    QLIST_INSERT_HEAD(&mon->fds, monfd, next);
+    return fd;
 }
 
 void qmp_closefd(const char *fdname, Error **errp)
 {
-    mon_fd_t *monfd;
-
-    QLIST_FOREACH(monfd, &cur_mon->fds, next) {
-        if (strcmp(monfd->name, fdname) != 0) {
-            continue;
-        }
-
-        QLIST_REMOVE(monfd, next);
-        close(monfd->fd);
-        g_free(monfd->name);
-        g_free(monfd);
-        return;
+    int fd = monitor_get_fd(cur_mon, fdname, errp);
+    if (fd != -1) {
+        close(fd);
     }
-
-    error_set(errp, QERR_FD_NOT_FOUND, fdname);
 }
 
 static void do_loadvm(Monitor *mon, const QDict *qdict)
@@ -2247,7 +2259,7 @@ static void do_loadvm(Monitor *mon, const QDict *qdict)
     }
 }
 
-int monitor_get_fd(Monitor *mon, const char *fdname)
+int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp)
 {
     mon_fd_t *monfd;
 
@@ -2268,9 +2280,25 @@ int monitor_get_fd(Monitor *mon, const char *fdname)
         return fd;
     }
 
+    error_set(errp, QERR_FD_NOT_FOUND, fdname);
     return -1;
 }
 
+int64_t qmp_pass_fd(const char *fdname, bool has_force, bool force,
+                    Error **errp)
+{
+    bool replace = false;
+    bool copy = has_force ? force : false;
+    return monitor_put_fd(cur_mon, fdname, replace, copy, errp);
+}
+
+void qmp_getfd(const char *fdname, Error **errp)
+{
+    bool replace = true;
+    bool copy = false;
+    monitor_put_fd(cur_mon, fdname, replace, copy, errp);
+}
+
 /* mon_cmds and info_cmds would be sorted at runtime */
 static mon_cmd_t mon_cmds[] = {
 #include "hmp-commands.h"
diff --git a/monitor.h b/monitor.h
index cd1d878..8fa515d 100644
--- a/monitor.h
+++ b/monitor.h
@@ -63,7 +63,7 @@ int monitor_read_block_device_key(Monitor *mon, const char *device,
                                   BlockDriverCompletionFunc *completion_cb,
                                   void *opaque);
 
-int monitor_get_fd(Monitor *mon, const char *fdname);
+int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp);
 
 void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
     GCC_FMT_ATTR(2, 0);
diff --git a/net.c b/net.c
index 4aa416c..28860b8 100644
--- a/net.c
+++ b/net.c
@@ -730,12 +730,14 @@ int qemu_find_nic_model(NICInfo *nd, const char * const *models,
 int net_handle_fd_param(Monitor *mon, const char *param)
 {
     int fd;
+    Error *local_err = NULL;
 
     if (!qemu_isdigit(param[0]) && mon) {
 
-        fd = monitor_get_fd(mon, param);
+        fd = monitor_get_fd(mon, param, &local_err);
         if (fd == -1) {
-            error_report("No file descriptor named %s found", param);
+            qerror_report_err(local_err);
+            error_free(local_err);
             return -1;
         }
     } else {
diff --git a/qapi-schema.json b/qapi-schema.json
index 26a6b84..2ac1261 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1864,6 +1864,41 @@
 { 'command': 'netdev_del', 'data': {'id': 'str'} }
 
 ##
+# @pass-fd:
+#
+# Pass a file descriptor via SCM rights and assign it a name
+#
+# @fdname: file descriptor name
+#
+# @force: #optional true specifies that an existing file descriptor is
+#         associated with @fdname, and that it should become a copy of the
+#         newly passed file descriptor.
+#
+# Returns: The QEMU file descriptor that is assigned to @fdname
+#          If file descriptor was not received, FdNotSupplied
+#          If @fdname is not valid, InvalidParameterValue
+#          If @fdname already exists, and @force is not true, InvalidParameter
+#          If @fdname does not already exist, and @force is true,
+#          InvalidParameter
+#          If @force fails to copy the passed file descriptor,
+#          UndefinedError
+#
+# Since: 1.2.0
+#
+# Notes: If @fdname already exists, and @force is not true, the
+#        command will fail.
+#
+#        If @fdname already exists, and @force is true, the value of
+#        the existing file descriptor is returned when the command is
+#        successful.
+#
+#        The 'closefd' command can be used to explicitly close the
+#        file descriptor when it is no longer needed.
+##
+{ 'command': 'pass-fd', 'data': {'fdname': 'str', '*force': 'bool'},
+  'returns': 'int' }
+
+##
 # @getfd:
 #
 # Receive a file descriptor via SCM rights and assign it a name
@@ -1879,6 +1914,7 @@
 # Notes: If @fdname already exists, the file descriptor assigned to
 #        it will be closed and replaced by the received file
 #        descriptor.
+#
 #        The 'closefd' command can be used to explicitly close the
 #        file descriptor when it is no longer needed.
 ##
diff --git a/qmp-commands.hx b/qmp-commands.hx
index e3cf3c5..7e3c07e 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -869,9 +869,49 @@ Example:
 EQMP
 
     {
+        .name       = "pass-fd",
+        .args_type  = "fdname:s,force:b?",
+        .params     = "pass-fd fdname force",
+        .help       = "pass a file descriptor via SCM rights and assign it a name",
+        .mhandler.cmd_new = qmp_marshal_input_pass_fd,
+    },
+
+SQMP
+pass-fd
+-------
+
+Pass a file descriptor via SCM rights and assign it a name.
+
+Arguments:
+
+- "fdname": file descriptor name (json-string)
+- "force": true specifies that an existing file descriptor is associated
+           with "fdname", and that it should become a copy of the newly
+           passed file descriptor. (json-bool, optional)
+
+Return a json-int with the QEMU file descriptor that is assigned to "fdname".
+
+Example:
+
+-> { "execute": "pass-fd", "arguments": { "fdname": "fd1" } }
+<- { "return": 42 }
+
+Notes:
+
+(1) If the name specified by the "fdname" argument already exists, and
+    "force" is not true, the command will fail.
+(2) If the name specified by the "fdname" argument already exists, and
+    "force" is true, the value of the existing file descriptor is
+    returned when the command is successful.
+(3) The 'closefd' command can be used to explicitly close the file
+    descriptor when it is no longer needed.
+
+EQMP
+
+    {
         .name       = "getfd",
         .args_type  = "fdname:s",
-        .params     = "getfd name",
+        .params     = "getfd fdname",
         .help       = "receive a file descriptor via SCM rights and assign it a name",
         .mhandler.cmd_new = qmp_marshal_input_getfd,
     },
-- 
1.7.10.2

  parent reply	other threads:[~2012-06-22 18:36 UTC|newest]

Thread overview: 56+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-06-22 18:36 [Qemu-devel] [PATCH v4 0/7] file descriptor passing using pass-fd Corey Bryant
2012-06-22 18:36 ` [Qemu-devel] [PATCH v4 1/7] qemu-char: Add MSG_CMSG_CLOEXEC flag to recvmsg Corey Bryant
2012-06-22 19:31   ` Eric Blake
2012-06-22 18:36 ` [Qemu-devel] [PATCH v4 2/7] qapi: Convert getfd and closefd Corey Bryant
2012-07-11 18:51   ` Luiz Capitulino
2012-06-22 18:36 ` Corey Bryant [this message]
2012-06-22 20:24   ` [Qemu-devel] [PATCH v4 3/7] qapi: Add pass-fd QMP command Eric Blake
2012-06-22 18:36 ` [Qemu-devel] [PATCH v4 4/7] qapi: Re-arrange monitor.c functions Corey Bryant
2012-06-22 18:36 ` [Qemu-devel] [PATCH v4 5/7] block: Prevent /dev/fd/X filename from being detected as floppy Corey Bryant
2012-06-22 18:36 ` [Qemu-devel] [PATCH v4 6/7] block: Convert open calls to qemu_open Corey Bryant
2012-06-22 18:36 ` [Qemu-devel] [PATCH v4 7/7] osdep: Enable qemu_open to dup pre-opened fd Corey Bryant
2012-06-22 19:58   ` Eric Blake
     [not found] ` <20120626091004.GA14451@redhat.com>
     [not found]   ` <4FE9A0F0.2050809@redhat.com>
     [not found]     ` <20120626175045.2c7011b3@doriath.home>
     [not found]       ` <4FEA37A9.10707@linux.vnet.ibm.com>
     [not found]         ` <4FEA3D9C.8080205@redhat.com>
2012-07-02 22:02           ` [Qemu-devel] [PATCH v4 0/7] file descriptor passing using pass-fd Corey Bryant
2012-07-02 22:31             ` Eric Blake
2012-07-03  9:07               ` Daniel P. Berrange
2012-07-03  9:40               ` Kevin Wolf
2012-07-03 13:42               ` Corey Bryant
2012-07-03 15:40             ` Corey Bryant
2012-07-03 15:59               ` Kevin Wolf
2012-07-03 16:25                 ` Corey Bryant
2012-07-03 17:03                   ` Eric Blake
2012-07-03 17:46                     ` Corey Bryant
2012-07-03 18:00                       ` Eric Blake
2012-07-03 18:21                         ` Corey Bryant
2012-07-04  8:09                           ` Kevin Wolf
2012-07-05 15:06                             ` Corey Bryant
2012-07-09 14:05                               ` Luiz Capitulino
2012-07-09 15:05                                 ` Corey Bryant
2012-07-09 15:46                                   ` Kevin Wolf
2012-07-09 16:18                                     ` Luiz Capitulino
2012-07-09 17:59                                       ` Corey Bryant
2012-07-09 17:35                                     ` Corey Bryant
2012-07-09 17:48                                       ` Luiz Capitulino
2012-07-09 18:02                                         ` Corey Bryant
2012-07-10  7:53                                       ` Kevin Wolf
2012-07-09 18:20                                   ` Corey Bryant
2012-07-04  8:00                     ` Kevin Wolf
2012-07-05 14:22                       ` Corey Bryant
2012-07-05 14:51                         ` Kevin Wolf
2012-07-05 16:35                           ` Corey Bryant
2012-07-05 16:37                             ` Corey Bryant
2012-07-06  9:06                               ` Kevin Wolf
2012-07-05 17:00                             ` Eric Blake
2012-07-05 17:36                               ` Corey Bryant
2012-07-06  9:11                               ` Kevin Wolf
2012-07-06 17:14                                 ` Corey Bryant
2012-07-06 17:15                                   ` Corey Bryant
2012-07-06 17:40                                 ` Corey Bryant
2012-07-06 18:19                                   ` [Qemu-devel] [libvirt] " Corey Bryant
2012-07-09 14:04                                   ` [Qemu-devel] " Kevin Wolf
2012-07-09 15:23                                     ` Corey Bryant
2012-07-09 15:30                                       ` Kevin Wolf
2012-07-09 18:40   ` Anthony Liguori
2012-07-09 19:00     ` Luiz Capitulino
2012-07-10  8:54       ` Daniel P. Berrange
2012-07-10  7:58     ` Kevin Wolf

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1340390174-7493-4-git-send-email-coreyb@linux.vnet.ibm.com \
    --to=coreyb@linux.vnet.ibm.com \
    --cc=aliguori@us.ibm.com \
    --cc=eblake@redhat.com \
    --cc=kwolf@redhat.com \
    --cc=lcapitulino@redhat.com \
    --cc=libvir-list@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@linux.vnet.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).