diff options
Diffstat (limited to 'util')
-rw-r--r-- | util/aio-win32.c | 12 | ||||
-rw-r--r-- | util/osdep.c | 104 | ||||
-rw-r--r-- | util/oslib-posix.c | 2 | ||||
-rw-r--r-- | util/rcu.c | 55 |
4 files changed, 140 insertions, 33 deletions
diff --git a/util/aio-win32.c b/util/aio-win32.c index 953c56ab48..49bd90e62e 100644 --- a/util/aio-win32.c +++ b/util/aio-win32.c @@ -37,6 +37,16 @@ struct AioHandler { static void aio_remove_fd_handler(AioContext *ctx, AioHandler *node) { + /* + * If the GSource is in the process of being destroyed then + * g_source_remove_poll() causes an assertion failure. Skip + * removal in that case, because glib cleans up its state during + * destruction anyway. + */ + if (!g_source_is_destroyed(&ctx->source)) { + g_source_remove_poll(&ctx->source, &node->pfd); + } + /* If aio_poll is in progress, just mark the node as deleted */ if (qemu_lockcnt_count(&ctx->list_lock)) { node->deleted = 1; @@ -139,8 +149,6 @@ void aio_set_event_notifier(AioContext *ctx, /* Are we deleting the fd handler? */ if (!io_notify) { if (node) { - g_source_remove_poll(&ctx->source, &node->pfd); - aio_remove_fd_handler(ctx, node); } } else { diff --git a/util/osdep.c b/util/osdep.c index e50dc2214e..66d01b9160 100644 --- a/util/osdep.c +++ b/util/osdep.c @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #include "qemu/osdep.h" +#include "qapi/error.h" /* Needed early for CONFIG_BSD etc. */ @@ -122,7 +123,7 @@ static int fcntl_op_getlk = -1; /* * Dups an fd and sets the flags */ -static int qemu_dup_flags(int fd, int flags) +int qemu_dup_flags(int fd, int flags) { int ret; int serrno; @@ -279,13 +280,27 @@ int qemu_lock_fd_test(int fd, int64_t start, int64_t len, bool exclusive) } #endif +static int qemu_open_cloexec(const char *name, int flags, mode_t mode) +{ + int ret; +#ifdef O_CLOEXEC + ret = open(name, flags | O_CLOEXEC, mode); +#else + ret = open(name, flags, mode); + if (ret >= 0) { + qemu_set_cloexec(ret); + } +#endif + return ret; +} + /* * Opens a file with FD_CLOEXEC set */ -int qemu_open(const char *name, int flags, ...) +static int +qemu_open_internal(const char *name, int flags, mode_t mode, Error **errp) { int ret; - int mode = 0; #ifndef _WIN32 const char *fdset_id_str; @@ -293,29 +308,19 @@ int qemu_open(const char *name, int flags, ...) /* Attempt dup of fd from fd set */ if (strstart(name, "/dev/fdset/", &fdset_id_str)) { int64_t fdset_id; - int fd, dupfd; + int dupfd; fdset_id = qemu_parse_fdset(fdset_id_str); if (fdset_id == -1) { + error_setg(errp, "Could not parse fdset %s", name); errno = EINVAL; return -1; } - fd = monitor_fdset_get_fd(fdset_id, flags); - if (fd < 0) { - errno = -fd; - return -1; - } - - dupfd = qemu_dup_flags(fd, flags); + dupfd = monitor_fdset_dup_fd_add(fdset_id, flags); if (dupfd == -1) { - return -1; - } - - ret = monitor_fdset_dup_fd_add(fdset_id, dupfd); - if (ret == -1) { - close(dupfd); - errno = EINVAL; + error_setg_errno(errp, errno, "Could not dup FD for %s flags %x", + name, flags); return -1; } @@ -323,22 +328,61 @@ int qemu_open(const char *name, int flags, ...) } #endif - if (flags & O_CREAT) { - va_list ap; + ret = qemu_open_cloexec(name, flags, mode); - va_start(ap, flags); - mode = va_arg(ap, int); - va_end(ap); + if (ret == -1) { + const char *action = flags & O_CREAT ? "create" : "open"; +#ifdef O_DIRECT + /* Give more helpful error message for O_DIRECT */ + if (errno == EINVAL && (flags & O_DIRECT)) { + ret = open(name, flags & ~O_DIRECT, mode); + if (ret != -1) { + close(ret); + error_setg(errp, "Could not %s '%s': " + "filesystem does not support O_DIRECT", + action, name); + errno = EINVAL; /* restore first open()'s errno */ + return -1; + } + } +#endif /* O_DIRECT */ + error_setg_errno(errp, errno, "Could not %s '%s'", + action, name); } -#ifdef O_CLOEXEC - ret = open(name, flags | O_CLOEXEC, mode); -#else - ret = open(name, flags, mode); - if (ret >= 0) { - qemu_set_cloexec(ret); + return ret; +} + + +int qemu_open(const char *name, int flags, Error **errp) +{ + assert(!(flags & O_CREAT)); + + return qemu_open_internal(name, flags, 0, errp); +} + + +int qemu_create(const char *name, int flags, mode_t mode, Error **errp) +{ + assert(!(flags & O_CREAT)); + + return qemu_open_internal(name, flags | O_CREAT, mode, errp); +} + + +int qemu_open_old(const char *name, int flags, ...) +{ + va_list ap; + mode_t mode = 0; + int ret; + + va_start(ap, flags); + if (flags & O_CREAT) { + mode = va_arg(ap, int); } -#endif + va_end(ap); + + ret = qemu_open_internal(name, flags, mode, NULL); #ifdef O_DIRECT if (ret == -1 && errno == EINVAL && (flags & O_DIRECT)) { diff --git a/util/oslib-posix.c b/util/oslib-posix.c index ad8001a4ad..f5f676f079 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -125,7 +125,7 @@ bool qemu_write_pidfile(const char *path, Error **errp) .l_len = 0, }; - fd = qemu_open(path, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR); + fd = qemu_open_old(path, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR); if (fd == -1) { error_setg_errno(errp, errno, "Cannot open pid file"); return false; diff --git a/util/rcu.c b/util/rcu.c index 60a37f72c3..c4fefa9333 100644 --- a/util/rcu.c +++ b/util/rcu.c @@ -293,6 +293,61 @@ void call_rcu1(struct rcu_head *node, void (*func)(struct rcu_head *node)) qemu_event_set(&rcu_call_ready_event); } + +struct rcu_drain { + struct rcu_head rcu; + QemuEvent drain_complete_event; +}; + +static void drain_rcu_callback(struct rcu_head *node) +{ + struct rcu_drain *event = (struct rcu_drain *)node; + qemu_event_set(&event->drain_complete_event); +} + +/* + * This function ensures that all pending RCU callbacks + * on the current thread are done executing + + * drops big qemu lock during the wait to allow RCU thread + * to process the callbacks + * + */ + +void drain_call_rcu(void) +{ + struct rcu_drain rcu_drain; + bool locked = qemu_mutex_iothread_locked(); + + memset(&rcu_drain, 0, sizeof(struct rcu_drain)); + qemu_event_init(&rcu_drain.drain_complete_event, false); + + if (locked) { + qemu_mutex_unlock_iothread(); + } + + + /* + * RCU callbacks are invoked in the same order as in which they + * are registered, thus we can be sure that when 'drain_rcu_callback' + * is called, all RCU callbacks that were registered on this thread + * prior to calling this function are completed. + * + * Note that since we have only one global queue of the RCU callbacks, + * we also end up waiting for most of RCU callbacks that were registered + * on the other threads, but this is a side effect that shoudn't be + * assumed. + */ + + call_rcu1(&rcu_drain.rcu, drain_rcu_callback); + qemu_event_wait(&rcu_drain.drain_complete_event); + + if (locked) { + qemu_mutex_lock_iothread(); + } + +} + void rcu_register_thread(void) { assert(rcu_reader.ctr == 0); |