add-fd, remove-fd, and query-fdsets provide functionality that can be
used for passing fds to qemu and closing fdsets that are no longer
necessary.
Signed-off-by: Jonathon Jongsma <jjongsma(a)redhat.com>
---
src/qemu/qemu_monitor.c | 93 +++++++++++++++++++
src/qemu/qemu_monitor.h | 41 +++++++++
src/qemu/qemu_monitor_json.c | 173 +++++++++++++++++++++++++++++++++++
src/qemu/qemu_monitor_json.h | 12 +++
4 files changed, 319 insertions(+)
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 8c991fefbb..594d701c48 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -2649,6 +2649,99 @@ qemuMonitorGraphicsRelocate(qemuMonitorPtr mon,
}
+/**
+ * qemuMonitorAddFileHandleToSet:
+ * @mon: monitor object
+ * @fd: file descriptor to pass to qemu
+ * @fdset: the fdset to register this fd with, -1 to create a new fdset
+ * @opaque: opaque data to associated with this fd
+ * @info: structure that will be updated with the fd and fdset returned by qemu
+ *
+ * Attempts to register a file descriptor with qemu that can then be referenced
+ * via the file path /dev/fdset/$FDSETID
+ * Returns 0 if ok, and -1 on failure */
+int
+qemuMonitorAddFileHandleToSet(qemuMonitorPtr mon,
+ int fd,
+ int fdset,
+ const char *opaque,
+ qemuMonitorAddFdInfoPtr info)
+{
+ VIR_DEBUG("fd=%d,fdset=%i,opaque=%s", fd, fdset, opaque);
+
+ QEMU_CHECK_MONITOR(mon);
+
+ if (fd < 0) {
+ virReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("fd must be valid"));
+ return -1;
+ }
+
+ return qemuMonitorJSONAddFileHandleToSet(mon, fd, fdset, opaque, info);
+}
+
+
+/**
+ * qemuMonitorRemoveFdset:
+ * @mon: monitor object
+ * @fdset: the fdset to remove
+ *
+ * Attempts to remove a fdset from qemu and close associated file descriptors
+ * Returns 0 if ok, and -1 on failure */
+int
+qemuMonitorRemoveFdset(qemuMonitorPtr mon,
+ int fdset)
+{
+ VIR_DEBUG("fdset=%d", fdset);
+
+ QEMU_CHECK_MONITOR(mon);
+
+ if (fdset < 0) {
+ virReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("fdset must be valid"));
+ return -1;
+ }
+
+ return qemuMonitorJSONRemoveFdset(mon, fdset);
+}
+
+
+void qemuMonitorFdsetsFree(qemuMonitorFdsetsPtr fdsets)
+{
+ size_t i;
+
+ for (i = 0; i < fdsets->nfdsets; i++) {
+ size_t j;
+ qemuMonitorFdsetInfoPtr set = &fdsets->fdsets[i];
+
+ for (j = 0; j < set->nfds; j++)
+ g_free(set->fds[j].opaque);
+ }
+ g_free(fdsets->fdsets);
+ g_free(fdsets);
+}
+
+
+/**
+ * qemuMonitorQueryFdsets:
+ * @mon: monitor object
+ * @fdsets: a pointer that is filled with a new qemuMonitorFdsets struct
+ *
+ * Queries qemu for the fdsets that are registered with that instance, and
+ * returns a structure describing those fdsets. The returned struct should be
+ * freed with qemuMonitorFdsetsFree();
+ *
+ * Returns 0 if ok, and -1 on failure */
+int
+qemuMonitorQueryFdsets(qemuMonitorPtr mon,
+ qemuMonitorFdsetsPtr *fdsets)
+{
+ QEMU_CHECK_MONITOR(mon);
+
+ return qemuMonitorJSONQueryFdsets(mon, fdsets);
+}
+
+
int
qemuMonitorSendFileHandle(qemuMonitorPtr mon,
const char *fdname,
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index a744c8975b..a372ba1eda 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -880,6 +880,47 @@ int qemuMonitorGraphicsRelocate(qemuMonitorPtr mon,
int tlsPort,
const char *tlsSubject);
+typedef struct _qemuMonitorAddFdInfo qemuMonitorAddFdInfo;
+typedef qemuMonitorAddFdInfo *qemuMonitorAddFdInfoPtr;
+struct _qemuMonitorAddFdInfo {
+ int fd;
+ int fdset;
+};
+int
+qemuMonitorAddFileHandleToSet(qemuMonitorPtr mon,
+ int fd,
+ int fdset,
+ const char *opaque,
+ qemuMonitorAddFdInfoPtr info);
+
+int
+qemuMonitorRemoveFdset(qemuMonitorPtr mon,
+ int fdset);
+
+typedef struct _qemuMonitorFdsetFdInfo qemuMonitorFdsetFdInfo;
+typedef qemuMonitorFdsetFdInfo *qemuMonitorFdsetFdInfoPtr;
+struct _qemuMonitorFdsetFdInfo {
+ int fd;
+ char *opaque;
+};
+typedef struct _qemuMonitorFdsetInfo qemuMonitorFdsetInfo;
+typedef qemuMonitorFdsetInfo *qemuMonitorFdsetInfoPtr;
+struct _qemuMonitorFdsetInfo {
+ int id;
+ qemuMonitorFdsetFdInfoPtr fds;
+ int nfds;
+};
+typedef struct _qemuMonitorFdsets qemuMonitorFdsets;
+typedef qemuMonitorFdsets *qemuMonitorFdsetsPtr;
+struct _qemuMonitorFdsets {
+ qemuMonitorFdsetInfoPtr fdsets;
+ int nfdsets;
+};
+void qemuMonitorFdsetsFree(qemuMonitorFdsetsPtr fdsets);
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(qemuMonitorFdsets, qemuMonitorFdsetsFree);
+int qemuMonitorQueryFdsets(qemuMonitorPtr mon,
+ qemuMonitorFdsetsPtr *fdsets);
+
int qemuMonitorSendFileHandle(qemuMonitorPtr mon,
const char *fdname,
int fd);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 26ac499fc5..1b77adfbcd 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -3929,6 +3929,179 @@ int qemuMonitorJSONGraphicsRelocate(qemuMonitorPtr mon,
}
+static int
+qemuAddfdInfoParse(virJSONValuePtr msg,
+ qemuMonitorAddFdInfoPtr fdinfo)
+{
+ virJSONValuePtr returnObj;
+
+ if (!(returnObj = virJSONValueObjectGetObject(msg, "return"))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Missing or invalid return data in add-fd
response"));
+ return -1;
+ }
+
+ if (virJSONValueObjectGetNumberInt(returnObj, "fd", &fdinfo->fd)
< 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Missing or invalid fd in add-fd response"));
+ return -1;
+ }
+
+ if (virJSONValueObjectGetNumberInt(returnObj, "fdset-id",
&fdinfo->fdset) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Missing or invalid fdset-id in add-fd response"));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/* if fdset is negative, qemu will create a new fdset and add the fd to that */
+int qemuMonitorJSONAddFileHandleToSet(qemuMonitorPtr mon,
+ int fd,
+ int fdset,
+ const char *opaque,
+ qemuMonitorAddFdInfoPtr fdinfo)
+{
+ virJSONValuePtr args = NULL;
+ g_autoptr(virJSONValue) reply = NULL;
+ g_autoptr(virJSONValue) cmd = NULL;
+
+ if (virJSONValueObjectCreate(&args, "S:opaque", opaque, NULL) < 0)
+ return -1;
+
+ if (fdset >= 0)
+ if (virJSONValueObjectAdd(args, "j:fdset-id", fdset, NULL) < 0)
+ return -1;
+
+ if (!(cmd = qemuMonitorJSONMakeCommandInternal("add-fd", args)))
+ return -1;
+
+ if (qemuMonitorJSONCommandWithFd(mon, cmd, fd, &reply) < 0)
+ return -1;
+
+ if (qemuMonitorJSONCheckError(cmd, reply) < 0)
+ return -1;
+
+ if (qemuAddfdInfoParse(reply, fdinfo) < 0)
+ return -1;
+
+ return 0;
+}
+
+static int
+qemuMonitorJSONQueryFdsetsParse(virJSONValuePtr msg,
+ qemuMonitorFdsetsPtr *fdsets)
+{
+ virJSONValuePtr returnArray, entry;
+ size_t i;
+ g_autoptr(qemuMonitorFdsets) sets = g_new0(qemuMonitorFdsets, 1);
+ int ninfo;
+
+ returnArray = virJSONValueObjectGetArray(msg, "return");
+
+ ninfo = virJSONValueArraySize(returnArray);
+ if (ninfo > 0)
+ sets->fdsets = g_new0(qemuMonitorFdsetInfo, ninfo);
+ sets->nfdsets = ninfo;
+
+ for (i = 0; i < ninfo; i++) {
+ size_t j;
+ const char *tmp;
+ virJSONValuePtr fdarray;
+ qemuMonitorFdsetInfoPtr fdsetinfo = &sets->fdsets[i];
+
+ if (!(entry = virJSONValueArrayGet(returnArray, i))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("query-fdsets return data missing fdset array
element"));
+ return -1;
+ }
+
+ if (virJSONValueObjectGetNumberInt(entry, "fdset-id",
&fdsetinfo->id) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("query-fdsets reply was missing
'fdset-id'"));
+ return -1;
+
+ }
+
+ fdarray = virJSONValueObjectGetArray(entry, "fds");
+ fdsetinfo->nfds = virJSONValueArraySize(fdarray);
+ if (fdsetinfo->nfds > 0)
+ fdsetinfo->fds = g_new0(qemuMonitorFdsetFdInfo, fdsetinfo->nfds);
+
+ for (j = 0; j < fdsetinfo->nfds; j++) {
+ qemuMonitorFdsetFdInfoPtr fdinfo = &fdsetinfo->fds[j];
+ virJSONValuePtr fdentry;
+
+ if (!(fdentry = virJSONValueArrayGet(fdarray, j))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("query-fdsets return data missing fd array
element"));
+ return -1;
+ }
+
+ if (virJSONValueObjectGetNumberInt(fdentry, "fd",
&fdinfo->fd) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("query-fdsets return data missing
'fd'"));
+ return -1;
+ }
+
+ /* opaque is optional and may be missing */
+ tmp = virJSONValueObjectGetString(fdentry, "opaque");
+ if (tmp)
+ fdinfo->opaque = g_strdup(tmp);
+ }
+ }
+
+ *fdsets = g_steal_pointer(&sets);
+ return 0;
+}
+
+
+int qemuMonitorJSONQueryFdsets(qemuMonitorPtr mon,
+ qemuMonitorFdsetsPtr *fdsets)
+{
+ g_autoptr(virJSONValue) reply = NULL;
+ g_autoptr(virJSONValue) cmd = qemuMonitorJSONMakeCommand("query-fdsets",
+ NULL);
+
+ if (!cmd)
+ return -1;
+
+ if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
+ return -1;
+
+ if (qemuMonitorJSONCheckError(cmd, reply) < 0)
+ return -1;
+
+ if (qemuMonitorJSONQueryFdsetsParse(reply, fdsets) < 0)
+ return -1;
+
+ return 0;
+}
+
+
+int qemuMonitorJSONRemoveFdset(qemuMonitorPtr mon,
+ int fdset)
+{
+ g_autoptr(virJSONValue) reply = NULL;
+ g_autoptr(virJSONValue) cmd = qemuMonitorJSONMakeCommand("remove-fd",
+ "i:fdset-id",
fdset,
+ NULL);
+
+ if (!cmd)
+ return -1;
+
+ if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
+ return -1;
+
+ if (qemuMonitorJSONCheckError(cmd, reply) < 0)
+ return -1;
+
+ return 0;
+}
+
+
int qemuMonitorJSONSendFileHandle(qemuMonitorPtr mon,
const char *fdname,
int fd)
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index 098ab857be..2b9a42efe0 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -202,6 +202,18 @@ int qemuMonitorJSONAddPCINetwork(qemuMonitorPtr mon,
int qemuMonitorJSONRemovePCIDevice(qemuMonitorPtr mon,
virPCIDeviceAddress *guestAddr);
+int qemuMonitorJSONAddFileHandleToSet(qemuMonitorPtr mon,
+ int fd,
+ int fdset,
+ const char *opaque,
+ qemuMonitorAddFdInfoPtr info);
+
+int qemuMonitorJSONRemoveFdset(qemuMonitorPtr mon,
+ int fdset);
+
+int qemuMonitorJSONQueryFdsets(qemuMonitorPtr mon,
+ qemuMonitorFdsetsPtr *fdsets);
+
int qemuMonitorJSONSendFileHandle(qemuMonitorPtr mon,
const char *fdname,
int fd);
--
2.26.2