block: Enable qemu_open/close to work with fd sets
When qemu_open is passed a filename of the "/dev/fdset/nnn" format (where nnn is the fdset ID), an fd with matching access mode flags will be searched for within the specified monitor fd set. If the fd is found, a dup of the fd will be returned from qemu_open. Signed-off-by: Corey Bryant <coreyb@linux.vnet.ibm.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
2e1e79dae7
commit
adb696f3d8
6
Makefile
6
Makefile
@ -148,9 +148,6 @@ install-libcacard: libcacard.la
|
||||
$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C libcacard V="$(V)" TARGET_DIR="$*/" install-libcacard,)
|
||||
endif
|
||||
|
||||
vscclient$(EXESUF): $(libcacard-y) $(oslib-obj-y) $(trace-obj-y) qemu-timer-common.o libcacard/vscclient.o
|
||||
$(call quiet-command,$(CC) $(LDFLAGS) -o $@ $^ $(libcacard_libs) $(LIBS)," LINK $@")
|
||||
|
||||
######################################################################
|
||||
|
||||
qemu-img.o: qemu-img-cmds.h
|
||||
@ -166,6 +163,9 @@ qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y) $(block-obj-y)
|
||||
|
||||
qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o
|
||||
|
||||
vscclient$(EXESUF): $(libcacard-y) $(oslib-obj-y) $(trace-obj-y) $(tools-obj-y) qemu-timer-common.o libcacard/vscclient.o
|
||||
$(call quiet-command,$(CC) $(LDFLAGS) -o $@ $^ $(libcacard_libs) $(LIBS)," LINK $@")
|
||||
|
||||
fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/virtio-9p-marshal.o oslib-posix.o $(trace-obj-y)
|
||||
fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap
|
||||
|
||||
|
5
cutils.c
5
cutils.c
@ -383,6 +383,11 @@ int qemu_parse_fd(const char *param)
|
||||
return fd;
|
||||
}
|
||||
|
||||
int qemu_parse_fdset(const char *param)
|
||||
{
|
||||
return qemu_parse_fd(param);
|
||||
}
|
||||
|
||||
/* round down to the nearest power of 2*/
|
||||
int64_t pow2floor(int64_t value)
|
||||
{
|
||||
|
86
monitor.c
86
monitor.c
@ -154,6 +154,7 @@ typedef struct MonFdset MonFdset;
|
||||
struct MonFdset {
|
||||
int64_t id;
|
||||
QLIST_HEAD(, MonFdsetFd) fds;
|
||||
QLIST_HEAD(, MonFdsetFd) dup_fds;
|
||||
QLIST_ENTRY(MonFdset) next;
|
||||
};
|
||||
|
||||
@ -2398,7 +2399,7 @@ static void monitor_fdset_cleanup(MonFdset *mon_fdset)
|
||||
}
|
||||
}
|
||||
|
||||
if (QLIST_EMPTY(&mon_fdset->fds)) {
|
||||
if (QLIST_EMPTY(&mon_fdset->fds) && QLIST_EMPTY(&mon_fdset->dup_fds)) {
|
||||
QLIST_REMOVE(mon_fdset, next);
|
||||
g_free(mon_fdset);
|
||||
}
|
||||
@ -2555,6 +2556,89 @@ FdsetInfoList *qmp_query_fdsets(Error **errp)
|
||||
return fdset_list;
|
||||
}
|
||||
|
||||
int monitor_fdset_get_fd(int64_t fdset_id, int flags)
|
||||
{
|
||||
MonFdset *mon_fdset;
|
||||
MonFdsetFd *mon_fdset_fd;
|
||||
int mon_fd_flags;
|
||||
|
||||
#ifndef _WIN32
|
||||
QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
|
||||
if (mon_fdset->id != fdset_id) {
|
||||
continue;
|
||||
}
|
||||
QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) {
|
||||
mon_fd_flags = fcntl(mon_fdset_fd->fd, F_GETFL);
|
||||
if (mon_fd_flags == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((flags & O_ACCMODE) == (mon_fd_flags & O_ACCMODE)) {
|
||||
return mon_fdset_fd->fd;
|
||||
}
|
||||
}
|
||||
errno = EACCES;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd)
|
||||
{
|
||||
MonFdset *mon_fdset;
|
||||
MonFdsetFd *mon_fdset_fd_dup;
|
||||
|
||||
QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
|
||||
if (mon_fdset->id != fdset_id) {
|
||||
continue;
|
||||
}
|
||||
QLIST_FOREACH(mon_fdset_fd_dup, &mon_fdset->dup_fds, next) {
|
||||
if (mon_fdset_fd_dup->fd == dup_fd) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
mon_fdset_fd_dup = g_malloc0(sizeof(*mon_fdset_fd_dup));
|
||||
mon_fdset_fd_dup->fd = dup_fd;
|
||||
QLIST_INSERT_HEAD(&mon_fdset->dup_fds, mon_fdset_fd_dup, next);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int monitor_fdset_dup_fd_find_remove(int dup_fd, bool remove)
|
||||
{
|
||||
MonFdset *mon_fdset;
|
||||
MonFdsetFd *mon_fdset_fd_dup;
|
||||
|
||||
QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
|
||||
QLIST_FOREACH(mon_fdset_fd_dup, &mon_fdset->dup_fds, next) {
|
||||
if (mon_fdset_fd_dup->fd == dup_fd) {
|
||||
if (remove) {
|
||||
QLIST_REMOVE(mon_fdset_fd_dup, next);
|
||||
if (QLIST_EMPTY(&mon_fdset->dup_fds)) {
|
||||
monitor_fdset_cleanup(mon_fdset);
|
||||
}
|
||||
}
|
||||
return mon_fdset->id;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int monitor_fdset_dup_fd_find(int dup_fd)
|
||||
{
|
||||
return monitor_fdset_dup_fd_find_remove(dup_fd, false);
|
||||
}
|
||||
|
||||
int monitor_fdset_dup_fd_remove(int dup_fd)
|
||||
{
|
||||
return monitor_fdset_dup_fd_find_remove(dup_fd, true);
|
||||
}
|
||||
|
||||
/* mon_cmds and info_cmds would be sorted at runtime */
|
||||
static mon_cmd_t mon_cmds[] = {
|
||||
#include "hmp-commands.h"
|
||||
|
@ -87,4 +87,9 @@ int qmp_qom_set(Monitor *mon, const QDict *qdict, QObject **ret);
|
||||
|
||||
int qmp_qom_get(Monitor *mon, const QDict *qdict, QObject **ret);
|
||||
|
||||
int monitor_fdset_get_fd(int64_t fdset_id, int flags);
|
||||
int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd);
|
||||
int monitor_fdset_dup_fd_remove(int dup_fd);
|
||||
int monitor_fdset_dup_fd_find(int dup_fd);
|
||||
|
||||
#endif /* !MONITOR_H */
|
||||
|
111
osdep.c
111
osdep.c
@ -48,6 +48,7 @@ extern int madvise(caddr_t, size_t, int);
|
||||
#include "qemu-common.h"
|
||||
#include "trace.h"
|
||||
#include "qemu_socket.h"
|
||||
#include "monitor.h"
|
||||
|
||||
static bool fips_enabled = false;
|
||||
|
||||
@ -78,6 +79,66 @@ int qemu_madvise(void *addr, size_t len, int advice)
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
/*
|
||||
* Dups an fd and sets the flags
|
||||
*/
|
||||
static int qemu_dup_flags(int fd, int flags)
|
||||
{
|
||||
int ret;
|
||||
int serrno;
|
||||
int dup_flags;
|
||||
int setfl_flags;
|
||||
|
||||
#ifdef F_DUPFD_CLOEXEC
|
||||
ret = fcntl(fd, F_DUPFD_CLOEXEC, 0);
|
||||
#else
|
||||
ret = dup(fd);
|
||||
if (ret != -1) {
|
||||
qemu_set_cloexec(ret);
|
||||
}
|
||||
#endif
|
||||
if (ret == -1) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dup_flags = fcntl(ret, F_GETFL);
|
||||
if (dup_flags == -1) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((flags & O_SYNC) != (dup_flags & O_SYNC)) {
|
||||
errno = EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Set/unset flags that we can with fcntl */
|
||||
setfl_flags = O_APPEND | O_ASYNC | O_DIRECT | O_NOATIME | O_NONBLOCK;
|
||||
dup_flags &= ~setfl_flags;
|
||||
dup_flags |= (flags & setfl_flags);
|
||||
if (fcntl(ret, F_SETFL, dup_flags) == -1) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Truncate the file in the cases that open() would truncate it */
|
||||
if (flags & O_TRUNC ||
|
||||
((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))) {
|
||||
if (ftruncate(ret, 0) == -1) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
fail:
|
||||
serrno = errno;
|
||||
if (ret != -1) {
|
||||
close(ret);
|
||||
}
|
||||
errno = serrno;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Opens a file with FD_CLOEXEC set
|
||||
@ -87,6 +148,41 @@ int qemu_open(const char *name, int flags, ...)
|
||||
int ret;
|
||||
int mode = 0;
|
||||
|
||||
#ifndef _WIN32
|
||||
const char *fdset_id_str;
|
||||
|
||||
/* Attempt dup of fd from fd set */
|
||||
if (strstart(name, "/dev/fdset/", &fdset_id_str)) {
|
||||
int64_t fdset_id;
|
||||
int fd, dupfd;
|
||||
|
||||
fdset_id = qemu_parse_fdset(fdset_id_str);
|
||||
if (fdset_id == -1) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
fd = monitor_fdset_get_fd(fdset_id, flags);
|
||||
if (fd == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
dupfd = qemu_dup_flags(fd, flags);
|
||||
if (dupfd == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = monitor_fdset_dup_fd_add(fdset_id, dupfd);
|
||||
if (ret == -1) {
|
||||
close(dupfd);
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return dupfd;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (flags & O_CREAT) {
|
||||
va_list ap;
|
||||
|
||||
@ -109,6 +205,21 @@ int qemu_open(const char *name, int flags, ...)
|
||||
|
||||
int qemu_close(int fd)
|
||||
{
|
||||
int64_t fdset_id;
|
||||
|
||||
/* Close fd that was dup'd from an fdset */
|
||||
fdset_id = monitor_fdset_dup_fd_find(fd);
|
||||
if (fdset_id != -1) {
|
||||
int ret;
|
||||
|
||||
ret = close(fd);
|
||||
if (ret == 0) {
|
||||
monitor_fdset_dup_fd_remove(fd);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return close(fd);
|
||||
}
|
||||
|
||||
|
@ -167,6 +167,7 @@ int qemu_fls(int i);
|
||||
int qemu_fdatasync(int fd);
|
||||
int fcntl_setfl(int fd, int flag);
|
||||
int qemu_parse_fd(const char *param);
|
||||
int qemu_parse_fdset(const char *param);
|
||||
|
||||
/*
|
||||
* strtosz() suffixes used to specify the default treatment of an
|
||||
|
20
qemu-tool.c
20
qemu-tool.c
@ -62,6 +62,26 @@ void monitor_protocol_event(MonitorEvent event, QObject *data)
|
||||
{
|
||||
}
|
||||
|
||||
int monitor_fdset_get_fd(int64_t fdset_id, int flags)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int monitor_fdset_dup_fd_remove(int dup_fd)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int monitor_fdset_dup_fd_find(int dup_fd)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int64_t cpu_get_clock(void)
|
||||
{
|
||||
return qemu_get_clock_ns(rt_clock);
|
||||
|
20
qemu-user.c
20
qemu-user.c
@ -35,3 +35,23 @@ void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
|
||||
void monitor_set_error(Monitor *mon, QError *qerror)
|
||||
{
|
||||
}
|
||||
|
||||
int monitor_fdset_get_fd(int64_t fdset_id, int flags)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int monitor_fdset_dup_fd_remove(int dup_fd)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int monitor_fdset_dup_fd_find(int dup_fd)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ TARGETS=$(patsubst %-softmmu,%, $(filter %-softmmu,$(TARGET_DIRS)))
|
||||
QTEST_TARGETS=$(foreach TARGET,$(TARGETS), $(if $(check-qtest-$(TARGET)-y), $(TARGET),))
|
||||
check-qtest-$(CONFIG_POSIX)=$(foreach TARGET,$(TARGETS), $(check-qtest-$(TARGET)-y))
|
||||
|
||||
qtest-obj-y = tests/libqtest.o $(oslib-obj-y)
|
||||
qtest-obj-y = tests/libqtest.o $(oslib-obj-y) $(tools-obj-y)
|
||||
$(check-qtest-y): $(qtest-obj-y)
|
||||
|
||||
.PHONY: check-help
|
||||
|
Loading…
Reference in New Issue
Block a user