Merge remote-tracking branch 'remotes/stefanha/tags/block-pull-request' into staging

Pull request

This pull request contains a virtio-blk/scsi performance optimization, event
loop scalability improvements, and a qtest-based device fuzzing framework.  I
am including the fuzzing patches because I have reviewed them and Thomas Huth
is currently away on leave.

# gpg: Signature made Sat 22 Feb 2020 08:50:05 GMT
# gpg:                using RSA key 8695A8BFD3F97CDAAC35775A9CA4ABB381AB73C8
# gpg: Good signature from "Stefan Hajnoczi <stefanha@redhat.com>" [full]
# gpg:                 aka "Stefan Hajnoczi <stefanha@gmail.com>" [full]
# Primary key fingerprint: 8695 A8BF D3F9 7CDA AC35  775A 9CA4 ABB3 81AB 73C8

* remotes/stefanha/tags/block-pull-request: (31 commits)
  fuzz: add documentation to docs/devel/
  fuzz: add virtio-scsi fuzz target
  fuzz: add virtio-net fuzz target
  fuzz: add i440fx fuzz targets
  fuzz: add configure flag --enable-fuzzing
  fuzz: add target/fuzz makefile rules
  fuzz: add support for qos-assisted fuzz targets
  fuzz: support for fork-based fuzzing.
  main: keep rcu_atfork callback enabled for qtest
  exec: keep ram block across fork when using qtest
  fuzz: add fuzzer skeleton
  libqos: move useful qos-test funcs to qos_external
  libqos: split qos-test and libqos makefile vars
  libqos: rename i2c_send and i2c_recv
  qtest: add in-process incoming command handler
  libqtest: make bufwrite rely on the TransportOps
  libqtest: add a layer of abstraction to send/recv
  qtest: add qtest_server_send abstraction
  fuzz: add FUZZ_TARGET module type
  module: check module wasn't already initialized
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell
2020-02-24 11:38:54 +00:00
51 changed files with 2366 additions and 401 deletions
+10 -1
View File
@@ -2031,7 +2031,8 @@ F: include/qemu/main-loop.h
F: include/sysemu/runstate.h
F: util/main-loop.c
F: util/qemu-timer.c
F: vl.c
F: softmmu/vl.c
F: softmmu/main.c
F: qapi/run-state.json
Human Monitor (HMP)
@@ -2183,6 +2184,14 @@ F: qtest.c
F: accel/qtest.c
F: tests/qtest/
Device Fuzzing
M: Alexander Bulekov <alxndr@bu.edu>
R: Paolo Bonzini <pbonzini@redhat.com>
R: Bandan Das <bsd@redhat.com>
R: Stefan Hajnoczi <stefanha@redhat.com>
S: Maintained
F: tests/qtest/fuzz/
Register API
M: Alistair Francis <alistair@alistair23.me>
S: Maintained
+14 -1
View File
@@ -477,7 +477,7 @@ config-host.h-timestamp: config-host.mak
qemu-options.def: $(SRC_PATH)/qemu-options.hx $(SRC_PATH)/scripts/hxtool
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$@")
TARGET_DIRS_RULES := $(foreach t, all clean install, $(addsuffix /$(t), $(TARGET_DIRS)))
TARGET_DIRS_RULES := $(foreach t, all fuzz clean install, $(addsuffix /$(t), $(TARGET_DIRS)))
SOFTMMU_ALL_RULES=$(filter %-softmmu/all, $(TARGET_DIRS_RULES))
$(SOFTMMU_ALL_RULES): $(authz-obj-y)
@@ -490,6 +490,15 @@ ifdef DECOMPRESS_EDK2_BLOBS
$(SOFTMMU_ALL_RULES): $(edk2-decompressed)
endif
SOFTMMU_FUZZ_RULES=$(filter %-softmmu/fuzz, $(TARGET_DIRS_RULES))
$(SOFTMMU_FUZZ_RULES): $(authz-obj-y)
$(SOFTMMU_FUZZ_RULES): $(block-obj-y)
$(SOFTMMU_FUZZ_RULES): $(chardev-obj-y)
$(SOFTMMU_FUZZ_RULES): $(crypto-obj-y)
$(SOFTMMU_FUZZ_RULES): $(io-obj-y)
$(SOFTMMU_FUZZ_RULES): config-all-devices.mak
$(SOFTMMU_FUZZ_RULES): $(edk2-decompressed)
.PHONY: $(TARGET_DIRS_RULES)
# The $(TARGET_DIRS_RULES) are of the form SUBDIR/GOAL, so that
# $(dir $@) yields the sub-directory, and $(notdir $@) yields the sub-goal
@@ -540,6 +549,9 @@ subdir-slirp: slirp/all
$(filter %/all, $(TARGET_DIRS_RULES)): libqemuutil.a $(common-obj-y) \
$(qom-obj-y)
$(filter %/fuzz, $(TARGET_DIRS_RULES)): libqemuutil.a $(common-obj-y) \
$(qom-obj-y) $(crypto-user-obj-$(CONFIG_USER_ONLY))
ROM_DIRS = $(addprefix pc-bios/, $(ROMS))
ROM_DIRS_RULES=$(foreach t, all clean, $(addsuffix /$(t), $(ROM_DIRS)))
# Only keep -O and -g cflags
@@ -549,6 +561,7 @@ $(ROM_DIRS_RULES):
.PHONY: recurse-all recurse-clean recurse-install
recurse-all: $(addsuffix /all, $(TARGET_DIRS) $(ROM_DIRS))
recurse-fuzz: $(addsuffix /fuzz, $(TARGET_DIRS) $(ROM_DIRS))
recurse-clean: $(addsuffix /clean, $(TARGET_DIRS) $(ROM_DIRS))
recurse-install: $(addsuffix /install, $(TARGET_DIRS))
$(addsuffix /install, $(TARGET_DIRS)): all
-2
View File
@@ -58,8 +58,6 @@ common-obj-y += ui/
common-obj-m += ui/
common-obj-y += dma-helpers.o
common-obj-y += vl.o
vl.o-cflags := $(GPROF_CFLAGS) $(SDL_CFLAGS)
common-obj-$(CONFIG_TPM) += tpm.o
common-obj-y += backends/
+18 -1
View File
@@ -160,6 +160,7 @@ obj-y += qapi/
obj-y += memory.o
obj-y += memory_mapping.o
obj-y += migration/ram.o
obj-y += softmmu/
LIBS := $(libs_softmmu) $(LIBS)
# Hardware support
@@ -202,7 +203,7 @@ endif
COMMON_LDADDS = ../libqemuutil.a
# build either PROG or PROGW
$(QEMU_PROG_BUILD): $(all-obj-y) $(COMMON_LDADDS)
$(QEMU_PROG_BUILD): $(all-obj-y) $(COMMON_LDADDS) $(softmmu-main-y)
$(call LINK, $(filter-out %.mak, $^))
ifdef CONFIG_DARWIN
$(call quiet-command,Rez -append $(SRC_PATH)/pc-bios/qemu.rsrc -o $@,"REZ","$(TARGET_DIR)$@")
@@ -227,6 +228,22 @@ ifdef CONFIG_TRACE_SYSTEMTAP
rm -f *.stp
endif
ifdef CONFIG_FUZZ
include $(SRC_PATH)/tests/qtest/fuzz/Makefile.include
include $(SRC_PATH)/tests/qtest/Makefile.include
fuzz: fuzz-vars
fuzz-vars: QEMU_CFLAGS := $(FUZZ_CFLAGS) $(QEMU_CFLAGS)
fuzz-vars: QEMU_LDFLAGS := $(FUZZ_LDFLAGS) $(QEMU_LDFLAGS)
fuzz-vars: $(QEMU_PROG_FUZZ)
dummy := $(call unnest-vars,, fuzz-obj-y)
$(QEMU_PROG_FUZZ): config-devices.mak $(all-obj-y) $(COMMON_LDADDS) $(fuzz-obj-y)
$(call LINK, $(filter-out %.mak, $^))
endif
install: all
ifneq ($(PROGS),)
$(call install-prog,$(PROGS),$(DESTDIR)$(bindir))
+1 -4
View File
@@ -2636,10 +2636,7 @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
static void bdrv_detach_child(BdrvChild *child)
{
if (child->next.le_prev) {
QLIST_REMOVE(child, next);
child->next.le_prev = NULL;
}
QLIST_SAFE_REMOVE(child, next);
bdrv_replace_child(child, NULL);
+1 -3
View File
@@ -216,9 +216,7 @@ static void char_spice_finalize(Object *obj)
vmc_unregister_interface(s);
if (s->next.le_prev) {
QLIST_REMOVE(s, next);
}
QLIST_SAFE_REMOVE(s, next);
g_free((char *)s->sin.subtype);
g_free((char *)s->sin.portname);
Vendored
+39
View File
@@ -505,6 +505,7 @@ debug_mutex="no"
libpmem=""
default_devices="yes"
plugins="no"
fuzzing="no"
supported_cpu="no"
supported_os="no"
@@ -635,6 +636,15 @@ int main(void) { return 0; }
EOF
}
write_c_fuzzer_skeleton() {
cat > $TMPC <<EOF
#include <stdint.h>
#include <sys/types.h>
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { return 0; }
EOF
}
if check_define __linux__ ; then
targetos="Linux"
elif check_define _WIN32 ; then
@@ -1558,6 +1568,10 @@ for opt do
;;
--disable-containers) use_containers="no"
;;
--enable-fuzzing) fuzzing=yes
;;
--disable-fuzzing) fuzzing=no
;;
*)
echo "ERROR: unknown option $opt"
echo "Try '$0 --help' for more information"
@@ -6072,6 +6086,15 @@ EOF
fi
fi
##########################################
# checks for fuzzer
if test "$fuzzing" = "yes" ; then
write_c_fuzzer_skeleton
if compile_prog "$CPU_CFLAGS -Werror -fsanitize=address,fuzzer" ""; then
have_fuzzer=yes
fi
fi
##########################################
# check for libpmem
@@ -6666,6 +6689,7 @@ echo "libpmem support $libpmem"
echo "libudev $libudev"
echo "default devices $default_devices"
echo "plugin support $plugins"
echo "fuzzing support $fuzzing"
if test "$supported_cpu" = "no"; then
echo
@@ -7504,6 +7528,16 @@ fi
if test "$sheepdog" = "yes" ; then
echo "CONFIG_SHEEPDOG=y" >> $config_host_mak
fi
if test "$fuzzing" = "yes" ; then
if test "$have_fuzzer" = "yes"; then
FUZZ_LDFLAGS=" -fsanitize=address,fuzzer"
FUZZ_CFLAGS=" -fsanitize=address,fuzzer"
CFLAGS=" -fsanitize=address,fuzzer-no-link"
else
error_exit "Your compiler doesn't support -fsanitize=address,fuzzer"
exit 1
fi
fi
if test "$plugins" = "yes" ; then
echo "CONFIG_PLUGIN=y" >> $config_host_mak
@@ -7605,6 +7639,11 @@ if test "$libudev" != "no"; then
echo "CONFIG_LIBUDEV=y" >> $config_host_mak
echo "LIBUDEV_LIBS=$libudev_libs" >> $config_host_mak
fi
if test "$fuzzing" != "no"; then
echo "CONFIG_FUZZ=y" >> $config_host_mak
echo "FUZZ_CFLAGS=$FUZZ_CFLAGS" >> $config_host_mak
echo "FUZZ_LDFLAGS=$FUZZ_LDFLAGS" >> $config_host_mak
fi
if test "$edk2_blobs" = "yes" ; then
echo "DECOMPRESS_EDK2_BLOBS=y" >> $config_host_mak
+116
View File
@@ -0,0 +1,116 @@
= Fuzzing =
== Introduction ==
This document describes the virtual-device fuzzing infrastructure in QEMU and
how to use it to implement additional fuzzers.
== Basics ==
Fuzzing operates by passing inputs to an entry point/target function. The
fuzzer tracks the code coverage triggered by the input. Based on these
findings, the fuzzer mutates the input and repeats the fuzzing.
To fuzz QEMU, we rely on libfuzzer. Unlike other fuzzers such as AFL, libfuzzer
is an _in-process_ fuzzer. For the developer, this means that it is their
responsibility to ensure that state is reset between fuzzing-runs.
== Building the fuzzers ==
NOTE: If possible, build a 32-bit binary. When forking, the 32-bit fuzzer is
much faster, since the page-map has a smaller size. This is due to the fact that
AddressSanitizer mmaps ~20TB of memory, as part of its detection. This results
in a large page-map, and a much slower fork().
To build the fuzzers, install a recent version of clang:
Configure with (substitute the clang binaries with the version you installed):
CC=clang-8 CXX=clang++-8 /path/to/configure --enable-fuzzing
Fuzz targets are built similarly to system/softmmu:
make i386-softmmu/fuzz
This builds ./i386-softmmu/qemu-fuzz-i386
The first option to this command is: --fuzz_taget=FUZZ_NAME
To list all of the available fuzzers run qemu-fuzz-i386 with no arguments.
eg:
./i386-softmmu/qemu-fuzz-i386 --fuzz-target=virtio-net-fork-fuzz
Internally, libfuzzer parses all arguments that do not begin with "--".
Information about these is available by passing -help=1
Now the only thing left to do is wait for the fuzzer to trigger potential
crashes.
== Adding a new fuzzer ==
Coverage over virtual devices can be improved by adding additional fuzzers.
Fuzzers are kept in tests/qtest/fuzz/ and should be added to
tests/qtest/fuzz/Makefile.include
Fuzzers can rely on both qtest and libqos to communicate with virtual devices.
1. Create a new source file. For example ``tests/qtest/fuzz/foo-device-fuzz.c``.
2. Write the fuzzing code using the libqtest/libqos API. See existing fuzzers
for reference.
3. Register the fuzzer in ``tests/fuzz/Makefile.include`` by appending the
corresponding object to fuzz-obj-y
Fuzzers can be more-or-less thought of as special qtest programs which can
modify the qtest commands and/or qtest command arguments based on inputs
provided by libfuzzer. Libfuzzer passes a byte array and length. Commonly the
fuzzer loops over the byte-array interpreting it as a list of qtest commands,
addresses, or values.
= Implementation Details =
== The Fuzzer's Lifecycle ==
The fuzzer has two entrypoints that libfuzzer calls. libfuzzer provides it's
own main(), which performs some setup, and calls the entrypoints:
LLVMFuzzerInitialize: called prior to fuzzing. Used to initialize all of the
necessary state
LLVMFuzzerTestOneInput: called for each fuzzing run. Processes the input and
resets the state at the end of each run.
In more detail:
LLVMFuzzerInitialize parses the arguments to the fuzzer (must start with two
dashes, so they are ignored by libfuzzer main()). Currently, the arguments
select the fuzz target. Then, the qtest client is initialized. If the target
requires qos, qgraph is set up and the QOM/LIBQOS modules are initialized.
Then the QGraph is walked and the QEMU cmd_line is determined and saved.
After this, the vl.c:qemu__main is called to set up the guest. There are
target-specific hooks that can be called before and after qemu_main, for
additional setup(e.g. PCI setup, or VM snapshotting).
LLVMFuzzerTestOneInput: Uses qtest/qos functions to act based on the fuzz
input. It is also responsible for manually calling the main loop/main_loop_wait
to ensure that bottom halves are executed and any cleanup required before the
next input.
Since the same process is reused for many fuzzing runs, QEMU state needs to
be reset at the end of each run. There are currently two implemented
options for resetting state:
1. Reboot the guest between runs.
Pros: Straightforward and fast for simple fuzz targets.
Cons: Depending on the device, does not reset all device state. If the
device requires some initialization prior to being ready for fuzzing
(common for QOS-based targets), this initialization needs to be done after
each reboot.
Example target: i440fx-qtest-reboot-fuzz
2. Run each test case in a separate forked process and copy the coverage
information back to the parent. This is fairly similar to AFL's "deferred"
fork-server mode [3]
Pros: Relatively fast. Devices only need to be initialized once. No need
to do slow reboots or vmloads.
Cons: Not officially supported by libfuzzer. Does not work well for devices
that rely on dedicated threads.
Example target: virtio-net-fork-fuzz
+10 -2
View File
@@ -35,6 +35,7 @@
#include "sysemu/kvm.h"
#include "sysemu/sysemu.h"
#include "sysemu/tcg.h"
#include "sysemu/qtest.h"
#include "qemu/timer.h"
#include "qemu/config-file.h"
#include "qemu/error-report.h"
@@ -2305,8 +2306,15 @@ static void ram_block_add(RAMBlock *new_block, Error **errp, bool shared)
if (new_block->host) {
qemu_ram_setup_dump(new_block->host, new_block->max_length);
qemu_madvise(new_block->host, new_block->max_length, QEMU_MADV_HUGEPAGE);
/* MADV_DONTFORK is also needed by KVM in absence of synchronous MMU */
qemu_madvise(new_block->host, new_block->max_length, QEMU_MADV_DONTFORK);
/*
* MADV_DONTFORK is also needed by KVM in absence of synchronous MMU
* Configure it unless the machine is a qtest server, in which case
* KVM is not used and it may be forked (eg for fuzzing purposes).
*/
if (!qtest_enabled()) {
qemu_madvise(new_block->host, new_block->max_length,
QEMU_MADV_DONTFORK);
}
ram_block_notify_add(new_block->host, new_block->max_length);
}
}
+1 -1
View File
@@ -1272,7 +1272,7 @@ static Property virtio_blk_properties[] = {
DEFINE_PROP_BIT("request-merging", VirtIOBlock, conf.request_merging, 0,
true),
DEFINE_PROP_UINT16("num-queues", VirtIOBlock, conf.num_queues, 1),
DEFINE_PROP_UINT16("queue-size", VirtIOBlock, conf.queue_size, 128),
DEFINE_PROP_UINT16("queue-size", VirtIOBlock, conf.queue_size, 256),
DEFINE_PROP_BOOL("seg-max-adjust", VirtIOBlock, conf.seg_max_adjust, true),
DEFINE_PROP_LINK("iothread", VirtIOBlock, conf.iothread, TYPE_IOTHREAD,
IOThread *),
+2
View File
@@ -28,6 +28,8 @@
#include "hw/mem/nvdimm.h"
GlobalProperty hw_compat_4_2[] = {
{ "virtio-blk-device", "queue-size", "128"},
{ "virtio-scsi-device", "virtqueue_size", "128"},
{ "virtio-blk-device", "x-enable-wce-if-config-wce", "off" },
{ "virtio-blk-device", "seg-max-adjust", "off"},
{ "virtio-scsi-device", "seg_max_adjust", "off"},
+1 -1
View File
@@ -965,7 +965,7 @@ static void virtio_scsi_device_unrealize(DeviceState *dev, Error **errp)
static Property virtio_scsi_properties[] = {
DEFINE_PROP_UINT32("num_queues", VirtIOSCSI, parent_obj.conf.num_queues, 1),
DEFINE_PROP_UINT32("virtqueue_size", VirtIOSCSI,
parent_obj.conf.virtqueue_size, 128),
parent_obj.conf.virtqueue_size, 256),
DEFINE_PROP_BOOL("seg_max_adjust", VirtIOSCSI,
parent_obj.conf.seg_max_adjust, true),
DEFINE_PROP_UINT32("max_sectors", VirtIOSCSI, parent_obj.conf.max_sectors,
+23 -3
View File
@@ -42,6 +42,7 @@ void qemu_aio_unref(void *p);
void qemu_aio_ref(void *p);
typedef struct AioHandler AioHandler;
typedef QLIST_HEAD(, AioHandler) AioHandlerList;
typedef void QEMUBHFunc(void *opaque);
typedef bool AioPollFn(void *opaque);
typedef void IOHandler(void *opaque);
@@ -51,6 +52,19 @@ struct ThreadPool;
struct LinuxAioState;
struct LuringState;
/*
* Each aio_bh_poll() call carves off a slice of the BH list, so that newly
* scheduled BHs are not processed until the next aio_bh_poll() call. All
* active aio_bh_poll() calls chain their slices together in a list, so that
* nested aio_bh_poll() calls process all scheduled bottom halves.
*/
typedef QSLIST_HEAD(, QEMUBH) BHList;
typedef struct BHListSlice BHListSlice;
struct BHListSlice {
BHList bh_list;
QSIMPLEQ_ENTRY(BHListSlice) next;
};
struct AioContext {
GSource source;
@@ -58,7 +72,10 @@ struct AioContext {
QemuRecMutex lock;
/* The list of registered AIO handlers. Protected by ctx->list_lock. */
QLIST_HEAD(, AioHandler) aio_handlers;
AioHandlerList aio_handlers;
/* The list of AIO handlers to be deleted. Protected by ctx->list_lock. */
AioHandlerList deleted_aio_handlers;
/* Used to avoid unnecessary event_notifier_set calls in aio_notify;
* accessed with atomic primitives. If this field is 0, everything
@@ -91,8 +108,11 @@ struct AioContext {
*/
QemuLockCnt list_lock;
/* Anchor of the list of Bottom Halves belonging to the context */
struct QEMUBH *first_bh;
/* Bottom Halves pending aio_bh_poll() processing */
BHList bh_list;
/* Chained BH list slices for each nested aio_bh_poll() call */
QSIMPLEQ_HEAD(, BHListSlice) bh_slice_list;
/* Used by aio_notify.
*
+3 -1
View File
@@ -46,6 +46,7 @@ typedef enum {
MODULE_INIT_TRACE,
MODULE_INIT_XEN_BACKEND,
MODULE_INIT_LIBQOS,
MODULE_INIT_FUZZ_TARGET,
MODULE_INIT_MAX
} module_init_type;
@@ -56,7 +57,8 @@ typedef enum {
#define xen_backend_init(function) module_init(function, \
MODULE_INIT_XEN_BACKEND)
#define libqos_init(function) module_init(function, MODULE_INIT_LIBQOS)
#define fuzz_target_init(function) module_init(function, \
MODULE_INIT_FUZZ_TARGET)
#define block_module_load_one(lib) module_load_one("block-", lib)
#define ui_module_load_one(lib) module_load_one("ui-", lib)
#define audio_module_load_one(lib) module_load_one("audio-", lib)
+30 -2
View File
@@ -144,6 +144,23 @@ struct { \
*(elm)->field.le_prev = (elm)->field.le_next; \
} while (/*CONSTCOND*/0)
/*
* Like QLIST_REMOVE() but safe to call when elm is not in a list
*/
#define QLIST_SAFE_REMOVE(elm, field) do { \
if ((elm)->field.le_prev != NULL) { \
if ((elm)->field.le_next != NULL) \
(elm)->field.le_next->field.le_prev = \
(elm)->field.le_prev; \
*(elm)->field.le_prev = (elm)->field.le_next; \
(elm)->field.le_next = NULL; \
(elm)->field.le_prev = NULL; \
} \
} while (/*CONSTCOND*/0)
/* Is elm in a list? */
#define QLIST_IS_INSERTED(elm, field) ((elm)->field.le_prev != NULL)
#define QLIST_FOREACH(var, head, field) \
for ((var) = ((head)->lh_first); \
(var); \
@@ -211,9 +228,20 @@ struct { \
(head)->slh_first = (head)->slh_first->field.sle_next; \
} while (/*CONSTCOND*/0)
#define QSLIST_REMOVE_AFTER(slistelm, field) do { \
#define QSLIST_REMOVE_AFTER(slistelm, field) do { \
(slistelm)->field.sle_next = \
QSLIST_NEXT(QSLIST_NEXT((slistelm), field), field); \
QSLIST_NEXT(QSLIST_NEXT((slistelm), field), field); \
} while (/*CONSTCOND*/0)
#define QSLIST_REMOVE(head, elm, type, field) do { \
if ((head)->slh_first == (elm)) { \
QSLIST_REMOVE_HEAD((head), field); \
} else { \
struct type *curelm = (head)->slh_first; \
while (curelm->field.sle_next != (elm)) \
curelm = curelm->field.sle_next; \
curelm->field.sle_next = curelm->field.sle_next->field.sle_next; \
} \
} while (/*CONSTCOND*/0)
#define QSLIST_FOREACH(var, head, field) \
+47
View File
@@ -262,6 +262,53 @@ extern "C" {
(var) && ((next) = atomic_rcu_read(&(var)->field.tqe_next), 1); \
(var) = (next))
/*
* RCU singly-linked list
*/
/* Singly-linked list access methods */
#define QSLIST_EMPTY_RCU(head) (atomic_read(&(head)->slh_first) == NULL)
#define QSLIST_FIRST_RCU(head) atomic_rcu_read(&(head)->slh_first)
#define QSLIST_NEXT_RCU(elm, field) atomic_rcu_read(&(elm)->field.sle_next)
/* Singly-linked list functions */
#define QSLIST_INSERT_HEAD_RCU(head, elm, field) do { \
(elm)->field.sle_next = (head)->slh_first; \
atomic_rcu_set(&(head)->slh_first, (elm)); \
} while (/*CONSTCOND*/0)
#define QSLIST_INSERT_AFTER_RCU(head, listelm, elm, field) do { \
(elm)->field.sle_next = (listelm)->field.sle_next; \
atomic_rcu_set(&(listelm)->field.sle_next, (elm)); \
} while (/*CONSTCOND*/0)
#define QSLIST_REMOVE_HEAD_RCU(head, field) do { \
atomic_set(&(head)->slh_first, (head)->slh_first->field.sle_next); \
} while (/*CONSTCOND*/0)
#define QSLIST_REMOVE_RCU(head, elm, type, field) do { \
if ((head)->slh_first == (elm)) { \
QSLIST_REMOVE_HEAD_RCU((head), field); \
} else { \
struct type *curr = (head)->slh_first; \
while (curr->field.sle_next != (elm)) { \
curr = curr->field.sle_next; \
} \
atomic_set(&curr->field.sle_next, \
curr->field.sle_next->field.sle_next); \
} \
} while (/*CONSTCOND*/0)
#define QSLIST_FOREACH_RCU(var, head, field) \
for ((var) = atomic_rcu_read(&(head)->slh_first); \
(var); \
(var) = atomic_rcu_read(&(var)->field.sle_next))
#define QSLIST_FOREACH_SAFE_RCU(var, head, field, next) \
for ((var) = atomic_rcu_read(&(head)->slh_first); \
(var) && ((next) = atomic_rcu_read(&(var)->field.sle_next), 1); \
(var) = (next))
#ifdef __cplusplus
}
#endif
+4
View File
@@ -26,4 +26,8 @@ bool qtest_driver(void);
void qtest_server_init(const char *qtest_chrdev, const char *qtest_log, Error **errp);
void qtest_server_set_send_handler(void (*send)(void *, const char *),
void *opaque);
void qtest_server_inproc_recv(void *opaque, const char *buf);
#endif
+4
View File
@@ -115,6 +115,10 @@ QemuOpts *qemu_get_machine_opts(void);
bool defaults_enabled(void);
void qemu_init(int argc, char **argv, char **envp);
void qemu_main_loop(void);
void qemu_cleanup(void);
extern QemuOptsList qemu_legacy_drive_opts;
extern QemuOptsList qemu_common_drive_opts;
extern QemuOptsList qemu_drive_opts;
+29 -2
View File
@@ -43,6 +43,8 @@ static GString *inbuf;
static int irq_levels[MAX_IRQ];
static qemu_timeval start_time;
static bool qtest_opened;
static void (*qtest_server_send)(void*, const char*);
static void *qtest_server_send_opaque;
#define FMT_timeval "%ld.%06ld"
@@ -229,8 +231,10 @@ static void GCC_FMT_ATTR(1, 2) qtest_log_send(const char *fmt, ...)
va_end(ap);
}
static void do_qtest_send(CharBackend *chr, const char *str, size_t len)
static void qtest_server_char_be_send(void *opaque, const char *str)
{
size_t len = strlen(str);
CharBackend* chr = (CharBackend *)opaque;
qemu_chr_fe_write_all(chr, (uint8_t *)str, len);
if (qtest_log_fp && qtest_opened) {
fprintf(qtest_log_fp, "%s", str);
@@ -239,7 +243,7 @@ static void do_qtest_send(CharBackend *chr, const char *str, size_t len)
static void qtest_send(CharBackend *chr, const char *str)
{
do_qtest_send(chr, str, strlen(str));
qtest_server_send(qtest_server_send_opaque, str);
}
static void GCC_FMT_ATTR(2, 3) qtest_sendf(CharBackend *chr,
@@ -784,9 +788,32 @@ void qtest_server_init(const char *qtest_chrdev, const char *qtest_log, Error **
qemu_chr_fe_set_echo(&qtest_chr, true);
inbuf = g_string_new("");
if (!qtest_server_send) {
qtest_server_set_send_handler(qtest_server_char_be_send, &qtest_chr);
}
}
void qtest_server_set_send_handler(void (*send)(void*, const char*), void *opaque)
{
qtest_server_send = send;
qtest_server_send_opaque = opaque;
}
bool qtest_driver(void)
{
return qtest_chr.chr != NULL;
}
void qtest_server_inproc_recv(void *dummy, const char *buf)
{
static GString *gstr;
if (!gstr) {
gstr = g_string_new(NULL);
}
g_string_append(gstr, buf);
if (gstr->str[gstr->len - 1] == '\n') {
qtest_process_inbuf(NULL, gstr);
g_string_truncate(gstr, 0);
}
}
+1 -1
View File
@@ -462,7 +462,7 @@ sub top_of_kernel_tree {
my @tree_check = (
"COPYING", "MAINTAINERS", "Makefile",
"README.rst", "docs", "VERSION",
"vl.c"
"linux-user", "softmmu"
);
foreach my $check (@tree_check) {

Some files were not shown because too many files have changed in this diff Show More