monitor: add lock to protect mon_fdsets

Introduce a new global big lock for mon_fdsets.  Take it where needed.

The monitor_fdset_get_fd() handling is a bit tricky: now we need to call
qemu_mutex_unlock() which might pollute errno, so we need to make sure
the correct errno be passed up to the callers.  To make things simpler,
we let monitor_fdset_get_fd() return the -errno directly when error
happens, then in qemu_open() we move it back into errno.

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
Message-Id: <20180608035511.7439-8-peterx@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
This commit is contained in:
Peter Xu 2018-06-08 11:55:11 +08:00 committed by Markus Armbruster
parent d32749deb6
commit 474514668b
3 changed files with 45 additions and 12 deletions

View File

@ -271,7 +271,10 @@ static QemuMutex monitor_lock;
static GHashTable *monitor_qapi_event_state; static GHashTable *monitor_qapi_event_state;
static QTAILQ_HEAD(mon_list, Monitor) mon_list; static QTAILQ_HEAD(mon_list, Monitor) mon_list;
/* Protects mon_fdsets */
static QemuMutex mon_fdsets_lock;
static QLIST_HEAD(mon_fdsets, MonFdset) mon_fdsets; static QLIST_HEAD(mon_fdsets, MonFdset) mon_fdsets;
static int mon_refcount; static int mon_refcount;
static mon_cmd_t mon_cmds[]; static mon_cmd_t mon_cmds[];
@ -2319,9 +2322,11 @@ static void monitor_fdsets_cleanup(void)
MonFdset *mon_fdset; MonFdset *mon_fdset;
MonFdset *mon_fdset_next; MonFdset *mon_fdset_next;
qemu_mutex_lock(&mon_fdsets_lock);
QLIST_FOREACH_SAFE(mon_fdset, &mon_fdsets, next, mon_fdset_next) { QLIST_FOREACH_SAFE(mon_fdset, &mon_fdsets, next, mon_fdset_next) {
monitor_fdset_cleanup(mon_fdset); monitor_fdset_cleanup(mon_fdset);
} }
qemu_mutex_unlock(&mon_fdsets_lock);
} }
AddfdInfo *qmp_add_fd(bool has_fdset_id, int64_t fdset_id, bool has_opaque, AddfdInfo *qmp_add_fd(bool has_fdset_id, int64_t fdset_id, bool has_opaque,
@ -2356,6 +2361,7 @@ void qmp_remove_fd(int64_t fdset_id, bool has_fd, int64_t fd, Error **errp)
MonFdsetFd *mon_fdset_fd; MonFdsetFd *mon_fdset_fd;
char fd_str[60]; char fd_str[60];
qemu_mutex_lock(&mon_fdsets_lock);
QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
if (mon_fdset->id != fdset_id) { if (mon_fdset->id != fdset_id) {
continue; continue;
@ -2375,10 +2381,12 @@ void qmp_remove_fd(int64_t fdset_id, bool has_fd, int64_t fd, Error **errp)
goto error; goto error;
} }
monitor_fdset_cleanup(mon_fdset); monitor_fdset_cleanup(mon_fdset);
qemu_mutex_unlock(&mon_fdsets_lock);
return; return;
} }
error: error:
qemu_mutex_unlock(&mon_fdsets_lock);
if (has_fd) { if (has_fd) {
snprintf(fd_str, sizeof(fd_str), "fdset-id:%" PRId64 ", fd:%" PRId64, snprintf(fd_str, sizeof(fd_str), "fdset-id:%" PRId64 ", fd:%" PRId64,
fdset_id, fd); fdset_id, fd);
@ -2394,6 +2402,7 @@ FdsetInfoList *qmp_query_fdsets(Error **errp)
MonFdsetFd *mon_fdset_fd; MonFdsetFd *mon_fdset_fd;
FdsetInfoList *fdset_list = NULL; FdsetInfoList *fdset_list = NULL;
qemu_mutex_lock(&mon_fdsets_lock);
QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
FdsetInfoList *fdset_info = g_malloc0(sizeof(*fdset_info)); FdsetInfoList *fdset_info = g_malloc0(sizeof(*fdset_info));
FdsetFdInfoList *fdsetfd_list = NULL; FdsetFdInfoList *fdsetfd_list = NULL;
@ -2423,6 +2432,7 @@ FdsetInfoList *qmp_query_fdsets(Error **errp)
fdset_info->next = fdset_list; fdset_info->next = fdset_list;
fdset_list = fdset_info; fdset_list = fdset_info;
} }
qemu_mutex_unlock(&mon_fdsets_lock);
return fdset_list; return fdset_list;
} }
@ -2435,6 +2445,7 @@ AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id,
MonFdsetFd *mon_fdset_fd; MonFdsetFd *mon_fdset_fd;
AddfdInfo *fdinfo; AddfdInfo *fdinfo;
qemu_mutex_lock(&mon_fdsets_lock);
if (has_fdset_id) { if (has_fdset_id) {
QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
/* Break if match found or match impossible due to ordering by ID */ /* Break if match found or match impossible due to ordering by ID */
@ -2455,6 +2466,7 @@ AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id,
if (fdset_id < 0) { if (fdset_id < 0) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "fdset-id", error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "fdset-id",
"a non-negative value"); "a non-negative value");
qemu_mutex_unlock(&mon_fdsets_lock);
return NULL; return NULL;
} }
/* Use specified fdset ID */ /* Use specified fdset ID */
@ -2505,16 +2517,21 @@ AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id,
fdinfo->fdset_id = mon_fdset->id; fdinfo->fdset_id = mon_fdset->id;
fdinfo->fd = mon_fdset_fd->fd; fdinfo->fd = mon_fdset_fd->fd;
qemu_mutex_unlock(&mon_fdsets_lock);
return fdinfo; return fdinfo;
} }
int monitor_fdset_get_fd(int64_t fdset_id, int flags) int monitor_fdset_get_fd(int64_t fdset_id, int flags)
{ {
#ifndef _WIN32 #ifdef _WIN32
return -ENOENT;
#else
MonFdset *mon_fdset; MonFdset *mon_fdset;
MonFdsetFd *mon_fdset_fd; MonFdsetFd *mon_fdset_fd;
int mon_fd_flags; int mon_fd_flags;
int ret;
qemu_mutex_lock(&mon_fdsets_lock);
QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
if (mon_fdset->id != fdset_id) { if (mon_fdset->id != fdset_id) {
continue; continue;
@ -2522,20 +2539,24 @@ int monitor_fdset_get_fd(int64_t fdset_id, int flags)
QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) { QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) {
mon_fd_flags = fcntl(mon_fdset_fd->fd, F_GETFL); mon_fd_flags = fcntl(mon_fdset_fd->fd, F_GETFL);
if (mon_fd_flags == -1) { if (mon_fd_flags == -1) {
return -1; ret = -errno;
goto out;
} }
if ((flags & O_ACCMODE) == (mon_fd_flags & O_ACCMODE)) { if ((flags & O_ACCMODE) == (mon_fd_flags & O_ACCMODE)) {
return mon_fdset_fd->fd; ret = mon_fdset_fd->fd;
goto out;
} }
} }
errno = EACCES; ret = -EACCES;
return -1; goto out;
} }
#endif ret = -ENOENT;
errno = ENOENT; out:
return -1; qemu_mutex_unlock(&mon_fdsets_lock);
return ret;
#endif
} }
int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd) int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd)
@ -2543,20 +2564,25 @@ int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd)
MonFdset *mon_fdset; MonFdset *mon_fdset;
MonFdsetFd *mon_fdset_fd_dup; MonFdsetFd *mon_fdset_fd_dup;
qemu_mutex_lock(&mon_fdsets_lock);
QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
if (mon_fdset->id != fdset_id) { if (mon_fdset->id != fdset_id) {
continue; continue;
} }
QLIST_FOREACH(mon_fdset_fd_dup, &mon_fdset->dup_fds, next) { QLIST_FOREACH(mon_fdset_fd_dup, &mon_fdset->dup_fds, next) {
if (mon_fdset_fd_dup->fd == dup_fd) { if (mon_fdset_fd_dup->fd == dup_fd) {
return -1; goto err;
} }
} }
mon_fdset_fd_dup = g_malloc0(sizeof(*mon_fdset_fd_dup)); mon_fdset_fd_dup = g_malloc0(sizeof(*mon_fdset_fd_dup));
mon_fdset_fd_dup->fd = dup_fd; mon_fdset_fd_dup->fd = dup_fd;
QLIST_INSERT_HEAD(&mon_fdset->dup_fds, mon_fdset_fd_dup, next); QLIST_INSERT_HEAD(&mon_fdset->dup_fds, mon_fdset_fd_dup, next);
qemu_mutex_unlock(&mon_fdsets_lock);
return 0; return 0;
} }
err:
qemu_mutex_unlock(&mon_fdsets_lock);
return -1; return -1;
} }
@ -2565,6 +2591,7 @@ static int monitor_fdset_dup_fd_find_remove(int dup_fd, bool remove)
MonFdset *mon_fdset; MonFdset *mon_fdset;
MonFdsetFd *mon_fdset_fd_dup; MonFdsetFd *mon_fdset_fd_dup;
qemu_mutex_lock(&mon_fdsets_lock);
QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
QLIST_FOREACH(mon_fdset_fd_dup, &mon_fdset->dup_fds, next) { QLIST_FOREACH(mon_fdset_fd_dup, &mon_fdset->dup_fds, next) {
if (mon_fdset_fd_dup->fd == dup_fd) { if (mon_fdset_fd_dup->fd == dup_fd) {
@ -2573,13 +2600,17 @@ static int monitor_fdset_dup_fd_find_remove(int dup_fd, bool remove)
if (QLIST_EMPTY(&mon_fdset->dup_fds)) { if (QLIST_EMPTY(&mon_fdset->dup_fds)) {
monitor_fdset_cleanup(mon_fdset); monitor_fdset_cleanup(mon_fdset);
} }
return -1; goto err;
} else { } else {
qemu_mutex_unlock(&mon_fdsets_lock);
return mon_fdset->id; return mon_fdset->id;
} }
} }
} }
} }
err:
qemu_mutex_unlock(&mon_fdsets_lock);
return -1; return -1;
} }
@ -4519,6 +4550,7 @@ void monitor_init_globals(void)
monitor_qapi_event_init(); monitor_qapi_event_init();
sortcmdlist(); sortcmdlist();
qemu_mutex_init(&monitor_lock); qemu_mutex_init(&monitor_lock);
qemu_mutex_init(&mon_fdsets_lock);
monitor_iothread_init(); monitor_iothread_init();
} }

View File

@ -14,7 +14,7 @@ int monitor_fdset_dup_fd_find(int dup_fd)
int monitor_fdset_get_fd(int64_t fdset_id, int flags) int monitor_fdset_get_fd(int64_t fdset_id, int flags)
{ {
return -1; return -ENOENT;
} }
void monitor_fdset_dup_fd_remove(int dupfd) void monitor_fdset_dup_fd_remove(int dupfd)

View File

@ -302,7 +302,8 @@ int qemu_open(const char *name, int flags, ...)
} }
fd = monitor_fdset_get_fd(fdset_id, flags); fd = monitor_fdset_get_fd(fdset_id, flags);
if (fd == -1) { if (fd < 0) {
errno = -fd;
return -1; return -1;
} }