* Longstanding chardev race condition fix (Berto)

* Cleanups and tests from the Meson POC (Marc-André, myself)
 * Coalesced range cleanup (Peter)
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.22 (GNU/Linux)
 
 iQEcBAABAgAGBQJdXX8PAAoJEL/70l94x66DkR4H/1Phk6zuTQfHISBXGACjDkFS
 kbVq2WE6gQXwqmbf/04mM/DZzsi9bCsHFlGhf7mFQoq9g2ywm7kgtjF7kiRewlqh
 YZYSLLEoEVKpZRxC8kQbbbZ/tfYDM7ejnKMPFK6ibNiiN7acuKJuY8z18OLg4PEA
 V5LfuaGPjsx98NUAuU6bHRs5ZDCL25DzBQ9pdcE5wkJ2pVJXpP6UBafN55l8Clzq
 PzuuNnP18QyuqbdRVm5YrY+0nUeDCdlU2clCC3/H9rS57Ts/z3gocs71VT8GKqIa
 ppNRg3wVADXtfql3MkpnmvZefx+QK6DguAAiKR4CtPax7Xx6WoA4DwtMKfsLHsY=
 =RwuS
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging

* Longstanding chardev race condition fix (Berto)
* Cleanups and tests from the Meson POC (Marc-André, myself)
* Coalesced range cleanup (Peter)

# gpg: Signature made Wed 21 Aug 2019 18:27:43 BST
# gpg:                using RSA key BFFBD25F78C7AE83
# gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" [full]
# gpg:                 aka "Paolo Bonzini <pbonzini@redhat.com>" [full]
# Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4  E2F7 7E15 100C CD36 69B1
#      Subkey fingerprint: F133 3857 4B66 2389 866C  7682 BFFB D25F 78C7 AE83

* remotes/bonzini/tags/for-upstream:
  char-socket: Lock tcp_chr_disconnect() and socket_reconnect_timeout()
  main-loop: Fix GSource leak in qio_task_thread_worker()
  memory: Fix up memory_region_{add|del}_coalescing
  memory: Remove has_coalesced_range counter
  memory: Split zones when do coalesced_io_del()
  memory: Refactor memory_region_clear_coalescing
  minikconf: don't print CONFIG_FOO=n lines
  configure: remove AUTOCONF_HOST
  tests: add module loading test
  module: return success on module load
  module: use g_hash_table_add()
  configure: define CONFIG_TOOLS here
  qemu-ga: clean up TOOLS variable

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2019-08-22 13:13:35 +01:00
commit 8109234808
13 changed files with 180 additions and 71 deletions

View File

