Merge remote-tracking branch 'remotes/nvme/tags/nvme-next-pull-request' into staging
hw/nvme fixes
* new PMR test (Gollu Appalanaidu)
* pmr/sgl mapping fix (Padmakar Kalghatgi)
* hotplug fixes (me)
* mmio out-of-bound read fix (me)
* big-endian host fixes (me)
# gpg: Signature made Mon 26 Jul 2021 20:18:12 BST
# gpg: using RSA key 522833AA75E2DCE6A24766C04DE1AF316D4F0DE9
# gpg: Good signature from "Klaus Jensen <its@irrelevant.dk>" [unknown]
# gpg: aka "Klaus Jensen <k.jensen@samsung.com>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg: There is no indication that the signature belongs to the owner.
# Primary key fingerprint: DDCA 4D9C 9EF9 31CC 3468 4272 63D5 6FC5 E55D A838
# Subkey fingerprint: 5228 33AA 75E2 DCE6 A247 66C0 4DE1 AF31 6D4F 0DE9
* remotes/nvme/tags/nvme-next-pull-request:
tests/qtest/nvme-test: add mmio read test
hw/nvme: fix mmio read
hw/nvme: fix out-of-bounds reads
hw/nvme: use symbolic names for registers
hw/nvme: split pmrmsc register into upper and lower
hw/nvme: fix controller hot unplugging
tests/qtest/nvme-test: add persistent memory region test
hw/nvme: error handling for too many mappings
hw/nvme: unregister controller with subsystem at exit
hw/nvme: mark nvme-subsys non-hotpluggable
hw/nvme: remove NvmeCtrl parameter from ns setup/check functions
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
index fc895cf..e5c0ccd 100644
--- a/accel/tcg/cpu-exec.c
+++ b/accel/tcg/cpu-exec.c
@@ -834,7 +834,7 @@
/* Ensure global icount has gone forward */
icount_update(cpu);
/* Refill decrementer and continue execution. */
- insns_left = MIN(CF_COUNT_MASK, cpu->icount_budget);
+ insns_left = MIN(0xffff, cpu->icount_budget);
cpu_neg(cpu)->icount_decr.u16.low = insns_left;
cpu->icount_extra = cpu->icount_budget - insns_left;
@@ -843,7 +843,9 @@
* execute we need to ensure we find/generate a TB with exactly
* insns_left instructions in it.
*/
- if (!cpu->icount_extra && insns_left > 0 && insns_left < tb->icount) {
+ if (insns_left > 0 && insns_left < tb->icount) {
+ assert(insns_left <= CF_COUNT_MASK);
+ assert(cpu->icount_extra == 0);
cpu->cflags_next_tb = (tb->cflags & ~CF_COUNT_MASK) | insns_left;
}
#endif
@@ -853,7 +855,6 @@
int cpu_exec(CPUState *cpu)
{
- CPUClass *cc = CPU_GET_CLASS(cpu);
int ret;
SyncClocks sc = { 0 };
@@ -887,19 +888,14 @@
* that we support, but is still unfixed in clang:
* https://bugs.llvm.org/show_bug.cgi?id=21183
*
- * Reload essential local variables here for those compilers.
+ * Reload an essential local variable here for those compilers.
* Newer versions of gcc would complain about this code (-Wclobbered),
* so we only perform the workaround for clang.
*/
cpu = current_cpu;
- cc = CPU_GET_CLASS(cpu);
#else
- /*
- * Non-buggy compilers preserve these locals; assert that
- * they have the correct value.
- */
+ /* Non-buggy compilers preserve this; assert the correct value. */
g_assert(cpu == current_cpu);
- g_assert(cc == CPU_GET_CLASS(cpu));
#endif
#ifndef CONFIG_SOFTMMU
diff --git a/block/nvme.c b/block/nvme.c
index 2b5421e..e8dbbc2 100644
--- a/block/nvme.c
+++ b/block/nvme.c
@@ -1030,7 +1030,29 @@
r = qemu_vfio_dma_map(s->vfio,
qiov->iov[i].iov_base,
len, true, &iova);
+ if (r == -ENOSPC) {
+ /*
+ * In addition to the -ENOMEM error, the VFIO_IOMMU_MAP_DMA
+ * ioctl returns -ENOSPC to signal the user exhausted the DMA
+ * mappings available for a container since Linux kernel commit
+ * 492855939bdb ("vfio/type1: Limit DMA mappings per container",
+ * April 2019, see CVE-2019-3882).
+ *
+ * This block driver already handles this error path by checking
+ * for the -ENOMEM error, so we directly replace -ENOSPC by
+ * -ENOMEM. Beside, -ENOSPC has a specific meaning for blockdev
+ * coroutines: it triggers BLOCKDEV_ON_ERROR_ENOSPC and
+ * BLOCK_ERROR_ACTION_STOP which stops the VM, asking the operator
+ * to add more storage to the blockdev. Not something we can do
+ * easily with an IOMMU :)
+ */
+ r = -ENOMEM;
+ }
if (r == -ENOMEM && retry) {
+ /*
+ * We exhausted the DMA mappings available for our container:
+ * recycle the volatile IOVA mappings.
+ */
retry = false;
trace_nvme_dma_flush_queue_wait(s);
if (s->dma_map_count) {
diff --git a/hw/audio/adlib.c b/hw/audio/adlib.c
index 42d50d2..5f979b1 100644
--- a/hw/audio/adlib.c
+++ b/hw/audio/adlib.c
@@ -186,7 +186,7 @@
static void adlib_callback (void *opaque, int free)
{
AdlibState *s = opaque;
- int samples, net = 0, to_play, written;
+ int samples, to_play, written;
samples = free >> SHIFT;
if (!(s->active && s->enabled) || !samples) {
@@ -219,7 +219,6 @@
written = write_audio (s, samples);
if (written) {
- net += written;
samples -= written;
s->pos = (s->pos + written) % s->samples;
}
diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c
index 6817c8b..ac0a130 100644
--- a/hw/m68k/q800.c
+++ b/hw/m68k/q800.c
@@ -334,7 +334,7 @@
prom = memory_region_get_ram_ptr(dp8393x_prom);
checksum = 0;
for (i = 0; i < 6; i++) {
- prom[i] = bitrev8(nd_table[0].macaddr.a[i]);
+ prom[i] = revbit8(nd_table[0].macaddr.a[i]);
checksum ^= prom[i];
}
prom[7] = 0xff - checksum;
diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index 54f57c6..5c375a9 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -392,7 +392,7 @@
v &= 0xffffffffffff0000ull;
v |= 0x000000000000cfffull & val;
}
- *tptr = val;
+ *tptr = v;
break;
}
case IODA3_TBL_MBT:
diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c
index 0cfc19b..23e2e2f 100644
--- a/hw/ppc/spapr_events.c
+++ b/hw/ppc/spapr_events.c
@@ -934,7 +934,6 @@
uint32_t nret, target_ulong rets)
{
uint32_t mask, buf, len, event_len;
- uint64_t xinfo;
SpaprEventLogEntry *event;
struct rtas_error_log header;
int i;
@@ -944,13 +943,9 @@
return;
}
- xinfo = rtas_ld(args, 1);
mask = rtas_ld(args, 2);
buf = rtas_ld(args, 4);
len = rtas_ld(args, 5);
- if (nargs == 7) {
- xinfo |= (uint64_t)rtas_ld(args, 6) << 32;
- }
event = rtas_event_log_dequeue(spapr, mask);
if (!event) {
diff --git a/include/qemu/bitops.h b/include/qemu/bitops.h
index 110c56e..03213ce 100644
--- a/include/qemu/bitops.h
+++ b/include/qemu/bitops.h
@@ -618,26 +618,4 @@
return x;
}
-/**
- * bitrev8:
- * @x: 8-bit value to be reversed
- *
- * Given an input value with bits::
- *
- * ABCDEFGH
- *
- * return the value with its bits reversed from left to right::
- *
- * HGFEDCBA
- *
- * Returns: the bit-reversed value.
- */
-static inline uint8_t bitrev8(uint8_t x)
-{
- x = ((x >> 1) & 0x55) | ((x << 1) & 0xaa);
- x = ((x >> 2) & 0x33) | ((x << 2) & 0xcc);
- x = (x >> 4) | (x << 4) ;
- return x;
-}
-
#endif
diff --git a/include/ui/gtk.h b/include/ui/gtk.h
index 9516670..80d6bbd 100644
--- a/include/ui/gtk.h
+++ b/include/ui/gtk.h
@@ -25,6 +25,9 @@
#include "ui/egl-helpers.h"
#include "ui/egl-context.h"
#endif
+#ifdef CONFIG_VTE
+#include "qemu/fifo8.h"
+#endif
#define MAX_VCS 10
@@ -62,6 +65,7 @@
GtkWidget *scrollbar;
GtkWidget *terminal;
Chardev *chr;
+ Fifo8 out_fifo;
bool echo;
} VirtualVteConsole;
#endif
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 376629c..ccd3892 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -8364,7 +8364,6 @@
abi_ulong guest_envp;
abi_ulong addr;
char **q;
- int total_size = 0;
argc = 0;
guest_argp = arg2;
@@ -8396,7 +8395,6 @@
break;
if (!(*q = lock_user_string(addr)))
goto execve_efault;
- total_size += strlen(*q) + 1;
}
*q = NULL;
@@ -8408,7 +8406,6 @@
break;
if (!(*q = lock_user_string(addr)))
goto execve_efault;
- total_size += strlen(*q) + 1;
}
*q = NULL;
diff --git a/migration/channel.c b/migration/channel.c
index 01275a9..c4fc000 100644
--- a/migration/channel.c
+++ b/migration/channel.c
@@ -44,13 +44,7 @@
TYPE_QIO_CHANNEL_TLS)) {
migration_tls_channel_process_incoming(s, ioc, &local_err);
} else {
- if (object_dynamic_cast(OBJECT(ioc), TYPE_QIO_CHANNEL_SOCKET) ||
- object_dynamic_cast(OBJECT(ioc), TYPE_QIO_CHANNEL_TLS)) {
- yank_register_function(MIGRATION_YANK_INSTANCE,
- migration_yank_iochannel,
- QIO_CHANNEL(ioc));
- }
-
+ migration_ioc_register_yank(ioc);
migration_ioc_process_incoming(ioc, &local_err);
}
@@ -94,12 +88,7 @@
} else {
QEMUFile *f = qemu_fopen_channel_output(ioc);
- if (object_dynamic_cast(OBJECT(ioc), TYPE_QIO_CHANNEL_SOCKET) ||
- object_dynamic_cast(OBJECT(ioc), TYPE_QIO_CHANNEL_TLS)) {
- yank_register_function(MIGRATION_YANK_INSTANCE,
- migration_yank_iochannel,
- QIO_CHANNEL(ioc));
- }
+ migration_ioc_register_yank(ioc);
qemu_mutex_lock(&s->qemu_file_lock);
s->to_dst_file = f;
diff --git a/migration/migration.c b/migration/migration.c
index 2d30658..041b845 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -59,6 +59,7 @@
#include "multifd.h"
#include "qemu/yank.h"
#include "sysemu/cpus.h"
+#include "yank_functions.h"
#define MAX_THROTTLE (128 << 20) /* Migration transfer speed throttling */
@@ -273,6 +274,7 @@
}
if (mis->from_src_file) {
+ migration_ioc_unregister_yank_from_file(mis->from_src_file);
qemu_fclose(mis->from_src_file);
mis->from_src_file = NULL;
}
@@ -1811,6 +1813,7 @@
* Close the file handle without the lock to make sure the
* critical section won't block for long.
*/
+ migration_ioc_unregister_yank_from_file(tmp);
qemu_fclose(tmp);
}
@@ -1879,9 +1882,11 @@
QEMUFile *f = migrate_get_current()->to_dst_file;
trace_migrate_fd_cancel();
- if (s->rp_state.from_dst_file) {
- /* shutdown the rp socket, so causing the rp thread to shutdown */
- qemu_file_shutdown(s->rp_state.from_dst_file);
+ WITH_QEMU_LOCK_GUARD(&s->qemu_file_lock) {
+ if (s->rp_state.from_dst_file) {
+ /* shutdown the rp socket, so causing the rp thread to shutdown */
+ qemu_file_shutdown(s->rp_state.from_dst_file);
+ }
}
do {
@@ -2686,6 +2691,23 @@
return 0;
}
+/* Release ms->rp_state.from_dst_file in a safe way */
+static void migration_release_from_dst_file(MigrationState *ms)
+{
+ QEMUFile *file;
+
+ WITH_QEMU_LOCK_GUARD(&ms->qemu_file_lock) {
+ /*
+ * Reset the from_dst_file pointer first before releasing it, as we
+ * can't block within lock section
+ */
+ file = ms->rp_state.from_dst_file;
+ ms->rp_state.from_dst_file = NULL;
+ }
+
+ qemu_fclose(file);
+}
+
/*
* Handles messages sent on the return path towards the source VM
*
@@ -2827,11 +2849,13 @@
* Maybe there is something we can do: it looks like a
* network down issue, and we pause for a recovery.
*/
- qemu_fclose(rp);
- ms->rp_state.from_dst_file = NULL;
+ migration_release_from_dst_file(ms);
rp = NULL;
if (postcopy_pause_return_path_thread(ms)) {
- /* Reload rp, reset the rest */
+ /*
+ * Reload rp, reset the rest. Referencing it is safe since
+ * it's reset only by us above, or when migration completes
+ */
rp = ms->rp_state.from_dst_file;
ms->rp_state.error = false;
goto retry;
@@ -2843,8 +2867,7 @@
}
trace_source_return_path_thread_end();
- ms->rp_state.from_dst_file = NULL;
- qemu_fclose(rp);
+ migration_release_from_dst_file(ms);
rcu_unregister_thread();
return NULL;
}
@@ -2852,7 +2875,6 @@
static int open_return_path_on_source(MigrationState *ms,
bool create_thread)
{
-
ms->rp_state.from_dst_file = qemu_file_get_return_path(ms->to_dst_file);
if (!ms->rp_state.from_dst_file) {
return -1;
@@ -2867,6 +2889,7 @@
qemu_thread_create(&ms->rp_state.rp_thread, "return path",
source_return_path_thread, ms, QEMU_THREAD_JOINABLE);
+ ms->rp_state.rp_thread_created = true;
trace_open_return_path_on_source_continue();
@@ -2891,6 +2914,7 @@
}
trace_await_return_path_close_on_source_joining();
qemu_thread_join(&ms->rp_state.rp_thread);
+ ms->rp_state.rp_thread_created = false;
trace_await_return_path_close_on_source_close();
return ms->rp_state.error;
}
@@ -3170,7 +3194,7 @@
* it will wait for the destination to send it's status in
* a SHUT command).
*/
- if (s->rp_state.from_dst_file) {
+ if (s->rp_state.rp_thread_created) {
int rp_error;
trace_migration_return_path_end_before();
rp_error = await_return_path_close_on_source(s);
@@ -3330,8 +3354,17 @@
while (true) {
QEMUFile *file;
- /* Current channel is possibly broken. Release it. */
+ /*
+ * Current channel is possibly broken. Release it. Note that this is
+ * guaranteed even without lock because to_dst_file should only be
+ * modified by the migration thread. That also guarantees that the
+ * unregister of yank is safe too without the lock. It should be safe
+ * even to be within the qemu_file_lock, but we didn't do that to avoid
+ * taking more mutex (yank_lock) within qemu_file_lock. TL;DR: we make
+ * the qemu_file_lock critical section as small as possible.
+ */
assert(s->to_dst_file);
+ migration_ioc_unregister_yank_from_file(s->to_dst_file);
qemu_mutex_lock(&s->qemu_file_lock);
file = s->to_dst_file;
s->to_dst_file = NULL;
@@ -3744,7 +3777,7 @@
* If we opened the return path, we need to make sure dst has it
* opened as well.
*/
- if (s->rp_state.from_dst_file) {
+ if (s->rp_state.rp_thread_created) {
/* Now tell the dest that it should open its end so it can reply */
qemu_savevm_send_open_return_path(s->to_dst_file);
diff --git a/migration/migration.h b/migration/migration.h
index 2ebb740..7a5aa8c 100644
--- a/migration/migration.h
+++ b/migration/migration.h
@@ -154,12 +154,13 @@
QemuThread thread;
QEMUBH *vm_start_bh;
QEMUBH *cleanup_bh;
+ /* Protected by qemu_file_lock */
QEMUFile *to_dst_file;
QIOChannelBuffer *bioc;
/*
- * Protects to_dst_file pointer. We need to make sure we won't
- * yield or hang during the critical section, since this lock will
- * be used in OOB command handler.
+ * Protects to_dst_file/from_dst_file pointers. We need to make sure we
+ * won't yield or hang during the critical section, since this lock will be
+ * used in OOB command handler.
*/
QemuMutex qemu_file_lock;
@@ -192,9 +193,17 @@
/* State related to return path */
struct {
+ /* Protected by qemu_file_lock */
QEMUFile *from_dst_file;
QemuThread rp_thread;
bool error;
+ /*
+ * We can also check non-zero of rp_thread, but there's no "official"
+ * way to do this, so this bool makes it slightly more elegant.
+ * Checking from_dst_file for this is racy because from_dst_file will
+ * be cleared in the rp_thread!
+ */
+ bool rp_thread_created;
QemuSemaphore rp_sem;
} rp_state;
diff --git a/migration/multifd.c b/migration/multifd.c
index ab41590..377da78 100644
--- a/migration/multifd.c
+++ b/migration/multifd.c
@@ -987,12 +987,8 @@
for (i = 0; i < migrate_multifd_channels(); i++) {
MultiFDRecvParams *p = &multifd_recv_state->params[i];
- if ((object_dynamic_cast(OBJECT(p->c), TYPE_QIO_CHANNEL_SOCKET) ||
- object_dynamic_cast(OBJECT(p->c), TYPE_QIO_CHANNEL_TLS))
- && OBJECT(p->c)->ref == 1) {
- yank_unregister_function(MIGRATION_YANK_INSTANCE,
- migration_yank_iochannel,
- QIO_CHANNEL(p->c));
+ if (OBJECT(p->c)->ref == 1) {
+ migration_ioc_unregister_yank(p->c);
}
object_unref(OBJECT(p->c));
diff --git a/migration/qemu-file-channel.c b/migration/qemu-file-channel.c
index fad340e..bb5a575 100644
--- a/migration/qemu-file-channel.c
+++ b/migration/qemu-file-channel.c
@@ -107,13 +107,6 @@
int ret;
QIOChannel *ioc = QIO_CHANNEL(opaque);
ret = qio_channel_close(ioc, errp);
- if ((object_dynamic_cast(OBJECT(ioc), TYPE_QIO_CHANNEL_SOCKET) ||
- object_dynamic_cast(OBJECT(ioc), TYPE_QIO_CHANNEL_TLS))
- && OBJECT(ioc)->ref == 1) {
- yank_unregister_function(MIGRATION_YANK_INSTANCE,
- migration_yank_iochannel,
- QIO_CHANNEL(ioc));
- }
object_unref(OBJECT(ioc));
return ret;
}
@@ -191,11 +184,11 @@
QEMUFile *qemu_fopen_channel_input(QIOChannel *ioc)
{
object_ref(OBJECT(ioc));
- return qemu_fopen_ops(ioc, &channel_input_ops);
+ return qemu_fopen_ops(ioc, &channel_input_ops, true);
}
QEMUFile *qemu_fopen_channel_output(QIOChannel *ioc)
{
object_ref(OBJECT(ioc));
- return qemu_fopen_ops(ioc, &channel_output_ops);
+ return qemu_fopen_ops(ioc, &channel_output_ops, true);
}
diff --git a/migration/qemu-file.c b/migration/qemu-file.c
index 1eacf9e..6338d8e 100644
--- a/migration/qemu-file.c
+++ b/migration/qemu-file.c
@@ -55,6 +55,8 @@
Error *last_error_obj;
/* has the file has been shutdown */
bool shutdown;
+ /* Whether opaque points to a QIOChannel */
+ bool has_ioc;
};
/*
@@ -101,7 +103,7 @@
return false;
}
-QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops)
+QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops, bool has_ioc)
{
QEMUFile *f;
@@ -109,6 +111,7 @@
f->opaque = opaque;
f->ops = ops;
+ f->has_ioc = has_ioc;
return f;
}
@@ -851,3 +854,15 @@
f->ops->set_blocking(f->opaque, block, NULL);
}
}
+
+/*
+ * Return the ioc object if it's a migration channel. Note: it can return NULL
+ * for callers passing in a non-migration qemufile. E.g. see qemu_fopen_bdrv()
+ * and its usage in e.g. load_snapshot(). So we need to check against NULL
+ * before using it. If without the check, migration_incoming_state_destroy()
+ * could fail for load_snapshot().
+ */
+QIOChannel *qemu_file_get_ioc(QEMUFile *file)
+{
+ return file->has_ioc ? QIO_CHANNEL(file->opaque) : NULL;
+}
diff --git a/migration/qemu-file.h b/migration/qemu-file.h
index a9b6d6c..3f36d4d 100644
--- a/migration/qemu-file.h
+++ b/migration/qemu-file.h
@@ -27,6 +27,7 @@
#include <zlib.h>
#include "exec/cpu-common.h"
+#include "io/channel.h"
/* Read a chunk of data from a file at the given position. The pos argument
* can be ignored if the file is only be used for streaming. The number of
@@ -119,7 +120,7 @@
QEMURamSaveFunc *save_page;
} QEMUFileHooks;
-QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops);
+QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops, bool has_ioc);
void qemu_file_set_hooks(QEMUFile *f, const QEMUFileHooks *hooks);
int qemu_get_fd(QEMUFile *f);
int qemu_fclose(QEMUFile *f);
@@ -179,5 +180,6 @@
size_t ram_control_save_page(QEMUFile *f, ram_addr_t block_offset,
ram_addr_t offset, size_t size,
uint64_t *bytes_sent);
+QIOChannel *qemu_file_get_ioc(QEMUFile *file);
#endif
diff --git a/migration/ram.c b/migration/ram.c
index b5fc454..7a43bfd 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -550,7 +550,7 @@
/* comp_param[i].file is just used as a dummy buffer to save data,
* set its ops to empty.
*/
- comp_param[i].file = qemu_fopen_ops(NULL, &empty_ops);
+ comp_param[i].file = qemu_fopen_ops(NULL, &empty_ops, false);
comp_param[i].done = true;
comp_param[i].quit = false;
qemu_mutex_init(&comp_param[i].mutex);
@@ -789,6 +789,53 @@
return find_next_bit(bitmap, size, start);
}
+static void migration_clear_memory_region_dirty_bitmap(RAMState *rs,
+ RAMBlock *rb,
+ unsigned long page)
+{
+ uint8_t shift;
+ hwaddr size, start;
+
+ if (!rb->clear_bmap || !clear_bmap_test_and_clear(rb, page)) {
+ return;
+ }
+
+ shift = rb->clear_bmap_shift;
+ /*
+ * CLEAR_BITMAP_SHIFT_MIN should always guarantee this... this
+ * can make things easier sometimes since then start address
+ * of the small chunk will always be 64 pages aligned so the
+ * bitmap will always be aligned to unsigned long. We should
+ * even be able to remove this restriction but I'm simply
+ * keeping it.
+ */
+ assert(shift >= 6);
+
+ size = 1ULL << (TARGET_PAGE_BITS + shift);
+ start = (((ram_addr_t)page) << TARGET_PAGE_BITS) & (-size);
+ trace_migration_bitmap_clear_dirty(rb->idstr, start, size, page);
+ memory_region_clear_dirty_bitmap(rb->mr, start, size);
+}
+
+static void
+migration_clear_memory_region_dirty_bitmap_range(RAMState *rs,
+ RAMBlock *rb,
+ unsigned long start,
+ unsigned long npages)
+{
+ unsigned long i, chunk_pages = 1UL << rb->clear_bmap_shift;
+ unsigned long chunk_start = QEMU_ALIGN_DOWN(start, chunk_pages);
+ unsigned long chunk_end = QEMU_ALIGN_UP(start + npages, chunk_pages);
+
+ /*
+ * Clear pages from start to start + npages - 1, so the end boundary is
+ * exclusive.
+ */
+ for (i = chunk_start; i < chunk_end; i += chunk_pages) {
+ migration_clear_memory_region_dirty_bitmap(rs, rb, i);
+ }
+}
+
static inline bool migration_bitmap_clear_dirty(RAMState *rs,
RAMBlock *rb,
unsigned long page)
@@ -803,26 +850,9 @@
* the page in the chunk we clear the remote dirty bitmap for all.
* Clearing it earlier won't be a problem, but too late will.
*/
- if (rb->clear_bmap && clear_bmap_test_and_clear(rb, page)) {
- uint8_t shift = rb->clear_bmap_shift;
- hwaddr size = 1ULL << (TARGET_PAGE_BITS + shift);
- hwaddr start = (((ram_addr_t)page) << TARGET_PAGE_BITS) & (-size);
-
- /*
- * CLEAR_BITMAP_SHIFT_MIN should always guarantee this... this
- * can make things easier sometimes since then start address
- * of the small chunk will always be 64 pages aligned so the
- * bitmap will always be aligned to unsigned long. We should
- * even be able to remove this restriction but I'm simply
- * keeping it.
- */
- assert(shift >= 6);
- trace_migration_bitmap_clear_dirty(rb->idstr, start, size, page);
- memory_region_clear_dirty_bitmap(rb->mr, start, size);
- }
+ migration_clear_memory_region_dirty_bitmap(rs, rb, page);
ret = test_and_clear_bit(page, rb->bmap);
-
if (ret) {
rs->migration_dirty_pages--;
}
@@ -2741,6 +2771,14 @@
npages = used_len >> TARGET_PAGE_BITS;
qemu_mutex_lock(&ram_state->bitmap_mutex);
+ /*
+ * The skipped free pages are equavalent to be sent from clear_bmap's
+ * perspective, so clear the bits from the memory region bitmap which
+ * are initially set. Otherwise those skipped pages will be sent in
+ * the next round after syncing from the memory region bitmap.
+ */
+ migration_clear_memory_region_dirty_bitmap_range(ram_state, block,
+ start, npages);
ram_state->migration_dirty_pages -=
bitmap_count_one_with_offset(block->bmap, start, npages);
bitmap_clear(block->bmap, start, npages);
@@ -4012,6 +4050,7 @@
int ram_dirty_bitmap_reload(MigrationState *s, RAMBlock *block)
{
int ret = -EINVAL;
+ /* from_dst_file is always valid because we're within rp_thread */
QEMUFile *file = s->rp_state.from_dst_file;
unsigned long *le_bitmap, nbits = block->used_length >> TARGET_PAGE_BITS;
uint64_t local_size = DIV_ROUND_UP(nbits, 8);
diff --git a/migration/savevm.c b/migration/savevm.c
index 72848b9..7b7b64b 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -65,6 +65,7 @@
#include "qemu/bitmap.h"
#include "net/announce.h"
#include "qemu/yank.h"
+#include "yank_functions.h"
const unsigned int postcopy_ram_discard_version;
@@ -168,9 +169,9 @@
static QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable)
{
if (is_writable) {
- return qemu_fopen_ops(bs, &bdrv_write_ops);
+ return qemu_fopen_ops(bs, &bdrv_write_ops, false);
}
- return qemu_fopen_ops(bs, &bdrv_read_ops);
+ return qemu_fopen_ops(bs, &bdrv_read_ops, false);
}
@@ -2568,6 +2569,12 @@
/* Clear the triggered bit to allow one recovery */
mis->postcopy_recover_triggered = false;
+ /*
+ * Unregister yank with either from/to src would work, since ioc behind it
+ * is the same
+ */
+ migration_ioc_unregister_yank_from_file(mis->from_src_file);
+
assert(mis->from_src_file);
qemu_file_shutdown(mis->from_src_file);
qemu_fclose(mis->from_src_file);
diff --git a/migration/yank_functions.c b/migration/yank_functions.c
index 96c90e1..8c08aef 100644
--- a/migration/yank_functions.c
+++ b/migration/yank_functions.c
@@ -11,6 +11,10 @@
#include "qapi/error.h"
#include "io/channel.h"
#include "yank_functions.h"
+#include "qemu/yank.h"
+#include "io/channel-socket.h"
+#include "io/channel-tls.h"
+#include "qemu-file.h"
void migration_yank_iochannel(void *opaque)
{
@@ -18,3 +22,41 @@
qio_channel_shutdown(ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL);
}
+
+/* Return whether yank is supported on this ioc */
+static bool migration_ioc_yank_supported(QIOChannel *ioc)
+{
+ return object_dynamic_cast(OBJECT(ioc), TYPE_QIO_CHANNEL_SOCKET) ||
+ object_dynamic_cast(OBJECT(ioc), TYPE_QIO_CHANNEL_TLS);
+}
+
+void migration_ioc_register_yank(QIOChannel *ioc)
+{
+ if (migration_ioc_yank_supported(ioc)) {
+ yank_register_function(MIGRATION_YANK_INSTANCE,
+ migration_yank_iochannel,
+ QIO_CHANNEL(ioc));
+ }
+}
+
+void migration_ioc_unregister_yank(QIOChannel *ioc)
+{
+ if (migration_ioc_yank_supported(ioc)) {
+ yank_unregister_function(MIGRATION_YANK_INSTANCE,
+ migration_yank_iochannel,
+ QIO_CHANNEL(ioc));
+ }
+}
+
+void migration_ioc_unregister_yank_from_file(QEMUFile *file)
+{
+ QIOChannel *ioc = qemu_file_get_ioc(file);
+
+ if (ioc) {
+ /*
+ * For migration qemufiles, we'll always reach here. Though we'll skip
+ * calls from e.g. savevm/loadvm as they don't use yank.
+ */
+ migration_ioc_unregister_yank(ioc);
+ }
+}
diff --git a/migration/yank_functions.h b/migration/yank_functions.h
index 055ea22..a757795 100644
--- a/migration/yank_functions.h
+++ b/migration/yank_functions.h
@@ -15,3 +15,6 @@
* @opaque: QIOChannel to shutdown
*/
void migration_yank_iochannel(void *opaque);
+void migration_ioc_register_yank(QIOChannel *ioc);
+void migration_ioc_unregister_yank(QIOChannel *ioc);
+void migration_ioc_unregister_yank_from_file(QEMUFile *file);
diff --git a/nbd/server.c b/nbd/server.c
index b60ebc3..3927f77 100644
--- a/nbd/server.c
+++ b/nbd/server.c
@@ -973,7 +973,8 @@
{
int ret;
g_autofree char *export_name = NULL;
- g_autofree bool *bitmaps = NULL;
+ /* Mark unused to work around https://bugs.llvm.org/show_bug.cgi?id=3888 */
+ g_autofree G_GNUC_UNUSED bool *bitmaps = NULL;
NBDExportMetaContexts local_meta = {0};
uint32_t nb_queries;
size_t i;
diff --git a/net/checksum.c b/net/checksum.c
index 70f4eae..68245fd 100644
--- a/net/checksum.c
+++ b/net/checksum.c
@@ -186,12 +186,11 @@
net_checksum_add_iov(const struct iovec *iov, const unsigned int iov_cnt,
uint32_t iov_off, uint32_t size, uint32_t csum_offset)
{
- size_t iovec_off, buf_off;
+ size_t iovec_off;
unsigned int i;
uint32_t res = 0;
iovec_off = 0;
- buf_off = 0;
for (i = 0; i < iov_cnt && size; i++) {
if (iov_off < (iovec_off + iov[i].iov_len)) {
size_t len = MIN((iovec_off + iov[i].iov_len) - iov_off , size);
@@ -200,7 +199,6 @@
res += net_checksum_add_cont(len, chunk_buf, csum_offset);
csum_offset += len;
- buf_off += len;
iov_off += len;
size -= len;
}
diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c
index 328d6db..1e8b778 100644
--- a/tests/qtest/migration-test.c
+++ b/tests/qtest/migration-test.c
@@ -787,10 +787,10 @@
args->hide_stderr = true;
- if (test_migrate_start(&from, &to, "tcp:0:0", args)) {
+ if (test_migrate_start(&from, &to, "tcp:127.0.0.1:0", args)) {
return;
}
- migrate_qmp(from, "tcp:0:0", "{}");
+ migrate_qmp(from, "tcp:127.0.0.1:0", "{}");
wait_for_migration_fail(from, false);
test_migrate_end(from, to, false);
}
diff --git a/tests/unit/test-iov.c b/tests/unit/test-iov.c
index 9c415e2..5371066 100644
--- a/tests/unit/test-iov.c
+++ b/tests/unit/test-iov.c
@@ -158,7 +158,7 @@
int sv[2];
int r;
- unsigned i, j, k, s, t;
+ unsigned i, j, k, s;
fd_set fds;
unsigned niov;
struct iovec *iov, *siov;
@@ -182,7 +182,6 @@
FD_ZERO(&fds);
- t = 0;
if (fork() == 0) {
/* writer */
@@ -201,7 +200,6 @@
g_assert(memcmp(iov, siov, sizeof(*iov)*niov) == 0);
if (r >= 0) {
k += r;
- t += r;
usleep(g_test_rand_int_range(0, 30));
} else if (errno == EAGAIN) {
select(sv[1]+1, NULL, &fds, NULL, NULL);
@@ -238,7 +236,6 @@
g_assert(memcmp(iov, siov, sizeof(*iov)*niov) == 0);
if (r > 0) {
k += r;
- t += r;
} else if (!r) {
if (s) {
break;
diff --git a/ui/cocoa.m b/ui/cocoa.m
index 9f72844..68a6302 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -1888,12 +1888,12 @@
exit(status);
}
-int main (int argc, const char * argv[]) {
+int main (int argc, char **argv) {
QemuThread thread;
COCOA_DEBUG("Entered main()\n");
gArgc = argc;
- gArgv = (char **)argv;
+ gArgv = argv;
qemu_sem_init(&display_init_sem, 0);
qemu_sem_init(&app_started_sem, 0);
diff --git a/ui/egl-headless.c b/ui/egl-headless.c
index 75404e0..a26a252 100644
--- a/ui/egl-headless.c
+++ b/ui/egl-headless.c
@@ -214,6 +214,4 @@
type_init(register_egl);
-#ifdef CONFIG_OPENGL
module_dep("ui-opengl");
-#endif
diff --git a/ui/gtk.c b/ui/gtk.c
index 376b4d5..974e4df 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -865,37 +865,25 @@
GdkWindow *win = gtk_widget_get_window(widget);
GdkMonitor *monitor = gdk_display_get_monitor_at_window(dpy, win);
GdkRectangle geometry;
- int screen_width, screen_height;
int x = (int)motion->x_root;
int y = (int)motion->y_root;
gdk_monitor_get_geometry(monitor, &geometry);
- screen_width = geometry.width;
- screen_height = geometry.height;
/* In relative mode check to see if client pointer hit
- * one of the screen edges, and if so move it back by
- * 200 pixels. This is important because the pointer
+ * one of the monitor edges, and if so move it back to the
+ * center of the monitor. This is important because the pointer
* in the server doesn't correspond 1-for-1, and so
* may still be only half way across the screen. Without
* this warp, the server pointer would thus appear to hit
* an invisible wall */
- if (x == 0) {
- x += 200;
- }
- if (y == 0) {
- y += 200;
- }
- if (x == (screen_width - 1)) {
- x -= 200;
- }
- if (y == (screen_height - 1)) {
- y -= 200;
- }
-
- if (x != (int)motion->x_root || y != (int)motion->y_root) {
+ if (x <= geometry.x || x - geometry.x >= geometry.width - 1 ||
+ y <= geometry.y || y - geometry.y >= geometry.height - 1) {
GdkDevice *dev = gdk_event_get_device((GdkEvent *)motion);
+ x = geometry.x + geometry.width / 2;
+ y = geometry.y + geometry.height / 2;
+
gdk_device_warp(dev, screen, x, y);
s->last_set = FALSE;
return FALSE;
@@ -1652,6 +1640,25 @@
}
}
+static void gd_vc_send_chars(VirtualConsole *vc)
+{
+ uint32_t len, avail;
+
+ len = qemu_chr_be_can_write(vc->vte.chr);
+ avail = fifo8_num_used(&vc->vte.out_fifo);
+ if (len > avail) {
+ len = avail;
+ }
+ while (len > 0) {
+ const uint8_t *buf;
+ uint32_t size;
+
+ buf = fifo8_pop_buf(&vc->vte.out_fifo, len, &size);
+ qemu_chr_be_write(vc->vte.chr, (uint8_t *)buf, size);
+ len -= size;
+ }
+}
+
static int gd_vc_chr_write(Chardev *chr, const uint8_t *buf, int len)
{
VCChardev *vcd = VC_CHARDEV(chr);
@@ -1661,6 +1668,14 @@
return len;
}
+static void gd_vc_chr_accept_input(Chardev *chr)
+{
+ VCChardev *vcd = VC_CHARDEV(chr);
+ VirtualConsole *vc = vcd->console;
+
+ gd_vc_send_chars(vc);
+}
+
static void gd_vc_chr_set_echo(Chardev *chr, bool echo)
{
VCChardev *vcd = VC_CHARDEV(chr);
@@ -1700,6 +1715,7 @@
cc->parse = qemu_chr_parse_vc;
cc->open = gd_vc_open;
cc->chr_write = gd_vc_chr_write;
+ cc->chr_accept_input = gd_vc_chr_accept_input;
cc->chr_set_echo = gd_vc_chr_set_echo;
}
@@ -1714,6 +1730,7 @@
gpointer user_data)
{
VirtualConsole *vc = user_data;
+ uint32_t free;
if (vc->vte.echo) {
VteTerminal *term = VTE_TERMINAL(vc->vte.terminal);
@@ -1733,16 +1750,10 @@
}
}
- int remaining = size;
- uint8_t* p = (uint8_t *)text;
- while (remaining > 0) {
- int can_write = qemu_chr_be_can_write(vc->vte.chr);
- int written = MIN(remaining, can_write);
- qemu_chr_be_write(vc->vte.chr, p, written);
+ free = fifo8_num_free(&vc->vte.out_fifo);
+ fifo8_push_all(&vc->vte.out_fifo, (uint8_t *)text, MIN(free, size));
+ gd_vc_send_chars(vc);
- remaining -= written;
- p += written;
- }
return TRUE;
}
@@ -1759,6 +1770,7 @@
vc->s = s;
vc->vte.echo = vcd->echo;
vc->vte.chr = chr;
+ fifo8_create(&vc->vte.out_fifo, 4096);
vcd->console = vc;
snprintf(buffer, sizeof(buffer), "vc%d", idx);
diff --git a/ui/keycodemapdb b/ui/keycodemapdb
index 6119e6e..d21009b 160000
--- a/ui/keycodemapdb
+++ b/ui/keycodemapdb
@@ -1 +1 @@
-Subproject commit 6119e6e19a050df847418de7babe5166779955e4
+Subproject commit d21009b1c9f94b740ea66be8e48a1d8ad8124023
diff --git a/ui/spice-app.c b/ui/spice-app.c
index 641f4a9..7e71e18 100644
--- a/ui/spice-app.c
+++ b/ui/spice-app.c
@@ -27,6 +27,7 @@
#include <gio/gio.h>
#include "ui/console.h"
+#include "ui/spice-display.h"
#include "qemu/config-file.h"
#include "qemu/option.h"
#include "qemu/cutils.h"
@@ -175,7 +176,7 @@
qemu_opt_set(qopts, "addr", sock_path, &error_abort);
qemu_opt_set(qopts, "image-compression", "off", &error_abort);
qemu_opt_set(qopts, "streaming-video", "off", &error_abort);
-#ifdef CONFIG_OPENGL
+#ifdef HAVE_SPICE_GL
qemu_opt_set(qopts, "gl", opts->has_gl ? "on" : "off", &error_abort);
display_opengl = opts->has_gl;
#endif
diff --git a/ui/spice-core.c b/ui/spice-core.c
index 86d4378..0371055 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -1039,6 +1039,6 @@
opts_init(spice_register_config);
module_opts("spice");
-#ifdef CONFIG_OPENGL
+#ifdef HAVE_SPICE_GL
module_dep("ui-opengl");
#endif
diff --git a/util/selfmap.c b/util/selfmap.c
index 2ec99df..2c14f01 100644
--- a/util/selfmap.c
+++ b/util/selfmap.c
@@ -23,29 +23,34 @@
gchar **fields = g_strsplit(lines[i], " ", 6);
if (g_strv_length(fields) > 4) {
MapInfo *e = g_new0(MapInfo, 1);
- int errors;
+ int errors = 0;
const char *end;
- errors = qemu_strtoul(fields[0], &end, 16, &e->start);
- errors += qemu_strtoul(end + 1, NULL, 16, &e->end);
+ errors |= qemu_strtoul(fields[0], &end, 16, &e->start);
+ errors |= qemu_strtoul(end + 1, NULL, 16, &e->end);
e->is_read = fields[1][0] == 'r';
e->is_write = fields[1][1] == 'w';
e->is_exec = fields[1][2] == 'x';
e->is_priv = fields[1][3] == 'p';
- errors += qemu_strtoul(fields[2], NULL, 16, &e->offset);
+ errors |= qemu_strtoul(fields[2], NULL, 16, &e->offset);
e->dev = g_strdup(fields[3]);
- errors += qemu_strtou64(fields[4], NULL, 10, &e->inode);
+ errors |= qemu_strtou64(fields[4], NULL, 10, &e->inode);
- /*
- * The last field may have leading spaces which we
- * need to strip.
- */
- if (g_strv_length(fields) == 6) {
- e->path = g_strdup(g_strchug(fields[5]));
+ if (!errors) {
+ /*
+ * The last field may have leading spaces which we
+ * need to strip.
+ */
+ if (g_strv_length(fields) == 6) {
+ e->path = g_strdup(g_strchug(fields[5]));
+ }
+ map_info = g_slist_prepend(map_info, e);
+ } else {
+ g_free(e->dev);
+ g_free(e);
}
- map_info = g_slist_prepend(map_info, e);
}
g_strfreev(fields);