qemu: add monitor functions for handling file descriptors

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@redhat.com>
Reviewed-by: Laine Stump <laine@redhat.com>
This commit is contained in:
Jonathon Jongsma 2020-10-14 12:08:28 -05:00 committed by Laine Stump
parent 0b1a05ffb5
commit b8998cc670
4 changed files with 319 additions and 0 deletions

View File

@ -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,

View File

@ -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);

View File

@ -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)

View File

@ -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);