mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging
- vhost-scsi: add bootindex property - RCU: fix MemoryRegion lifetime issues in PCI; document the rules; convert of AddressSpaceDispatch and RAMList - KVM: add kvm_exit reasons for aarch64 # gpg: Signature made Mon Feb 16 16:32:32 2015 GMT using RSA key ID 78C7AE83 # gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" # gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" # 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: 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: (21 commits) Convert ram_list to RCU exec: convert ram_list to QLIST cosmetic changes preparing for the following patches exec: protect mru_block with RCU rcu: add g_free_rcu rcu: introduce RCU-enabled QLIST exec: RCUify AddressSpaceDispatch exec: make iotlb RCU-friendly exec: introduce cpu_reload_memory_map docs: clarify memory region lifecycle pci: split shpc_cleanup and shpc_free pcie: remove mmconfig memory leak and wrap mmconfig update with transaction memory: keep the owner of the AddressSpace alive until do_address_space_destroy rcu: run RCU callbacks under the BQL rcu: do not let RCU callbacks pile up indefinitely vhost-scsi: set the bootable value of channel/target/lun vhost-scsi: add a property for booting vhost-scsi: expose the TYPE_FW_PATH_PROVIDER interface vhost-scsi: add bootindex property qdev: support to get a device firmware path directly ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
+51
-22
@@ -52,6 +52,7 @@
|
||||
#include "exec/ram_addr.h"
|
||||
#include "hw/acpi/acpi.h"
|
||||
#include "qemu/host-utils.h"
|
||||
#include "qemu/rcu_queue.h"
|
||||
|
||||
#ifdef DEBUG_ARCH_INIT
|
||||
#define DPRINTF(fmt, ...) \
|
||||
@@ -487,7 +488,6 @@ static void migration_bitmap_sync_range(ram_addr_t start, ram_addr_t length)
|
||||
}
|
||||
|
||||
|
||||
/* Needs iothread lock! */
|
||||
/* Fix me: there are too many global variables used in migration process. */
|
||||
static int64_t start_time;
|
||||
static int64_t bytes_xfer_prev;
|
||||
@@ -500,6 +500,7 @@ static void migration_bitmap_sync_init(void)
|
||||
num_dirty_pages_period = 0;
|
||||
}
|
||||
|
||||
/* Called with iothread lock held, to protect ram_list.dirty_memory[] */
|
||||
static void migration_bitmap_sync(void)
|
||||
{
|
||||
RAMBlock *block;
|
||||
@@ -523,9 +524,12 @@ static void migration_bitmap_sync(void)
|
||||
trace_migration_bitmap_sync_start();
|
||||
address_space_sync_dirty_bitmap(&address_space_memory);
|
||||
|
||||
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
||||
rcu_read_lock();
|
||||
QLIST_FOREACH_RCU(block, &ram_list.blocks, next) {
|
||||
migration_bitmap_sync_range(block->mr->ram_addr, block->used_length);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
trace_migration_bitmap_sync_end(migration_dirty_pages
|
||||
- num_dirty_pages_init);
|
||||
num_dirty_pages_period += migration_dirty_pages - num_dirty_pages_init;
|
||||
@@ -648,6 +652,8 @@ static int ram_save_page(QEMUFile *f, RAMBlock* block, ram_addr_t offset,
|
||||
/*
|
||||
* ram_find_and_save_block: Finds a page to send and sends it to f
|
||||
*
|
||||
* Called within an RCU critical section.
|
||||
*
|
||||
* Returns: The number of bytes written.
|
||||
* 0 means no dirty pages
|
||||
*/
|
||||
@@ -661,7 +667,7 @@ static int ram_find_and_save_block(QEMUFile *f, bool last_stage)
|
||||
MemoryRegion *mr;
|
||||
|
||||
if (!block)
|
||||
block = QTAILQ_FIRST(&ram_list.blocks);
|
||||
block = QLIST_FIRST_RCU(&ram_list.blocks);
|
||||
|
||||
while (true) {
|
||||
mr = block->mr;
|
||||
@@ -672,9 +678,9 @@ static int ram_find_and_save_block(QEMUFile *f, bool last_stage)
|
||||
}
|
||||
if (offset >= block->used_length) {
|
||||
offset = 0;
|
||||
block = QTAILQ_NEXT(block, next);
|
||||
block = QLIST_NEXT_RCU(block, next);
|
||||
if (!block) {
|
||||
block = QTAILQ_FIRST(&ram_list.blocks);
|
||||
block = QLIST_FIRST_RCU(&ram_list.blocks);
|
||||
complete_round = true;
|
||||
ram_bulk_stage = false;
|
||||
}
|
||||
@@ -688,9 +694,9 @@ static int ram_find_and_save_block(QEMUFile *f, bool last_stage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
last_seen_block = block;
|
||||
last_offset = offset;
|
||||
|
||||
return bytes_sent;
|
||||
}
|
||||
|
||||
@@ -728,9 +734,10 @@ uint64_t ram_bytes_total(void)
|
||||
RAMBlock *block;
|
||||
uint64_t total = 0;
|
||||
|
||||
QTAILQ_FOREACH(block, &ram_list.blocks, next)
|
||||
rcu_read_lock();
|
||||
QLIST_FOREACH_RCU(block, &ram_list.blocks, next)
|
||||
total += block->used_length;
|
||||
|
||||
rcu_read_unlock();
|
||||
return total;
|
||||
}
|
||||
|
||||
@@ -776,6 +783,13 @@ static void reset_ram_globals(void)
|
||||
|
||||
#define MAX_WAIT 50 /* ms, half buffered_file limit */
|
||||
|
||||
|
||||
/* Each of ram_save_setup, ram_save_iterate and ram_save_complete has
|
||||
* long-running RCU critical section. When rcu-reclaims in the code
|
||||
* start to become numerous it will be necessary to reduce the
|
||||
* granularity of these critical sections.
|
||||
*/
|
||||
|
||||
static int ram_save_setup(QEMUFile *f, void *opaque)
|
||||
{
|
||||
RAMBlock *block;
|
||||
@@ -816,8 +830,10 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
|
||||
acct_clear();
|
||||
}
|
||||
|
||||
/* iothread lock needed for ram_list.dirty_memory[] */
|
||||
qemu_mutex_lock_iothread();
|
||||
qemu_mutex_lock_ramlist();
|
||||
rcu_read_lock();
|
||||
bytes_transferred = 0;
|
||||
reset_ram_globals();
|
||||
|
||||
@@ -830,7 +846,7 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
|
||||
* gaps due to alignment or unplugs.
|
||||
*/
|
||||
migration_dirty_pages = 0;
|
||||
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
||||
QLIST_FOREACH_RCU(block, &ram_list.blocks, next) {
|
||||
uint64_t block_pages;
|
||||
|
||||
block_pages = block->used_length >> TARGET_PAGE_BITS;
|
||||
@@ -839,17 +855,18 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
|
||||
|
||||
memory_global_dirty_log_start();
|
||||
migration_bitmap_sync();
|
||||
qemu_mutex_unlock_ramlist();
|
||||
qemu_mutex_unlock_iothread();
|
||||
|
||||
qemu_put_be64(f, ram_bytes_total() | RAM_SAVE_FLAG_MEM_SIZE);
|
||||
|
||||
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
||||
QLIST_FOREACH_RCU(block, &ram_list.blocks, next) {
|
||||
qemu_put_byte(f, strlen(block->idstr));
|
||||
qemu_put_buffer(f, (uint8_t *)block->idstr, strlen(block->idstr));
|
||||
qemu_put_be64(f, block->used_length);
|
||||
}
|
||||
|
||||
qemu_mutex_unlock_ramlist();
|
||||
rcu_read_unlock();
|
||||
|
||||
ram_control_before_iterate(f, RAM_CONTROL_SETUP);
|
||||
ram_control_after_iterate(f, RAM_CONTROL_SETUP);
|
||||
@@ -866,12 +883,14 @@ static int ram_save_iterate(QEMUFile *f, void *opaque)
|
||||
int64_t t0;
|
||||
int total_sent = 0;
|
||||
|
||||
qemu_mutex_lock_ramlist();
|
||||
|
||||
rcu_read_lock();
|
||||
if (ram_list.version != last_version) {
|
||||
reset_ram_globals();
|
||||
}
|
||||
|
||||
/* Read version before ram_list.blocks */
|
||||
smp_rmb();
|
||||
|
||||
ram_control_before_iterate(f, RAM_CONTROL_ROUND);
|
||||
|
||||
t0 = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
|
||||
@@ -902,8 +921,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque)
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
qemu_mutex_unlock_ramlist();
|
||||
rcu_read_unlock();
|
||||
|
||||
/*
|
||||
* Must occur before EOS (or any QEMUFile operation)
|
||||
@@ -928,9 +946,11 @@ static int ram_save_iterate(QEMUFile *f, void *opaque)
|
||||
return total_sent;
|
||||
}
|
||||
|
||||
/* Called with iothread lock */
|
||||
static int ram_save_complete(QEMUFile *f, void *opaque)
|
||||
{
|
||||
qemu_mutex_lock_ramlist();
|
||||
rcu_read_lock();
|
||||
|
||||
migration_bitmap_sync();
|
||||
|
||||
ram_control_before_iterate(f, RAM_CONTROL_FINISH);
|
||||
@@ -952,7 +972,7 @@ static int ram_save_complete(QEMUFile *f, void *opaque)
|
||||
ram_control_after_iterate(f, RAM_CONTROL_FINISH);
|
||||
migration_end();
|
||||
|
||||
qemu_mutex_unlock_ramlist();
|
||||
rcu_read_unlock();
|
||||
qemu_put_be64(f, RAM_SAVE_FLAG_EOS);
|
||||
|
||||
return 0;
|
||||
@@ -966,7 +986,9 @@ static uint64_t ram_save_pending(QEMUFile *f, void *opaque, uint64_t max_size)
|
||||
|
||||
if (remaining_size < max_size) {
|
||||
qemu_mutex_lock_iothread();
|
||||
rcu_read_lock();
|
||||
migration_bitmap_sync();
|
||||
rcu_read_unlock();
|
||||
qemu_mutex_unlock_iothread();
|
||||
remaining_size = ram_save_remaining() * TARGET_PAGE_SIZE;
|
||||
}
|
||||
@@ -1008,6 +1030,9 @@ static int load_xbzrle(QEMUFile *f, ram_addr_t addr, void *host)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Must be called from within a rcu critical section.
|
||||
* Returns a pointer from within the RCU-protected ram_list.
|
||||
*/
|
||||
static inline void *host_from_stream_offset(QEMUFile *f,
|
||||
ram_addr_t offset,
|
||||
int flags)
|
||||
@@ -1029,7 +1054,7 @@ static inline void *host_from_stream_offset(QEMUFile *f,
|
||||
qemu_get_buffer(f, (uint8_t *)id, len);
|
||||
id[len] = 0;
|
||||
|
||||
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
||||
QLIST_FOREACH_RCU(block, &ram_list.blocks, next) {
|
||||
if (!strncmp(id, block->idstr, sizeof(id)) &&
|
||||
block->max_length > offset) {
|
||||
return memory_region_get_ram_ptr(block->mr) + offset;
|
||||
@@ -1062,6 +1087,12 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
/* This RCU critical section can be very long running.
|
||||
* When RCU reclaims in the code start to become numerous,
|
||||
* it will be necessary to reduce the granularity of this
|
||||
* critical section.
|
||||
*/
|
||||
rcu_read_lock();
|
||||
while (!ret && !(flags & RAM_SAVE_FLAG_EOS)) {
|
||||
ram_addr_t addr, total_ram_bytes;
|
||||
void *host;
|
||||
@@ -1086,7 +1117,7 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
|
||||
id[len] = 0;
|
||||
length = qemu_get_be64(f);
|
||||
|
||||
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
|
||||
QLIST_FOREACH_RCU(block, &ram_list.blocks, next) {
|
||||
if (!strncmp(id, block->idstr, sizeof(id))) {
|
||||
if (length != block->used_length) {
|
||||
Error *local_err = NULL;
|
||||
@@ -1117,7 +1148,6 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
ch = qemu_get_byte(f);
|
||||
ram_handle_compressed(host, ch, TARGET_PAGE_SIZE);
|
||||
break;
|
||||
@@ -1128,7 +1158,6 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
qemu_get_buffer(f, host, TARGET_PAGE_SIZE);
|
||||
break;
|
||||
case RAM_SAVE_FLAG_XBZRLE:
|
||||
@@ -1138,7 +1167,6 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (load_xbzrle(f, addr, host) < 0) {
|
||||
error_report("Failed to decompress XBZRLE page at "
|
||||
RAM_ADDR_FMT, addr);
|
||||
@@ -1163,6 +1191,7 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
|
||||
}
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
DPRINTF("Completed load of VM with exit code %d seq iteration "
|
||||
"%" PRIu64 "\n", ret, seq_iter);
|
||||
return ret;
|
||||
|
||||
+17
-14
@@ -210,7 +210,9 @@ char *get_boot_devices_list(size_t *size, bool ignore_suffixes)
|
||||
char *list = NULL;
|
||||
|
||||
QTAILQ_FOREACH(i, &fw_boot_order, link) {
|
||||
char *devpath = NULL, *bootpath;
|
||||
char *devpath = NULL, *suffix = NULL;
|
||||
char *bootpath;
|
||||
char *d;
|
||||
size_t len;
|
||||
|
||||
if (i->dev) {
|
||||
@@ -218,21 +220,22 @@ char *get_boot_devices_list(size_t *size, bool ignore_suffixes)
|
||||
assert(devpath);
|
||||
}
|
||||
|
||||
if (i->suffix && !ignore_suffixes && devpath) {
|
||||
size_t bootpathlen = strlen(devpath) + strlen(i->suffix) + 1;
|
||||
|
||||
bootpath = g_malloc(bootpathlen);
|
||||
snprintf(bootpath, bootpathlen, "%s%s", devpath, i->suffix);
|
||||
g_free(devpath);
|
||||
} else if (devpath) {
|
||||
bootpath = devpath;
|
||||
} else if (!ignore_suffixes) {
|
||||
assert(i->suffix);
|
||||
bootpath = g_strdup(i->suffix);
|
||||
} else {
|
||||
bootpath = g_strdup("");
|
||||
if (!ignore_suffixes) {
|
||||
d = qdev_get_own_fw_dev_path_from_handler(i->dev->parent_bus, i->dev);
|
||||
if (d) {
|
||||
assert(!i->suffix);
|
||||
suffix = d;
|
||||
} else {
|
||||
suffix = g_strdup(i->suffix);
|
||||
}
|
||||
}
|
||||
|
||||
bootpath = g_strdup_printf("%s%s",
|
||||
devpath ? devpath : "",
|
||||
suffix ? suffix : "");
|
||||
g_free(devpath);
|
||||
g_free(suffix);
|
||||
|
||||
if (total) {
|
||||
list[total-1] = '\n';
|
||||
}
|
||||
|
||||
+33
@@ -24,6 +24,9 @@
|
||||
#include "qemu/atomic.h"
|
||||
#include "sysemu/qtest.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "exec/memory-internal.h"
|
||||
#include "qemu/rcu.h"
|
||||
|
||||
/* -icount align implementation. */
|
||||
|
||||
@@ -141,6 +144,33 @@ void cpu_resume_from_signal(CPUState *cpu, void *puc)
|
||||
cpu->exception_index = -1;
|
||||
siglongjmp(cpu->jmp_env, 1);
|
||||
}
|
||||
|
||||
void cpu_reload_memory_map(CPUState *cpu)
|
||||
{
|
||||
AddressSpaceDispatch *d;
|
||||
|
||||
if (qemu_in_vcpu_thread()) {
|
||||
/* Do not let the guest prolong the critical section as much as it
|
||||
* as it desires.
|
||||
*
|
||||
* Currently, this is prevented by the I/O thread's periodinc kicking
|
||||
* of the VCPU thread (iothread_requesting_mutex, qemu_cpu_kick_thread)
|
||||
* but this will go away once TCG's execution moves out of the global
|
||||
* mutex.
|
||||
*
|
||||
* This pair matches cpu_exec's rcu_read_lock()/rcu_read_unlock(), which
|
||||
* only protects cpu->as->dispatch. Since we reload it below, we can
|
||||
* split the critical section.
|
||||
*/
|
||||
rcu_read_unlock();
|
||||
rcu_read_lock();
|
||||
}
|
||||
|
||||
/* The CPU and TLB are protected by the iothread lock. */
|
||||
d = atomic_rcu_read(&cpu->as->dispatch);
|
||||
cpu->memory_dispatch = d;
|
||||
tlb_flush(cpu, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Execute a TB, and fix up the CPU state afterwards if necessary */
|
||||
@@ -352,6 +382,8 @@ int cpu_exec(CPUArchState *env)
|
||||
* an instruction scheduling constraint on modern architectures. */
|
||||
smp_mb();
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
if (unlikely(exit_request)) {
|
||||
cpu->exit_request = 1;
|
||||
}
|
||||
@@ -548,6 +580,7 @@ int cpu_exec(CPUArchState *env)
|
||||
} /* for(;;) */
|
||||
|
||||
cc->cpu_exec_exit(cpu);
|
||||
rcu_read_unlock();
|
||||
|
||||
/* fail safe : never use current_cpu outside cpu_exec() */
|
||||
current_cpu = NULL;
|
||||
|
||||
@@ -1108,7 +1108,7 @@ bool qemu_cpu_is_self(CPUState *cpu)
|
||||
return qemu_thread_is_self(cpu->thread);
|
||||
}
|
||||
|
||||
static bool qemu_in_vcpu_thread(void)
|
||||
bool qemu_in_vcpu_thread(void)
|
||||
{
|
||||
return current_cpu && qemu_cpu_is_self(current_cpu);
|
||||
}
|
||||
|
||||
@@ -243,8 +243,12 @@ static void tlb_add_large_page(CPUArchState *env, target_ulong vaddr,
|
||||
}
|
||||
|
||||
/* Add a new TLB entry. At most one entry for a given virtual address
|
||||
is permitted. Only a single TARGET_PAGE_SIZE region is mapped, the
|
||||
supplied size is only used by tlb_flush_page. */
|
||||
* is permitted. Only a single TARGET_PAGE_SIZE region is mapped, the
|
||||
* supplied size is only used by tlb_flush_page.
|
||||
*
|
||||
* Called from TCG-generated code, which is under an RCU read-side
|
||||
* critical section.
|
||||
*/
|
||||
void tlb_set_page(CPUState *cpu, target_ulong vaddr,
|
||||
hwaddr paddr, int prot,
|
||||
int mmu_idx, target_ulong size)
|
||||
@@ -265,8 +269,7 @@ void tlb_set_page(CPUState *cpu, target_ulong vaddr,
|
||||
}
|
||||
|
||||
sz = size;
|
||||
section = address_space_translate_for_iotlb(cpu->as, paddr,
|
||||
&xlat, &sz);
|
||||
section = address_space_translate_for_iotlb(cpu, paddr, &xlat, &sz);
|
||||
assert(sz >= TARGET_PAGE_SIZE);
|
||||
|
||||
#if defined(DEBUG_TLB)
|
||||
@@ -347,7 +350,7 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr)
|
||||
cpu_ldub_code(env1, addr);
|
||||
}
|
||||
pd = env1->iotlb[mmu_idx][page_index] & ~TARGET_PAGE_MASK;
|
||||
mr = iotlb_to_region(cpu->as, pd);
|
||||
mr = iotlb_to_region(cpu, pd);
|
||||
if (memory_region_is_unassigned(mr)) {
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
|
||||
|
||||
+58
-16
@@ -73,17 +73,66 @@ stability.
|
||||
Region lifecycle
|
||||
----------------
|
||||
|
||||
A region is created by one of the constructor functions (memory_region_init*())
|
||||
and attached to an object. It is then destroyed by object_unparent() or simply
|
||||
when the parent object dies.
|
||||
A region is created by one of the memory_region_init*() functions and
|
||||
attached to an object, which acts as its owner or parent. QEMU ensures
|
||||
that the owner object remains alive as long as the region is visible to
|
||||
the guest, or as long as the region is in use by a virtual CPU or another
|
||||
device. For example, the owner object will not die between an
|
||||
address_space_map operation and the corresponding address_space_unmap.
|
||||
|
||||
In between, a region can be added to an address space
|
||||
by using memory_region_add_subregion() and removed using
|
||||
memory_region_del_subregion(). Destroying the region implicitly
|
||||
removes the region from the address space.
|
||||
After creation, a region can be added to an address space or a
|
||||
container with memory_region_add_subregion(), and removed using
|
||||
memory_region_del_subregion().
|
||||
|
||||
Various region attributes (read-only, dirty logging, coalesced mmio,
|
||||
ioeventfd) can be changed during the region lifecycle. They take effect
|
||||
as soon as the region is made visible. This can be immediately, later,
|
||||
or never.
|
||||
|
||||
Destruction of a memory region happens automatically when the owner
|
||||
object dies.
|
||||
|
||||
If however the memory region is part of a dynamically allocated data
|
||||
structure, you should call object_unparent() to destroy the memory region
|
||||
before the data structure is freed. For an example see VFIOMSIXInfo
|
||||
and VFIOQuirk in hw/vfio/pci.c.
|
||||
|
||||
You must not destroy a memory region as long as it may be in use by a
|
||||
device or CPU. In order to do this, as a general rule do not create or
|
||||
destroy memory regions dynamically during a device's lifetime, and only
|
||||
call object_unparent() in the memory region owner's instance_finalize
|
||||
callback. The dynamically allocated data structure that contains the
|
||||
memory region then should obviously be freed in the instance_finalize
|
||||
callback as well.
|
||||
|
||||
If you break this rule, the following situation can happen:
|
||||
|
||||
- the memory region's owner had a reference taken via memory_region_ref
|
||||
(for example by address_space_map)
|
||||
|
||||
- the region is unparented, and has no owner anymore
|
||||
|
||||
- when address_space_unmap is called, the reference to the memory region's
|
||||
owner is leaked.
|
||||
|
||||
|
||||
There is an exception to the above rule: it is okay to call
|
||||
object_unparent at any time for an alias or a container region. It is
|
||||
therefore also okay to create or destroy alias and container regions
|
||||
dynamically during a device's lifetime.
|
||||
|
||||
This exceptional usage is valid because aliases and containers only help
|
||||
QEMU building the guest's memory map; they are never accessed directly.
|
||||
memory_region_ref and memory_region_unref are never called on aliases
|
||||
or containers, and the above situation then cannot happen. Exploiting
|
||||
this exception is rarely necessary, and therefore it is discouraged,
|
||||
but nevertheless it is used in a few places.
|
||||
|
||||
For regions that "have no owner" (NULL is passed at creation time), the
|
||||
machine object is actually used as the owner. Since instance_finalize is
|
||||
never called for the machine object, you must never call object_unparent
|
||||
on regions that have no owner, unless they are aliases or containers.
|
||||
|
||||
Region attributes may be changed at any point; they take effect once
|
||||
the region becomes exposed to the guest.
|
||||
|
||||
Overlapping regions and priority
|
||||
--------------------------------
|
||||
@@ -215,13 +264,6 @@ BAR containing MMIO registers is mapped after it.
|
||||
Note that if the guest maps a BAR outside the PCI hole, it would not be
|
||||
visible as the pci-hole alias clips it to a 0.5GB range.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
|
||||
Various region attributes (read-only, dirty logging, coalesced mmio, ioeventfd)
|
||||
can be changed during the region lifecycle. They take effect once the region
|
||||
is made visible (which can be immediately, later, or never).
|
||||
|
||||
MMIO Operations
|
||||
---------------
|
||||
|
||||
|
||||
+7
-4
@@ -120,12 +120,15 @@ The core RCU API is small:
|
||||
void call_rcu(T *p,
|
||||
void (*func)(T *p),
|
||||
field-name);
|
||||
void g_free_rcu(T *p,
|
||||
field-name);
|
||||
|
||||
call_rcu1 is typically used through this macro, in the common case
|
||||
where the "struct rcu_head" is the first field in the struct. In
|
||||
the above case, one could have written simply:
|
||||
call_rcu1 is typically used through these macro, in the common case
|
||||
where the "struct rcu_head" is the first field in the struct. If
|
||||
the callback function is g_free, in particular, g_free_rcu can be
|
||||
used. In the above case, one could have written simply:
|
||||
|
||||
call_rcu(foo_reclaim, g_free, rcu);
|
||||
g_free_rcu(foo_reclaim, rcu);
|
||||
|
||||
typeof(*p) atomic_rcu_read(p);
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include "fsdev/qemu-fsdev.h"
|
||||
#include "virtio-9p-synth.h"
|
||||
#include "qemu/rcu.h"
|
||||
|
||||
#include "qemu/rcu_queue.h"
|
||||
#include <sys/stat.h>
|
||||
|
||||
/* Root node for synth file system */
|
||||
|
||||
@@ -818,6 +818,13 @@ static char *qdev_get_fw_dev_path_from_handler(BusState *bus, DeviceState *dev)
|
||||
return d;
|
||||
}
|
||||
|
||||
char *qdev_get_own_fw_dev_path_from_handler(BusState *bus, DeviceState *dev)
|
||||
{
|
||||
Object *obj = OBJECT(dev);
|
||||
|
||||
return fw_path_provider_try_get_dev_path(obj, bus, dev);
|
||||
}
|
||||
|
||||
static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
|
||||
{
|
||||
int l = 0;
|
||||
|
||||
@@ -745,6 +745,9 @@ static inline bool vtd_is_interrupt_addr(hwaddr addr)
|
||||
|
||||
/* Map dev to context-entry then do a paging-structures walk to do a iommu
|
||||
* translation.
|
||||
*
|
||||
* Called from RCU critical section.
|
||||
*
|
||||
* @bus_num: The bus number
|
||||
* @devfn: The devfn, which is the combined of device and function number
|
||||
* @is_write: The access is a write operation
|
||||
|
||||
@@ -97,6 +97,11 @@ static void pci_bridge_dev_exitfn(PCIDevice *dev)
|
||||
pci_bridge_exitfn(dev);
|
||||
}
|
||||
|
||||
static void pci_bridge_dev_instance_finalize(Object *obj)
|
||||
{
|
||||
shpc_free(PCI_DEVICE(obj));
|
||||
}
|
||||
|
||||
static void pci_bridge_dev_write_config(PCIDevice *d,
|
||||
uint32_t address, uint32_t val, int len)
|
||||
{
|
||||
@@ -154,10 +159,11 @@ static void pci_bridge_dev_class_init(ObjectClass *klass, void *data)
|
||||
}
|
||||
|
||||
static const TypeInfo pci_bridge_dev_info = {
|
||||
.name = TYPE_PCI_BRIDGE_DEV,
|
||||
.parent = TYPE_PCI_BRIDGE,
|
||||
.instance_size = sizeof(PCIBridgeDev),
|
||||
.class_init = pci_bridge_dev_class_init,
|
||||
.name = TYPE_PCI_BRIDGE_DEV,
|
||||
.parent = TYPE_PCI_BRIDGE,
|
||||
.instance_size = sizeof(PCIBridgeDev),
|
||||
.class_init = pci_bridge_dev_class_init,
|
||||
.instance_finalize = pci_bridge_dev_instance_finalize,
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
{ TYPE_HOTPLUG_HANDLER },
|
||||
{ }
|
||||
|
||||
@@ -205,6 +205,7 @@ static AddressSpace *pbm_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
|
||||
return &is->iommu_as;
|
||||
}
|
||||
|
||||
/* Called from RCU critical section */
|
||||
static IOMMUTLBEntry pbm_translate_iommu(MemoryRegion *iommu, hwaddr addr,
|
||||
bool is_write)
|
||||
{
|
||||
|
||||
+5
-2
@@ -88,6 +88,8 @@ static void pcie_host_init(Object *obj)
|
||||
PCIExpressHost *e = PCIE_HOST_BRIDGE(obj);
|
||||
|
||||
e->base_addr = PCIE_BASE_ADDR_UNMAPPED;
|
||||
memory_region_init_io(&e->mmio, OBJECT(e), &pcie_mmcfg_ops, e, "pcie-mmcfg-mmio",
|
||||
PCIE_MMCFG_SIZE_MAX);
|
||||
}
|
||||
|
||||
void pcie_host_mmcfg_unmap(PCIExpressHost *e)
|
||||
@@ -104,8 +106,7 @@ void pcie_host_mmcfg_init(PCIExpressHost *e, uint32_t size)
|
||||
assert(size >= PCIE_MMCFG_SIZE_MIN);
|
||||
assert(size <= PCIE_MMCFG_SIZE_MAX);
|
||||
e->size = size;
|
||||
memory_region_init_io(&e->mmio, OBJECT(e), &pcie_mmcfg_ops, e,
|
||||
"pcie-mmcfg", e->size);
|
||||
memory_region_set_size(&e->mmio, e->size);
|
||||
}
|
||||
|
||||
void pcie_host_mmcfg_map(PCIExpressHost *e, hwaddr addr,
|
||||
@@ -121,10 +122,12 @@ void pcie_host_mmcfg_update(PCIExpressHost *e,
|
||||
hwaddr addr,
|
||||
uint32_t size)
|
||||
{
|
||||
memory_region_transaction_begin();
|
||||
pcie_host_mmcfg_unmap(e);
|
||||
if (enable) {
|
||||
pcie_host_mmcfg_map(e, addr, size);
|
||||
}
|
||||
memory_region_transaction_commit();
|
||||
}
|
||||
|
||||
static const TypeInfo pcie_host_type_info = {
|
||||
|
||||
+10
-1
@@ -663,13 +663,22 @@ void shpc_cleanup(PCIDevice *d, MemoryRegion *bar)
|
||||
SHPCDevice *shpc = d->shpc;
|
||||
d->cap_present &= ~QEMU_PCI_CAP_SHPC;
|
||||
memory_region_del_subregion(bar, &shpc->mmio);
|
||||
object_unparent(OBJECT(&shpc->mmio));
|
||||
/* TODO: cleanup config space changes? */
|
||||
}
|
||||
|
||||
void shpc_free(PCIDevice *d)
|
||||
{
|
||||
SHPCDevice *shpc = d->shpc;
|
||||
if (!shpc) {
|
||||
return;
|
||||
}
|
||||
object_unparent(OBJECT(&shpc->mmio));
|
||||
g_free(shpc->config);
|
||||
g_free(shpc->cmask);
|
||||
g_free(shpc->wmask);
|
||||
g_free(shpc->w1cmask);
|
||||
g_free(shpc);
|
||||
d->shpc = NULL;
|
||||
}
|
||||
|
||||
void shpc_cap_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l)
|
||||
|
||||
@@ -59,6 +59,7 @@ static sPAPRTCETable *spapr_tce_find_by_liobn(uint32_t liobn)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Called from RCU critical section */
|
||||
static IOMMUTLBEntry spapr_tce_translate_iommu(MemoryRegion *iommu, hwaddr addr,
|
||||
bool is_write)
|
||||
{
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "hw/virtio/virtio-scsi.h"
|
||||
#include "hw/virtio/virtio-bus.h"
|
||||
#include "hw/virtio/virtio-access.h"
|
||||
#include "hw/fw-path-provider.h"
|
||||
|
||||
/* Features supported by host kernel. */
|
||||
static const int kernel_feature_bits[] = {
|
||||
@@ -250,6 +251,12 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
/* At present, channel and lun both are 0 for bootable vhost-scsi disk */
|
||||
s->channel = 0;
|
||||
s->lun = 0;
|
||||
/* Note: we can also get the minimum tpgt from kernel */
|
||||
s->target = vs->conf.boot_tpgt;
|
||||
|
||||
error_setg(&s->migration_blocker,
|
||||
"vhost-scsi does not support migration");
|
||||
migrate_add_blocker(s->migration_blocker);
|
||||
@@ -271,6 +278,19 @@ static void vhost_scsi_unrealize(DeviceState *dev, Error **errp)
|
||||
virtio_scsi_common_unrealize(dev, errp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Implementation of an interface to adjust firmware path
|
||||
* for the bootindex property handling.
|
||||
*/
|
||||
static char *vhost_scsi_get_fw_dev_path(FWPathProvider *p, BusState *bus,
|
||||
DeviceState *dev)
|
||||
{
|
||||
VHostSCSI *s = VHOST_SCSI(dev);
|
||||
/* format: channel@channel/vhost-scsi@target,lun */
|
||||
return g_strdup_printf("channel@%x/%s@%x,%x", s->channel,
|
||||
qdev_fw_name(dev), s->target, s->lun);
|
||||
}
|
||||
|
||||
static Property vhost_scsi_properties[] = {
|
||||
DEFINE_VHOST_SCSI_PROPERTIES(VHostSCSI, parent_obj.conf),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
@@ -280,6 +300,7 @@ static void vhost_scsi_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
|
||||
FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(klass);
|
||||
|
||||
dc->props = vhost_scsi_properties;
|
||||
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
|
||||
@@ -288,6 +309,15 @@ static void vhost_scsi_class_init(ObjectClass *klass, void *data)
|
||||
vdc->get_features = vhost_scsi_get_features;
|
||||
vdc->set_config = vhost_scsi_set_config;
|
||||
vdc->set_status = vhost_scsi_set_status;
|
||||
fwc->get_dev_path = vhost_scsi_get_fw_dev_path;
|
||||
}
|
||||
|
||||
static void vhost_scsi_instance_init(Object *obj)
|
||||
{
|
||||
VHostSCSI *dev = VHOST_SCSI(obj);
|
||||
|
||||
device_add_bootindex_property(obj, &dev->bootindex, "bootindex", NULL,
|
||||
DEVICE(dev), NULL);
|
||||
}
|
||||
|
||||
static const TypeInfo vhost_scsi_info = {
|
||||
@@ -295,6 +325,11 @@ static const TypeInfo vhost_scsi_info = {
|
||||
.parent = TYPE_VIRTIO_SCSI_COMMON,
|
||||
.instance_size = sizeof(VHostSCSI),
|
||||
.class_init = vhost_scsi_class_init,
|
||||
.instance_init = vhost_scsi_instance_init,
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
{ TYPE_FW_PATH_PROVIDER },
|
||||
{ }
|
||||
},
|
||||
};
|
||||
|
||||
static void virtio_register_types(void)
|
||||
|
||||
@@ -1238,6 +1238,8 @@ static void vhost_scsi_pci_instance_init(Object *obj)
|
||||
|
||||
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
|
||||
TYPE_VHOST_SCSI);
|
||||
object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
|
||||
"bootindex", &error_abort);
|
||||
}
|
||||
|
||||
static const TypeInfo vhost_scsi_pci_info = {
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "exec/memory.h"
|
||||
#include "qemu/thread.h"
|
||||
#include "qom/cpu.h"
|
||||
#include "qemu/rcu.h"
|
||||
|
||||
/* some important defines:
|
||||
*
|
||||
@@ -268,6 +269,7 @@ CPUArchState *cpu_copy(CPUArchState *env);
|
||||
typedef struct RAMBlock RAMBlock;
|
||||
|
||||
struct RAMBlock {
|
||||
struct rcu_head rcu;
|
||||
struct MemoryRegion *mr;
|
||||
uint8_t *host;
|
||||
ram_addr_t offset;
|
||||
@@ -275,11 +277,10 @@ struct RAMBlock {
|
||||
ram_addr_t max_length;
|
||||
void (*resized)(const char*, uint64_t length, void *host);
|
||||
uint32_t flags;
|
||||
/* Protected by iothread lock. */
|
||||
char idstr[256];
|
||||
/* Reads can take either the iothread or the ramlist lock.
|
||||
* Writes must take both locks.
|
||||
*/
|
||||
QTAILQ_ENTRY(RAMBlock) next;
|
||||
/* RCU-enabled, writes protected by the ramlist lock */
|
||||
QLIST_ENTRY(RAMBlock) next;
|
||||
int fd;
|
||||
};
|
||||
|
||||
@@ -295,8 +296,8 @@ typedef struct RAMList {
|
||||
/* Protected by the iothread lock. */
|
||||
unsigned long *dirty_memory[DIRTY_MEMORY_NUM];
|
||||
RAMBlock *mru_block;
|
||||
/* Protected by the ramlist lock. */
|
||||
QTAILQ_HEAD(, RAMBlock) blocks;
|
||||
/* RCU-enabled, writes protected by the ramlist lock. */
|
||||
QLIST_HEAD(, RAMBlock) blocks;
|
||||
uint32_t version;
|
||||
} RAMList;
|
||||
extern RAMList ram_list;
|
||||
|
||||
@@ -34,7 +34,7 @@ extern int tlb_flush_count;
|
||||
void tb_flush_jmp_cache(CPUState *cpu, target_ulong addr);
|
||||
|
||||
MemoryRegionSection *
|
||||
address_space_translate_for_iotlb(AddressSpace *as, hwaddr addr, hwaddr *xlat,
|
||||
address_space_translate_for_iotlb(CPUState *cpu, hwaddr addr, hwaddr *xlat,
|
||||
hwaddr *plen);
|
||||
hwaddr memory_region_section_get_iotlb(CPUState *cpu,
|
||||
MemoryRegionSection *section,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user