Skip to content

Commit

Permalink
block: Enable qemu_open/close to work with fd sets
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Corey Bryant authored and kevmw committed Aug 15, 2012
1 parent 2e1e79d commit adb696f
Show file tree
Hide file tree
Showing 9 changed files with 251 additions and 5 deletions.
6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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

Expand Down
5 changes: 5 additions & 0 deletions cutils.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
86 changes: 85 additions & 1 deletion monitor.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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"
Expand Down
5 changes: 5 additions & 0 deletions monitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 111 additions & 0 deletions osdep.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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
Expand All @@ -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;

Expand All @@ -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);
}

Expand Down
1 change: 1 addition & 0 deletions qemu-common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
20 changes: 20 additions & 0 deletions qemu-tool.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
20 changes: 20 additions & 0 deletions qemu-user.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
2 changes: 1 addition & 1 deletion tests/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit adb696f

Please sign in to comment.