@ -84,8 +84,7 @@ endif
include $(SRC_PATH)/rules.mak
# notempy and lor are defined in rules.mak
CONFIG_TOOLS := $(call notempty,$(TOOLS))
# lor is defined in rules.mak
CONFIG_BLOCK := $(call lor,$(CONFIG_SOFTMMU),$(CONFIG_TOOLS))
# Create QEMU_PKGVERSION and FULL_VERSION strings
@ -681,7 +680,7 @@ clean: recurse-clean
! -path ./roms/edk2/BaseTools/Source/Python/UPT/Dll/sqlite3.dll \
-exec rm {} +
rm -f $(edk2-decompressed)
rm -f $(filter-out %.tlb,$(TOOLS)) $(HELPERS-y) qemu-ga$(EXESUF) TAGS cscope.* *.pod *~ */*~
rm -f $(filter-out %.tlb,$(TOOLS)) $(HELPERS-y) TAGS cscope.* *.pod *~ */*~
rm -f fsdev/*.pod scsi/*.pod
rm -f qemu-img-cmds.h
rm -f ui/shader/*-vert.h ui/shader/*-frag.h
@ -809,7 +808,7 @@ ifdef CONFIG_POSIX
$(INSTALL_DATA) docs/interop/qemu-qmp-ref.7 "$(DESTDIR)$(mandir)/man7"
$(INSTALL_DATA) docs/qemu-block-drivers.7 "$(DESTDIR)$(mandir)/man7"
$(INSTALL_DATA) docs/qemu-cpu-models.7 "$(DESTDIR)$(mandir)/man7"
ifneq ($(TOOLS),)
ifeq ($(CONFIG_TOOLS),y)
$(INSTALL_DATA) qemu-img.1 "$(DESTDIR)$(mandir)/man1"
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man8"
$(INSTALL_DATA) qemu-nbd.8 "$(DESTDIR)$(mandir)/man8"
@ -845,7 +844,7 @@ install: all $(if $(BUILD_DOCS),install-doc) install-datadir install-localstated
$(if $(INSTALL_BLOBS),$(edk2-decompressed)) \
recurse-install
ifneq ($(TOOLS),)
$(call install-prog,$(subst qemu-ga,qemu-ga$(EXESUF),$(TOOLS)),$(DESTDIR)$(bindir))
$(call install-prog,$(TOOLS),$(DESTDIR)$(bindir))
endif
ifneq ($(CONFIG_MODULES),)
$(INSTALL_DIR) "$(DESTDIR)$(qemu_moddir)"

View File

@ -150,7 +150,7 @@ static void tcp_chr_accept(QIONetListener *listener,
void *opaque);
static int tcp_chr_read_poll(void *opaque);
static void tcp_chr_disconnect(Chardev *chr);
static void tcp_chr_disconnect_locked(Chardev *chr);
/* Called with chr_write_lock held. */
static int tcp_chr_write(Chardev *chr, const uint8_t *buf, int len)
@ -174,7 +174,7 @@ static int tcp_chr_write(Chardev *chr, const uint8_t *buf, int len)
if (ret < 0 && errno != EAGAIN) {
if (tcp_chr_read_poll(chr) <= 0) {
tcp_chr_disconnect(chr);
tcp_chr_disconnect_locked(chr);
return len;
} /* else let the read handler finish it properly */
}
@ -469,8 +469,9 @@ static void update_disconnected_filename(SocketChardev *s)
/* NB may be called even if tcp_chr_connect has not been
* reached, due to TLS or telnet initialization failure,
* so can *not* assume s->state == TCP_CHARDEV_STATE_CONNECTED
* This must be called with chr->chr_write_lock held.
*/
static void tcp_chr_disconnect(Chardev *chr)
static void tcp_chr_disconnect_locked(Chardev *chr)
{
SocketChardev *s = SOCKET_CHARDEV(chr);
bool emit_close = s->state == TCP_CHARDEV_STATE_CONNECTED;
@ -490,6 +491,13 @@ static void tcp_chr_disconnect(Chardev *chr)
}
}
static void tcp_chr_disconnect(Chardev *chr)
{
qemu_mutex_lock(&chr->chr_write_lock);
tcp_chr_disconnect_locked(chr);
qemu_mutex_unlock(&chr->chr_write_lock);
}
static gboolean tcp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
{
Chardev *chr = CHARDEV(opaque);
@ -1131,8 +1139,10 @@ static gboolean socket_reconnect_timeout(gpointer opaque)
Chardev *chr = CHARDEV(opaque);
SocketChardev *s = SOCKET_CHARDEV(opaque);
qemu_mutex_lock(&chr->chr_write_lock);
g_source_unref(s->reconnect_timer);
s->reconnect_timer = NULL;
qemu_mutex_unlock(&chr->chr_write_lock);
if (chr->be_open) {
return false;

10
configure vendored
View File

@ -6129,7 +6129,7 @@ if [ "$guest_agent" != "no" ]; then
if [ "$softmmu" = no -a "$want_tools" = no ] ; then
guest_agent=no
elif [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" -o "$mingw32" = "yes" ] ; then
tools="qemu-ga $tools"
tools="qemu-ga\$(EXESUF) $tools"
guest_agent=yes
elif [ "$guest_agent" != yes ]; then
guest_agent=no
@ -6614,6 +6614,9 @@ fi
if test "$profiler" = "yes" ; then
echo "CONFIG_PROFILER=y" >> $config_host_mak
fi
if test "$want_tools" = "yes" ; then
echo "CONFIG_TOOLS=y" >> $config_host_mak
fi
if test "$slirp" != "no"; then
echo "CONFIG_SLIRP=y" >> $config_host_mak
echo "CONFIG_SMBD_COMMAND=\"$smbd\"" >> $config_host_mak
@ -7360,11 +7363,6 @@ if test "$sparse" = "yes" ; then
echo "HOST_CC := REAL_CC=\"\$(HOST_CC)\" cgcc" >> $config_host_mak
echo "QEMU_CFLAGS += -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-non-pointer-null" >> $config_host_mak
fi
if test "$cross_prefix" != ""; then
echo "AUTOCONF_HOST := --host=${cross_prefix%-}" >> $config_host_mak
else
echo "AUTOCONF_HOST := " >> $config_host_mak
fi
echo "LDFLAGS=$LDFLAGS" >> $config_host_mak
echo "LDFLAGS_NOPIE=$LDFLAGS_NOPIE" >> $config_host_mak
echo "QEMU_LDFLAGS=$QEMU_LDFLAGS" >> $config_host_mak

View File

@ -65,6 +65,6 @@ void register_module_init(void (*fn)(void), module_init_type type);
void register_dso_module_init(void (*fn)(void), module_init_type type);
void module_call_init(module_init_type type);
void module_load_one(const char *prefix, const char *lib_name);
bool module_load_one(const char *prefix, const char *lib_name);
#endif

View File

@ -136,6 +136,7 @@ static gpointer qio_task_thread_worker(gpointer opaque)
qio_task_thread_result, task, NULL);
g_source_attach(task->thread->completion,
task->thread->context);
g_source_unref(task->thread->completion);
trace_qio_task_thread_source_attach(task, task->thread->completion);
qemu_cond_signal(&task->thread_cond);

103
memory.c
View File

@ -217,7 +217,6 @@ struct FlatRange {
bool romd_mode;
bool readonly;
bool nonvolatile;
int has_coalesced_range;
};
#define FOR_EACH_FLAT_RANGE(var, view) \
@ -654,7 +653,6 @@ static void render_memory_region(FlatView *view,
fr.romd_mode = mr->romd_mode;
fr.readonly = readonly;
fr.nonvolatile = nonvolatile;
fr.has_coalesced_range = 0;
/* Render the region itself into any gaps left by the current view. */
for (i = 0; i < view->nr && int128_nz(remain); ++i) {
@ -855,46 +853,55 @@ static void address_space_update_ioeventfds(AddressSpace *as)
flatview_unref(view);
}
/*
* Notify the memory listeners about the coalesced IO change events of
* range `cmr'. Only the part that has intersection of the specified
* FlatRange will be sent.
*/
static void flat_range_coalesced_io_notify(FlatRange *fr, AddressSpace *as,
CoalescedMemoryRange *cmr, bool add)
{
AddrRange tmp;
tmp = addrrange_shift(cmr->addr,
int128_sub(fr->addr.start,
int128_make64(fr->offset_in_region)));
if (!addrrange_intersects(tmp, fr->addr)) {
return;
}
tmp = addrrange_intersection(tmp, fr->addr);
if (add) {
MEMORY_LISTENER_UPDATE_REGION(fr, as, Forward, coalesced_io_add,
int128_get64(tmp.start),
int128_get64(tmp.size));
} else {
MEMORY_LISTENER_UPDATE_REGION(fr, as, Reverse, coalesced_io_del,
int128_get64(tmp.start),
int128_get64(tmp.size));
}
}
static void flat_range_coalesced_io_del(FlatRange *fr, AddressSpace *as)
{
if (!fr->has_coalesced_range) {
return;
}
CoalescedMemoryRange *cmr;
if (--fr->has_coalesced_range > 0) {
return;
QTAILQ_FOREACH(cmr, &fr->mr->coalesced, link) {
flat_range_coalesced_io_notify(fr, as, cmr, false);
}
MEMORY_LISTENER_UPDATE_REGION(fr, as, Reverse, coalesced_io_del,
int128_get64(fr->addr.start),
int128_get64(fr->addr.size));
}
static void flat_range_coalesced_io_add(FlatRange *fr, AddressSpace *as)
{
MemoryRegion *mr = fr->mr;
CoalescedMemoryRange *cmr;
AddrRange tmp;
if (QTAILQ_EMPTY(&mr->coalesced)) {
return;
}
if (fr->has_coalesced_range++) {
return;
}
QTAILQ_FOREACH(cmr, &mr->coalesced, link) {
tmp = addrrange_shift(cmr->addr,
int128_sub(fr->addr.start,
int128_make64(fr->offset_in_region)));
if (!addrrange_intersects(tmp, fr->addr)) {
continue;
}
tmp = addrrange_intersection(tmp, fr->addr);
MEMORY_LISTENER_UPDATE_REGION(fr, as, Forward, coalesced_io_add,
int128_get64(tmp.start),
int128_get64(tmp.size));
flat_range_coalesced_io_notify(fr, as, cmr, true);
}
}
@ -2236,27 +2243,26 @@ void memory_region_ram_resize(MemoryRegion *mr, ram_addr_t newsize, Error **errp
qemu_ram_resize(mr->ram_block, newsize, errp);
}
static void memory_region_update_coalesced_range_as(MemoryRegion *mr, AddressSpace *as)
/*
* Call proper memory listeners about the change on the newly
* added/removed CoalescedMemoryRange.
*/
static void memory_region_update_coalesced_range(MemoryRegion *mr,
CoalescedMemoryRange *cmr,
bool add)
{
AddressSpace *as;
FlatView *view;
FlatRange *fr;
view = address_space_get_flatview(as);
FOR_EACH_FLAT_RANGE(fr, view) {
if (fr->mr == mr) {
flat_range_coalesced_io_del(fr, as);
flat_range_coalesced_io_add(fr, as);
}
}
flatview_unref(view);
}
static void memory_region_update_coalesced_range(MemoryRegion *mr)
{
AddressSpace *as;
QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
memory_region_update_coalesced_range_as(mr, as);
view = address_space_get_flatview(as);
FOR_EACH_FLAT_RANGE(fr, view) {
if (fr->mr == mr) {
flat_range_coalesced_io_notify(fr, as, cmr, add);
}
}
flatview_unref(view);
}
}
@ -2274,14 +2280,17 @@ void memory_region_add_coalescing(MemoryRegion *mr,
cmr->addr = addrrange_make(int128_make64(offset), int128_make64(size));
QTAILQ_INSERT_TAIL(&mr->coalesced, cmr, link);
memory_region_update_coalesced_range(mr);
memory_region_update_coalesced_range(mr, cmr, true);
memory_region_set_flush_coalesced(mr);
}
void memory_region_clear_coalescing(MemoryRegion *mr)
{
CoalescedMemoryRange *cmr;
bool updated = false;
if (QTAILQ_EMPTY(&mr->coalesced)) {
return;
}
qemu_flush_coalesced_mmio_buffer();
mr->flush_coalesced_mmio = false;
@ -2289,12 +2298,8 @@ void memory_region_clear_coalescing(MemoryRegion *mr)
while (!QTAILQ_EMPTY(&mr->coalesced)) {
cmr = QTAILQ_FIRST(&mr->coalesced);
QTAILQ_REMOVE(&mr->coalesced, cmr, link);
memory_region_update_coalesced_range(mr, cmr, false);
g_free(cmr);
updated = true;
}
if (updated) {
memory_region_update_coalesced_range(mr);
}
}

View File

@ -661,6 +661,15 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
qtest_send_prefix(chr);
qtest_sendf(chr, "OK %"PRIi64"\n",
(int64_t)qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
} else if (strcmp(words[0], "module_load") == 0) {
g_assert(words[1] && words[2]);
qtest_send_prefix(chr);
if (module_load_one(words[1], words[2])) {
qtest_sendf(chr, "OK\n");
} else {
qtest_sendf(chr, "FAIL\n");
}
} else if (qtest_enabled() && strcmp(words[0], "clock_set") == 0) {
int64_t ns;
int ret;

View File

@ -702,8 +702,8 @@ if __name__ == '__main__':
config = data.compute_config()
for key in sorted(config.keys()):
if key not in external_vars:
print ('CONFIG_%s=%s' % (key, ('y' if config[key] else 'n')))
if key not in external_vars and config[key]:
print ('CONFIG_%s=y' % key)
deps = open(argv[2], 'w')
for fname in data.previously_included:

View File

@ -149,6 +149,7 @@ check-block-$(call land,$(CONFIG_POSIX),$(CONFIG_SOFTMMU)) += tests/check-block.
check-qtest-generic-y += tests/qmp-test$(EXESUF)
check-qtest-generic-y += tests/qmp-cmd-test$(EXESUF)
check-qtest-generic-$(CONFIG_MODULES) += tests/modules-test$(EXESUF)
check-qtest-generic-y += tests/device-introspect-test$(EXESUF)
check-qtest-generic-y += tests/cdrom-test$(EXESUF)

View File

@ -811,6 +811,12 @@ bool qtest_get_irq(QTestState *s, int num)
return s->irq_level[num];
}
void qtest_module_load(QTestState *s, const char *prefix, const char *libname)
{
qtest_sendf(s, "module_load %s %s\n", prefix, libname);
qtest_rsp(s, 0);
}
static int64_t qtest_clock_rsp(QTestState *s)
{
gchar **words;

View File

@ -262,6 +262,8 @@ char *qtest_hmp(QTestState *s, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
char *qtest_vhmp(QTestState *s, const char *fmt, va_list ap)
GCC_FMT_ATTR(2, 0);
void qtest_module_load(QTestState *s, const char *prefix, const char *libname);
/**
* qtest_get_irq:
* @s: #QTestState instance to operate on.

71
tests/modules-test.c Normal file
View File

@ -0,0 +1,71 @@
#include "qemu/osdep.h"
#include "libqtest.h"
static void test_modules_load(const void *data)
{
QTestState *qts;
const char **args = data;
qts = qtest_init(NULL);
qtest_module_load(qts, args[0], args[1]);
qtest_quit(qts);
}
int main(int argc, char *argv[])
{
const char *modules[] = {
#ifdef CONFIG_CURL
"block-", "curl",
#endif
#ifdef CONFIG_GLUSTERFS
"block-", "gluster",
#endif
#ifdef CONFIG_LIBISCSI
"block-", "iscsi",
#endif
#ifdef CONFIG_LIBNFS
"block-", "nfs",
#endif
#ifdef CONFIG_LIBSSH
"block-", "ssh",
#endif
#ifdef CONFIG_RBD
"block-", "rbd",
#endif
#ifdef CONFIG_AUDIO_ALSA
"audio-", "alsa",
#endif
#ifdef CONFIG_AUDIO_OSS
"audio-", "oss",
#endif
#ifdef CONFIG_AUDIO_PA
"audio-", "pa",
#endif
#ifdef CONFIG_AUDIO_SDL
"audio-", "sdl",
#endif
#ifdef CONFIG_CURSES
"ui-", "curses",
#endif
#if defined(CONFIG_GTK) && defined(CONFIG_VTE)
"ui-", "gtk",
#endif
#ifdef CONFIG_SDL
"ui-", "sdl",
#endif
#if defined(CONFIG_SPICE) && defined(CONFIG_GIO)
"ui-", "spice-app",
#endif
};
int i;
g_test_init(&argc, &argv, NULL);
for (i = 0; i < G_N_ELEMENTS(modules); i += 2) {
char *testname = g_strdup_printf("/module/load/%s", modules[i + 1]);
qtest_add_data_func(testname, modules + i, test_modules_load);
g_free(testname);
}
return g_test_run();
}

View File

@ -156,8 +156,10 @@ out:
}
#endif
void module_load_one(const char *prefix, const char *lib_name)
bool module_load_one(const char *prefix, const char *lib_name)
{
bool success = false;
#ifdef CONFIG_MODULES
char *fname = NULL;
char *exec_dir;
@ -170,7 +172,7 @@ void module_load_one(const char *prefix, const char *lib_name)
if (!g_module_supported()) {
fprintf(stderr, "Module is not supported by system.\n");
return;
return false;
}
if (!loaded_modules) {
@ -179,11 +181,10 @@ void module_load_one(const char *prefix, const char *lib_name)
module_name = g_strdup_printf("%s%s", prefix, lib_name);
if (g_hash_table_lookup(loaded_modules, module_name)) {
if (!g_hash_table_add(loaded_modules, module_name)) {
g_free(module_name);
return;
return true;
}
g_hash_table_insert(loaded_modules, module_name, module_name);
exec_dir = qemu_get_exec_dir();
search_dir = getenv("QEMU_MODULE_DIR");
@ -206,13 +207,19 @@ void module_load_one(const char *prefix, const char *lib_name)
fname = NULL;
/* Try loading until loaded a module file */
if (!ret) {
success = true;
break;
}
}
if (!success) {
g_hash_table_remove(loaded_modules, module_name);
}
for (i = 0; i < n_dirs; i++) {
g_free(dirs[i]);
}
#endif
return success;
}