Compare commits

..

5 Commits

Author SHA1 Message Date
Fabiano Rosas
6321d78dc5 include/block/block_int: Document protocol related functions
Clarify that:

- for protocols the brdv_file_open function is used instead
of bdrv_open;

- when protocol_name is set, a driver should expect
to be given only a filename and no other options.

Signed-off-by: Fabiano Rosas <farosas@linux.vnet.ibm.com>
2018-03-12 18:11:01 -03:00
Fabiano Rosas
a0974f99aa block/blkreplay: Remove protocol-related fields
The blkreplay driver is not a protocol so it should implement bdrv_open
instead of bdrv_file_open and not provide a protocol_name.

Attempts to invoke this driver using protocol syntax
(i.e. blkreplay:<filename:options:...>) will now fail gracefully:

  $ qemu-img info blkreplay:foo
  qemu-img: Could not open 'blkreplay:foo': Unknown protocol 'blkreplay'

Signed-off-by: Fabiano Rosas <farosas@linux.vnet.ibm.com>
Reviewed-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
Reviewed-by: Max Reitz <mreitz@redhat.com>
2018-03-12 18:11:01 -03:00
Fabiano Rosas
42883c01bf block/throttle: Remove protocol-related fields
The throttle driver is not a protocol so it should implement bdrv_open
instead of bdrv_file_open and not provide a protocol_name.

Attempts to invoke this driver using protocol syntax
(i.e. throttle:<filename:options:...>) will now fail gracefully:

  $ qemu-img info throttle:foo
  qemu-img: Could not open 'throttle:foo': Unknown protocol 'throttle'

Signed-off-by: Fabiano Rosas <farosas@linux.vnet.ibm.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
2018-03-12 18:11:01 -03:00
Fabiano Rosas
7966c2b312 block/quorum: Remove protocol-related fields
The quorum driver is not a protocol so it should implement bdrv_open
instead of bdrv_file_open and not provide a protocol_name.

Attempts to invoke this driver using protocol syntax
(i.e. quorum:<filename:options:...>) will now fail gracefully:

  $ qemu-img info quorum:foo
  qemu-img: Could not open 'quorum:foo': Unknown protocol 'quorum'

Signed-off-by: Fabiano Rosas <farosas@linux.vnet.ibm.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
2018-03-12 18:11:01 -03:00
Fabiano Rosas
5888011244 block/replication: Remove protocol_name field
The protocol_name field is used when selecting a driver via protocol
syntax (i.e. <protocol_name>:<filename:options:...>). Drivers that are
only selected explicitly (e.g. driver=replication,mode=primary,...)
should not have a protocol_name.

This patch removes the protocol_name field from the brdv_replication
structure so that attempts to invoke this driver using protocol syntax
will fail gracefully:

  $ qemu-img info replication:foo
  qemu-img: Could not open 'replication:': Unknown protocol 'replication'

Buglink: https://bugs.launchpad.net/qemu/+bug/1726733
Signed-off-by: Fabiano Rosas <farosas@linux.vnet.ibm.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
2018-03-12 18:11:01 -03:00
477 changed files with 4528 additions and 22695 deletions

View File

@@ -49,10 +49,9 @@ env:
- TEST_CMD="make check"
- MAKEFLAGS="-j3"
matrix:
- CONFIG="--disable-system"
- CONFIG="--disable-user"
- CONFIG="--enable-debug --enable-debug-tcg"
- CONFIG="--disable-linux-aio --disable-cap-ng --disable-attr --disable-brlapi --disable-uuid --disable-libusb --disable-user"
- CONFIG=""
- CONFIG="--enable-debug --enable-debug-tcg --enable-trace-backends=log"
- CONFIG="--disable-linux-aio --disable-cap-ng --disable-attr --disable-brlapi --disable-uuid --disable-libusb"
- CONFIG="--enable-modules --disable-linux-user"
- CONFIG="--with-coroutine=ucontext --disable-linux-user"
- CONFIG="--with-coroutine=sigaltstack --disable-linux-user"

View File

@@ -127,6 +127,7 @@ Alpha
M: Richard Henderson <rth@twiddle.net>
S: Maintained
F: target/alpha/
F: hw/alpha/
F: tests/tcg/alpha/
F: disas/alpha.c
@@ -289,7 +290,7 @@ T: git git://github.com/ehabkost/qemu.git x86-next
Xtensa
M: Max Filippov <jcmvbkbc@gmail.com>
W: http://wiki.osll.ru/doku.php?id=etc:users:jcmvbkbc:qemu-target-xtensa
W: http://wiki.osll.spb.ru/doku.php?id=etc:users:jcmvbkbc:qemu-target-xtensa
S: Maintained
F: target/xtensa/
F: hw/xtensa/
@@ -412,12 +413,6 @@ F: include/*/*win32*
X: qga/*win32*
F: qemu.nsi
Alpha Machines
M: Richard Henderson <rth@twiddle.net>
S: Maintained
F: hw/alpha/
F: hw/isa/smc37c669-superio.c
ARM Machines
------------
Allwinner-a10
@@ -705,8 +700,6 @@ Fulong 2E
M: Yongbok Kim <yongbok.kim@mips.com>
S: Odd Fixes
F: hw/mips/mips_fulong2e.c
F: hw/isa/vt82c686.c
F: include/hw/isa/vt82c686.h
Boston
M: Paul Burton <paul.burton@mips.com>
@@ -783,10 +776,9 @@ F: hw/ppc/prep_systemio.c
F: hw/ppc/rs6000_mc.c
F: hw/pci-host/prep.[hc]
F: hw/isa/i82378.c
F: hw/isa/pc87312.c
F: hw/isa/pc87312.[hc]
F: hw/dma/i82374.c
F: hw/timer/m48t59-isa.c
F: include/hw/isa/pc87312.h
F: include/hw/timer/m48t59.h
F: pc-bios/ppc_rom.bin
@@ -932,7 +924,7 @@ M: Michael S. Tsirkin <mst@redhat.com>
M: Paolo Bonzini <pbonzini@redhat.com>
S: Supported
F: hw/char/debugcon.c
F: hw/char/parallel*
F: hw/char/parallel.c
F: hw/char/serial*
F: hw/dma/i8257*
F: hw/i2c/pm_smbus.c
@@ -940,7 +932,6 @@ F: hw/input/pckbd.c
F: hw/intc/apic*
F: hw/intc/ioapic*
F: hw/intc/i8259*
F: hw/isa/isa-superio.c
F: hw/misc/debugexit.c
F: hw/misc/pc-testdev.c
F: hw/timer/hpet*
@@ -948,11 +939,8 @@ F: hw/timer/i8254*
F: hw/timer/mc146818rtc*
F: hw/watchdog/wdt_ib700.c
F: include/hw/display/vga.h
F: include/hw/char/parallel.h
F: include/hw/dma/i8257.h
F: include/hw/i2c/pm_smbus.h
F: include/hw/input/i8042.h
F: include/hw/isa/superio.h
F: include/hw/isa/i8257.h
F: include/hw/timer/hpet.h
F: include/hw/timer/i8254*
F: include/hw/timer/mc146818rtc*

View File

@@ -438,23 +438,21 @@ all: $(DOCS) $(TOOLS) $(HELPERS-y) recurse-all modules
qemu-version.h: FORCE
$(call quiet-command, \
(cd $(SRC_PATH); \
printf '#define QEMU_PKGVERSION '; \
if test -n "$(PKGVERSION)"; then \
pkgvers="$(PKGVERSION)"; \
printf '"$(PKGVERSION)"\n'; \
else \
if test -d .git; then \
pkgvers=$$(git describe --match 'v*' 2>/dev/null | tr -d '\n');\
printf '" ('; \
git describe --match 'v*' 2>/dev/null | tr -d '\n'; \
if ! git diff-index --quiet HEAD &>/dev/null; then \
pkgvers="$${pkgvers}-dirty"; \
printf -- '-dirty'; \
fi; \
printf ')"\n'; \
else \
printf '""\n'; \
fi; \
fi; \
printf "#define QEMU_PKGVERSION \"$${pkgvers}\"\n"; \
if test -n "$${pkgvers}"; then \
printf '#define QEMU_FULL_VERSION QEMU_VERSION " (" QEMU_PKGVERSION ")"\n'; \
else \
printf '#define QEMU_FULL_VERSION QEMU_VERSION\n'; \
fi; \
) > $@.tmp)
fi) > $@.tmp)
$(call quiet-command, if ! cmp -s $@ $@.tmp; then \
mv $@.tmp $@; \
else \
@@ -777,6 +775,7 @@ bepo cz
ifdef INSTALL_BLOBS
BLOBS=bios.bin bios-256k.bin sgabios.bin vgabios.bin vgabios-cirrus.bin \
vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin vgabios-virtio.bin \
acpi-dsdt.aml \
ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc QEMU,tcx.bin QEMU,cgthree.bin \
pxe-e1000.rom pxe-eepro100.rom pxe-ne2k_pci.rom \
pxe-pcnet.rom pxe-rtl8139.rom pxe-virtio.rom \
@@ -1047,16 +1046,10 @@ endif
include $(SRC_PATH)/tests/docker/Makefile.include
include $(SRC_PATH)/tests/vm/Makefile.include
printgen:
@echo $(GENERATED_FILES)
.PHONY: help
help:
@echo 'Generic targets:'
@echo ' all - Build all'
ifdef CONFIG_MODULES
@echo ' modules - Build all modules'
endif
@echo ' dir/file.o - Build specified target only'
@echo ' install - Install QEMU, documentation and tools'
@echo ' ctags/TAGS - Generate tags file for editors'

View File

@@ -1 +1 @@
2.11.90
2.11.50

View File

@@ -1,4 +1,4 @@
obj-$(CONFIG_SOFTMMU) += accel.o
obj-$(CONFIG_KVM) += kvm/
obj-y += kvm/
obj-$(CONFIG_TCG) += tcg/
obj-y += stubs/

View File

@@ -1,2 +1 @@
obj-y += kvm-all.o
obj-$(call lnot,$(CONFIG_SEV)) += sev-stub.o
obj-$(CONFIG_KVM) += kvm-all.o

View File

@@ -38,7 +38,6 @@
#include "qemu/event_notifier.h"
#include "trace.h"
#include "hw/irq.h"
#include "sysemu/sev.h"
#include "hw/boards.h"
@@ -104,10 +103,6 @@ struct KVMState
#endif
KVMMemoryListener memory_listener;
QLIST_HEAD(, KVMParkedVcpu) kvm_parked_vcpus;
/* memory encryption */
void *memcrypt_handle;
int (*memcrypt_encrypt_data)(void *handle, uint8_t *ptr, uint64_t len);
};
KVMState *kvm_state;
@@ -143,26 +138,6 @@ int kvm_get_max_memslots(void)
return s->nr_slots;
}
bool kvm_memcrypt_enabled(void)
{
if (kvm_state && kvm_state->memcrypt_handle) {
return true;
}
return false;
}
int kvm_memcrypt_encrypt_data(uint8_t *ptr, uint64_t len)
{
if (kvm_state->memcrypt_handle &&
kvm_state->memcrypt_encrypt_data) {
return kvm_state->memcrypt_encrypt_data(kvm_state->memcrypt_handle,
ptr, len);
}
return 1;
}
static KVMSlot *kvm_get_free_slot(KVMMemoryListener *kml)
{
KVMState *s = kvm_state;
@@ -1661,20 +1636,6 @@ static int kvm_init(MachineState *ms)
kvm_state = s;
/*
* if memory encryption object is specified then initialize the memory
* encryption context.
*/
if (ms->memory_encryption) {
kvm_state->memcrypt_handle = sev_guest_init(ms->memory_encryption);
if (!kvm_state->memcrypt_handle) {
ret = -1;
goto err;
}
kvm_state->memcrypt_encrypt_data = sev_encrypt_data;
}
ret = kvm_arch_init(ms, s);
if (ret < 0) {
goto err;

View File

@@ -1,26 +0,0 @@
/*
* QEMU SEV stub
*
* Copyright Advanced Micro Devices 2018
*
* Authors:
* Brijesh Singh <brijesh.singh@amd.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*
*/
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "sysemu/sev.h"
int sev_encrypt_data(void *handle, uint8_t *ptr, uint64_t len)
{
abort();
}
void *sev_guest_init(const char *id)
{
return NULL;
}

View File

@@ -105,16 +105,6 @@ int kvm_on_sigbus(int code, void *addr)
return 1;
}
bool kvm_memcrypt_enabled(void)
{
return false;
}
int kvm_memcrypt_encrypt_data(uint8_t *ptr, uint64_t len)
{
return 1;
}
#ifndef CONFIG_USER_ONLY
int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev)
{

View File

@@ -585,7 +585,6 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
else {
if (cc->cpu_exec_interrupt(cpu, interrupt_request)) {
replay_interrupt();
cpu->exception_index = -1;
*last_tb = NULL;
}
/* The target hook may have updated the 'cpu->interrupt_request';
@@ -607,9 +606,7 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
if (unlikely(atomic_read(&cpu->exit_request)
|| (use_icount && cpu->icount_decr.u16.low + cpu->icount_extra == 0))) {
atomic_set(&cpu->exit_request, 0);
if (cpu->exception_index == -1) {
cpu->exception_index = EXCP_INTERRUPT;
}
cpu->exception_index = EXCP_INTERRUPT;
return true;
}

View File

@@ -1728,8 +1728,7 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr)
CPUArchState *env = cpu->env_ptr;
#endif
TranslationBlock *tb;
uint32_t n, flags;
target_ulong pc, cs_base;
uint32_t n;
tb_lock();
tb = tb_find_pc(retaddr);
@@ -1767,14 +1766,8 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr)
cpu_abort(cpu, "TB too big during recompile");
}
pc = tb->pc;
cs_base = tb->cs_base;
flags = tb->flags;
tb_phys_invalidate(tb, -1);
/* Execute one IO instruction without caching
instead of creating large TB. */
cpu->cflags_next_tb = curr_cflags() | CF_LAST_IO | CF_NOCACHE | 1;
/* Adjust the execution state of the next TB. */
cpu->cflags_next_tb = curr_cflags() | CF_LAST_IO | n;
if (tb->cflags & CF_NOCACHE) {
if (tb->orig_tb) {
@@ -1785,11 +1778,6 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr)
tb_remove(tb);
}
/* Generate new TB instead of the current one. */
/* FIXME: In theory this could raise an exception. In practice
we have already translated the block once so it's probably ok. */
tb_gen_code(cpu, pc, cs_base, flags, curr_cflags() | CF_LAST_IO | n);
/* TODO: If env->pc != tb->pc (i.e. the faulting instruction was not
* the first in the TB) then we end up generating a whole new TB and
* repeating the fault, which is horribly inefficient.

23
block.c
View File

@@ -33,7 +33,6 @@
#include "qapi/error.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qjson.h"
#include "qapi/qmp/qnull.h"
#include "qapi/qmp/qstring.h"
#include "qapi/qobject-output-visitor.h"
#include "qapi/qapi-visit-block-core.h"
@@ -1458,7 +1457,7 @@ static QDict *parse_json_filename(const char *filename, Error **errp)
return NULL;
}
options = qobject_to(QDict, options_obj);
options = qobject_to_qdict(options_obj);
if (!options) {
qobject_decref(options_obj);
error_setg(errp, "Invalid JSON object given");
@@ -2434,7 +2433,7 @@ BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp)
}
visit_complete(v, &obj);
qdict = qobject_to(QDict, obj);
qdict = qobject_to_qdict(obj);
qdict_flatten(qdict);
/* bdrv_open_inherit() defaults to the values in bdrv_flags (for
@@ -2646,13 +2645,7 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
/* See cautionary note on accessing @options above */
backing = qdict_get_try_str(options, "backing");
if (qobject_to(QNull, qdict_get(options, "backing")) != NULL ||
(backing && *backing == '\0'))
{
if (backing) {
warn_report("Use of \"backing\": \"\" is deprecated; "
"use \"backing\": null instead");
}
if (backing && *backing == '\0') {
flags |= BDRV_O_NO_BACKING;
qdict_del(options, "backing");
}
@@ -2890,16 +2883,8 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
/* Inherit from parent node */
if (parent_options) {
QemuOpts *opts;
QDict *options_copy;
assert(!flags);
role->inherit_options(&flags, options, parent_flags, parent_options);
options_copy = qdict_clone_shallow(options);
opts = qemu_opts_create(&bdrv_runtime_opts, NULL, 0, &error_abort);
qemu_opts_absorb_qdict(opts, options_copy, NULL);
update_flags_from_options(&flags, opts);
qemu_opts_del(opts);
QDECREF(options_copy);
}
/* Old values are used for options that aren't set yet */
@@ -3686,12 +3671,12 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
GSList *ignore_children = g_slist_prepend(NULL, c);
bdrv_check_update_perm(base, NULL, c->perm, c->shared_perm,
ignore_children, &local_err);
g_slist_free(ignore_children);
if (local_err) {
ret = -EPERM;
error_report_err(local_err);
goto exit;
}
g_slist_free(ignore_children);
/* If so, update the backing file path in the image file */
if (c->role->update_filename) {

View File

@@ -94,94 +94,6 @@ void block_acct_start(BlockAcctStats *stats, BlockAcctCookie *cookie,
cookie->type = type;
}
/* block_latency_histogram_compare_func:
* Compare @key with interval [@it[0], @it[1]).
* Return: -1 if @key < @it[0]
* 0 if @key in [@it[0], @it[1])
* +1 if @key >= @it[1]
*/
static int block_latency_histogram_compare_func(const void *key, const void *it)
{
uint64_t k = *(uint64_t *)key;
uint64_t a = ((uint64_t *)it)[0];
uint64_t b = ((uint64_t *)it)[1];
return k < a ? -1 : (k < b ? 0 : 1);
}
static void block_latency_histogram_account(BlockLatencyHistogram *hist,
int64_t latency_ns)
{
uint64_t *pos;
if (hist->bins == NULL) {
/* histogram disabled */
return;
}
if (latency_ns < hist->boundaries[0]) {
hist->bins[0]++;
return;
}
if (latency_ns >= hist->boundaries[hist->nbins - 2]) {
hist->bins[hist->nbins - 1]++;
return;
}
pos = bsearch(&latency_ns, hist->boundaries, hist->nbins - 2,
sizeof(hist->boundaries[0]),
block_latency_histogram_compare_func);
assert(pos != NULL);
hist->bins[pos - hist->boundaries + 1]++;
}
int block_latency_histogram_set(BlockAcctStats *stats, enum BlockAcctType type,
uint64List *boundaries)
{
BlockLatencyHistogram *hist = &stats->latency_histogram[type];
uint64List *entry;
uint64_t *ptr;
uint64_t prev = 0;
int new_nbins = 1;
for (entry = boundaries; entry; entry = entry->next) {
if (entry->value <= prev) {
return -EINVAL;
}
new_nbins++;
prev = entry->value;
}
hist->nbins = new_nbins;
g_free(hist->boundaries);
hist->boundaries = g_new(uint64_t, hist->nbins - 1);
for (entry = boundaries, ptr = hist->boundaries; entry;
entry = entry->next, ptr++)
{
*ptr = entry->value;
}
g_free(hist->bins);
hist->bins = g_new0(uint64_t, hist->nbins);
return 0;
}
void block_latency_histograms_clear(BlockAcctStats *stats)
{
int i;
for (i = 0; i < BLOCK_MAX_IOTYPE; i++) {
BlockLatencyHistogram *hist = &stats->latency_histogram[i];
g_free(hist->bins);
g_free(hist->boundaries);
memset(hist, 0, sizeof(*hist));
}
}
static void block_account_one_io(BlockAcctStats *stats, BlockAcctCookie *cookie,
bool failed)
{
@@ -204,9 +116,6 @@ static void block_account_one_io(BlockAcctStats *stats, BlockAcctCookie *cookie,
stats->nr_ops[cookie->type]++;
}
block_latency_histogram_account(&stats->latency_histogram[cookie->type],
latency_ns);
if (!failed || stats->account_failed) {
stats->total_time_ns[cookie->type] += latency_ns;
stats->last_access_time_ns = time_ns;

View File

@@ -206,7 +206,7 @@ static void backup_cleanup_sync_bitmap(BackupBlockJob *job, int ret)
BdrvDirtyBitmap *bm;
BlockDriverState *bs = blk_bs(job->common.blk);
if (ret < 0) {
if (ret < 0 || block_job_is_cancelled(&job->common)) {
/* Merge the successor back into the parent, delete nothing. */
bm = bdrv_reclaim_dirty_bitmap(bs, job->sync_bitmap, NULL);
assert(bm);
@@ -621,7 +621,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
}
/* job->common.len is fixed, so we can't allow resize */
job = block_job_create(job_id, &backup_job_driver, txn, bs,
job = block_job_create(job_id, &backup_job_driver, bs,
BLK_PERM_CONSISTENT_READ,
BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE |
BLK_PERM_WRITE_UNCHANGED | BLK_PERM_GRAPH_MOD,
@@ -677,6 +677,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL,
&error_abort);
job->common.len = len;
block_job_txn_add_job(txn, &job->common);
return &job->common;

View File

@@ -129,10 +129,9 @@ static int coroutine_fn blkreplay_co_flush(BlockDriverState *bs)
static BlockDriver bdrv_blkreplay = {
.format_name = "blkreplay",
.protocol_name = "blkreplay",
.instance_size = 0,
.bdrv_file_open = blkreplay_open,
.bdrv_open = blkreplay_open,
.bdrv_close = blkreplay_close,
.bdrv_child_perm = bdrv_filter_default_perms,
.bdrv_getlength = blkreplay_getlength,

View File

@@ -31,13 +31,6 @@
static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb);
typedef struct BlockBackendAioNotifier {
void (*attached_aio_context)(AioContext *new_context, void *opaque);
void (*detach_aio_context)(void *opaque);
void *opaque;
QLIST_ENTRY(BlockBackendAioNotifier) list;
} BlockBackendAioNotifier;
struct BlockBackend {
char *name;
int refcnt;
@@ -76,7 +69,6 @@ struct BlockBackend {
bool allow_write_beyond_eof;
NotifierList remove_bs_notifiers, insert_bs_notifiers;
QLIST_HEAD(, BlockBackendAioNotifier) aio_notifiers;
int quiesce_counter;
VMChangeStateEntry *vmsh;
@@ -255,36 +247,6 @@ static int blk_root_inactivate(BdrvChild *child)
return 0;
}
static void blk_root_attach(BdrvChild *child)
{
BlockBackend *blk = child->opaque;
BlockBackendAioNotifier *notifier;
trace_blk_root_attach(child, blk, child->bs);
QLIST_FOREACH(notifier, &blk->aio_notifiers, list) {
bdrv_add_aio_context_notifier(child->bs,
notifier->attached_aio_context,
notifier->detach_aio_context,
notifier->opaque);
}
}
static void blk_root_detach(BdrvChild *child)
{
BlockBackend *blk = child->opaque;
BlockBackendAioNotifier *notifier;
trace_blk_root_detach(child, blk, child->bs);
QLIST_FOREACH(notifier, &blk->aio_notifiers, list) {
bdrv_remove_aio_context_notifier(child->bs,
notifier->attached_aio_context,
notifier->detach_aio_context,
notifier->opaque);
}
}
static const BdrvChildRole child_root = {
.inherit_options = blk_root_inherit_options,
@@ -298,9 +260,6 @@ static const BdrvChildRole child_root = {
.activate = blk_root_activate,
.inactivate = blk_root_inactivate,
.attach = blk_root_attach,
.detach = blk_root_detach,
};
/*
@@ -328,7 +287,6 @@ BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm)
notifier_list_init(&blk->remove_bs_notifiers);
notifier_list_init(&blk->insert_bs_notifiers);
QLIST_INIT(&blk->aio_notifiers);
QTAILQ_INSERT_TAIL(&block_backends, blk, link);
return blk;
@@ -406,7 +364,6 @@ static void blk_delete(BlockBackend *blk)
}
assert(QLIST_EMPTY(&blk->remove_bs_notifiers.notifiers));
assert(QLIST_EMPTY(&blk->insert_bs_notifiers.notifiers));
assert(QLIST_EMPTY(&blk->aio_notifiers));
QTAILQ_REMOVE(&block_backends, blk, link);
drive_info_del(blk->legacy_dinfo);
block_acct_cleanup(&blk->stats);
@@ -1900,15 +1857,8 @@ void blk_add_aio_context_notifier(BlockBackend *blk,
void (*attached_aio_context)(AioContext *new_context, void *opaque),
void (*detach_aio_context)(void *opaque), void *opaque)
{
BlockBackendAioNotifier *notifier;
BlockDriverState *bs = blk_bs(blk);
notifier = g_new(BlockBackendAioNotifier, 1);
notifier->attached_aio_context = attached_aio_context;
notifier->detach_aio_context = detach_aio_context;
notifier->opaque = opaque;
QLIST_INSERT_HEAD(&blk->aio_notifiers, notifier, list);
if (bs) {
bdrv_add_aio_context_notifier(bs, attached_aio_context,
detach_aio_context, opaque);
@@ -1921,25 +1871,12 @@ void blk_remove_aio_context_notifier(BlockBackend *blk,
void (*detach_aio_context)(void *),
void *opaque)
{
BlockBackendAioNotifier *notifier;
BlockDriverState *bs = blk_bs(blk);
if (bs) {
bdrv_remove_aio_context_notifier(bs, attached_aio_context,
detach_aio_context, opaque);
}
QLIST_FOREACH(notifier, &blk->aio_notifiers, list) {
if (notifier->attached_aio_context == attached_aio_context &&
notifier->detach_aio_context == detach_aio_context &&
notifier->opaque == opaque) {
QLIST_REMOVE(notifier, list);
g_free(notifier);
return;
}
}
abort();
}
void blk_add_remove_bs_notifier(BlockBackend *blk, Notifier *notify)

View File

@@ -289,7 +289,7 @@ void commit_start(const char *job_id, BlockDriverState *bs,
return;
}
s = block_job_create(job_id, &commit_job_driver, NULL, bs, 0, BLK_PERM_ALL,
s = block_job_create(job_id, &commit_job_driver, bs, 0, BLK_PERM_ALL,
speed, BLOCK_JOB_DEFAULT, NULL, NULL, errp);
if (!s) {
return;

View File

@@ -71,6 +71,8 @@ static ssize_t block_crypto_read_func(QCryptoBlock *block,
struct BlockCryptoCreateData {
const char *filename;
QemuOpts *opts;
BlockBackend *blk;
uint64_t size;
};
@@ -101,18 +103,27 @@ static ssize_t block_crypto_init_func(QCryptoBlock *block,
Error **errp)
{
struct BlockCryptoCreateData *data = opaque;
if (data->size > INT64_MAX || headerlen > INT64_MAX - data->size) {
error_setg(errp, "The requested file size is too large");
return -EFBIG;
}
int ret;
/* User provided size should reflect amount of space made
* available to the guest, so we must take account of that
* which will be used by the crypto header
*/
return blk_truncate(data->blk, data->size + headerlen, PREALLOC_MODE_OFF,
errp);
data->size += headerlen;
qemu_opt_set_number(data->opts, BLOCK_OPT_SIZE, data->size, &error_abort);
ret = bdrv_create_file(data->filename, data->opts, errp);
if (ret < 0) {
return -1;
}
data->blk = blk_new_open(data->filename, NULL, NULL,
BDRV_O_RDWR | BDRV_O_PROTOCOL, errp);
if (!data->blk) {
return -1;
}
return 0;
}
@@ -311,29 +322,30 @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
}
static int block_crypto_co_create_generic(BlockDriverState *bs,
int64_t size,
QCryptoBlockCreateOptions *opts,
Error **errp)
static int block_crypto_create_generic(QCryptoBlockFormat format,
const char *filename,
QemuOpts *opts,
Error **errp)
{
int ret;
BlockBackend *blk;
int ret = -EINVAL;
QCryptoBlockCreateOptions *create_opts = NULL;
QCryptoBlock *crypto = NULL;
struct BlockCryptoCreateData data;
struct BlockCryptoCreateData data = {
.size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
BDRV_SECTOR_SIZE),
.opts = opts,
.filename = filename,
};
QDict *cryptoopts;
blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
cryptoopts = qemu_opts_to_qdict(opts, NULL);
ret = blk_insert_bs(blk, bs, errp);
if (ret < 0) {
goto cleanup;
create_opts = block_crypto_create_opts_init(format, cryptoopts, errp);
if (!create_opts) {
return -1;
}
data = (struct BlockCryptoCreateData) {
.blk = blk,
.size = size,
};
crypto = qcrypto_block_create(opts, NULL,
crypto = qcrypto_block_create(create_opts, NULL,
block_crypto_init_func,
block_crypto_write_func,
&data,
@@ -346,8 +358,10 @@ static int block_crypto_co_create_generic(BlockDriverState *bs,
ret = 0;
cleanup:
QDECREF(cryptoopts);
qcrypto_block_free(crypto);
blk_unref(blk);
blk_unref(data.blk);
qapi_free_QCryptoBlockCreateOptions(create_opts);
return ret;
}
@@ -523,10 +537,7 @@ static int64_t block_crypto_getlength(BlockDriverState *bs)
uint64_t offset = qcrypto_block_get_payload_offset(crypto->block);
assert(offset < INT64_MAX);
if (offset > len) {
return -EIO;
}
assert(offset < len);
len -= offset;
@@ -551,88 +562,12 @@ static int block_crypto_open_luks(BlockDriverState *bs,
bs, options, flags, errp);
}
static int coroutine_fn
block_crypto_co_create_luks(BlockdevCreateOptions *create_options, Error **errp)
{
BlockdevCreateOptionsLUKS *luks_opts;
BlockDriverState *bs = NULL;
QCryptoBlockCreateOptions create_opts;
int ret;
assert(create_options->driver == BLOCKDEV_DRIVER_LUKS);
luks_opts = &create_options->u.luks;
bs = bdrv_open_blockdev_ref(luks_opts->file, errp);
if (bs == NULL) {
return -EIO;
}
create_opts = (QCryptoBlockCreateOptions) {
.format = Q_CRYPTO_BLOCK_FORMAT_LUKS,
.u.luks = *qapi_BlockdevCreateOptionsLUKS_base(luks_opts),
};
ret = block_crypto_co_create_generic(bs, luks_opts->size, &create_opts,
errp);
if (ret < 0) {
goto fail;
}
ret = 0;
fail:
bdrv_unref(bs);
return ret;
}
static int coroutine_fn block_crypto_co_create_opts_luks(const char *filename,
QemuOpts *opts,
Error **errp)
{
QCryptoBlockCreateOptions *create_opts = NULL;
BlockDriverState *bs = NULL;
QDict *cryptoopts;
int64_t size;
int ret;
/* Parse options */
size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
cryptoopts = qemu_opts_to_qdict_filtered(opts, NULL,
&block_crypto_create_opts_luks,
true);
create_opts = block_crypto_create_opts_init(Q_CRYPTO_BLOCK_FORMAT_LUKS,
cryptoopts, errp);
if (!create_opts) {
ret = -EINVAL;
goto fail;
}
/* Create protocol layer */
ret = bdrv_create_file(filename, opts, errp);
if (ret < 0) {
return ret;
}
bs = bdrv_open(filename, NULL, NULL,
BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp);
if (!bs) {
ret = -EINVAL;
goto fail;
}
/* Create format layer */
ret = block_crypto_co_create_generic(bs, size, create_opts, errp);
if (ret < 0) {
goto fail;
}
ret = 0;
fail:
bdrv_unref(bs);
qapi_free_QCryptoBlockCreateOptions(create_opts);
QDECREF(cryptoopts);
return ret;
return block_crypto_create_generic(Q_CRYPTO_BLOCK_FORMAT_LUKS,
filename, opts, errp);
}
static int block_crypto_get_info_luks(BlockDriverState *bs,
@@ -688,7 +623,6 @@ BlockDriver bdrv_crypto_luks = {
.bdrv_open = block_crypto_open_luks,
.bdrv_close = block_crypto_close,
.bdrv_child_perm = bdrv_format_default_perms,
.bdrv_co_create = block_crypto_co_create_luks,
.bdrv_co_create_opts = block_crypto_co_create_opts_luks,
.bdrv_truncate = block_crypto_truncate,
.create_opts = &block_crypto_create_opts_luks,

View File

@@ -40,8 +40,6 @@ struct BdrvDirtyBitmap {
QemuMutex *mutex;
HBitmap *bitmap; /* Dirty bitmap implementation */
HBitmap *meta; /* Meta dirty bitmap */
bool qmp_locked; /* Bitmap is locked, it can't be modified
through QMP */
BdrvDirtyBitmap *successor; /* Anonymous child; implies frozen status */
char *name; /* Optional non-empty unique ID */
int64_t size; /* Size of the bitmap, in bytes */
@@ -185,18 +183,6 @@ bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap)
return bitmap->successor;
}
void bdrv_dirty_bitmap_set_qmp_locked(BdrvDirtyBitmap *bitmap, bool qmp_locked)
{
qemu_mutex_lock(bitmap->mutex);
bitmap->qmp_locked = qmp_locked;
qemu_mutex_unlock(bitmap->mutex);
}
bool bdrv_dirty_bitmap_qmp_locked(BdrvDirtyBitmap *bitmap)
{
return bitmap->qmp_locked;
}
/* Called with BQL taken. */
bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap)
{
@@ -208,8 +194,6 @@ DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap)
{
if (bdrv_dirty_bitmap_frozen(bitmap)) {
return DIRTY_BITMAP_STATUS_FROZEN;
} else if (bdrv_dirty_bitmap_qmp_locked(bitmap)) {
return DIRTY_BITMAP_STATUS_LOCKED;
} else if (!bdrv_dirty_bitmap_enabled(bitmap)) {
return DIRTY_BITMAP_STATUS_DISABLED;
} else {
@@ -250,59 +234,6 @@ int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs,
return 0;
}
/* Called with BQL taken. */
void bdrv_dirty_bitmap_enable_successor(BdrvDirtyBitmap *bitmap)
{
qemu_mutex_lock(bitmap->mutex);
bdrv_enable_dirty_bitmap(bitmap->successor);
qemu_mutex_unlock(bitmap->mutex);
}
/* Called within bdrv_dirty_bitmap_lock..unlock */
static void bdrv_do_release_matching_dirty_bitmap_locked(
BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
bool (*cond)(BdrvDirtyBitmap *bitmap))
{
BdrvDirtyBitmap *bm, *next;
QLIST_FOREACH_SAFE(bm, &bs->dirty_bitmaps, list, next) {
if ((!bitmap || bm == bitmap) && (!cond || cond(bm))) {
assert(!bm->active_iterators);
assert(!bdrv_dirty_bitmap_frozen(bm));
assert(!bm->meta);
QLIST_REMOVE(bm, list);
hbitmap_free(bm->bitmap);
g_free(bm->name);
g_free(bm);
if (bitmap) {
return;
}
}
}
if (bitmap) {
abort();
}
}
/* Called with BQL taken. */
static void bdrv_do_release_matching_dirty_bitmap(
BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
bool (*cond)(BdrvDirtyBitmap *bitmap))
{
bdrv_dirty_bitmaps_lock(bs);
bdrv_do_release_matching_dirty_bitmap_locked(bs, bitmap, cond);
bdrv_dirty_bitmaps_unlock(bs);
}
/* Called within bdrv_dirty_bitmap_lock..unlock */
static void bdrv_release_dirty_bitmap_locked(BlockDriverState *bs,
BdrvDirtyBitmap *bitmap)
{
bdrv_do_release_matching_dirty_bitmap_locked(bs, bitmap, NULL);
}
/**
* For a bitmap with a successor, yield our name to the successor,
* delete the old bitmap, and return a handle to the new bitmap.
@@ -336,11 +267,11 @@ BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs,
* In cases of failure where we can no longer safely delete the parent,
* we may wish to re-join the parent and child/successor.
* The merged parent will be un-frozen, but not explicitly re-enabled.
* Called within bdrv_dirty_bitmap_lock..unlock and with BQL taken.
* Called with BQL taken.
*/
BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap_locked(BlockDriverState *bs,
BdrvDirtyBitmap *parent,
Error **errp)
BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap(BlockDriverState *bs,
BdrvDirtyBitmap *parent,
Error **errp)
{
BdrvDirtyBitmap *successor = parent->successor;
@@ -353,26 +284,12 @@ BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap_locked(BlockDriverState *bs,
error_setg(errp, "Merging of parent and successor bitmap failed");
return NULL;
}
bdrv_release_dirty_bitmap_locked(bs, successor);
bdrv_release_dirty_bitmap(bs, successor);
parent->successor = NULL;
return parent;
}
/* Called with BQL taken. */
BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap(BlockDriverState *bs,
BdrvDirtyBitmap *parent,
Error **errp)
{
BdrvDirtyBitmap *ret;
qemu_mutex_lock(parent->mutex);
ret = bdrv_reclaim_dirty_bitmap_locked(bs, parent, errp);
qemu_mutex_unlock(parent->mutex);
return ret;
}
/**
* Truncates _all_ bitmaps attached to a BDS.
* Called with BQL taken.
@@ -396,6 +313,36 @@ static bool bdrv_dirty_bitmap_has_name(BdrvDirtyBitmap *bitmap)
return !!bdrv_dirty_bitmap_name(bitmap);
}
/* Called with BQL taken. */
static void bdrv_do_release_matching_dirty_bitmap(
BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
bool (*cond)(BdrvDirtyBitmap *bitmap))
{
BdrvDirtyBitmap *bm, *next;
bdrv_dirty_bitmaps_lock(bs);
QLIST_FOREACH_SAFE(bm, &bs->dirty_bitmaps, list, next) {
if ((!bitmap || bm == bitmap) && (!cond || cond(bm))) {
assert(!bm->active_iterators);
assert(!bdrv_dirty_bitmap_frozen(bm));
assert(!bm->meta);
QLIST_REMOVE(bm, list);
hbitmap_free(bm->bitmap);
g_free(bm->name);
g_free(bm);
if (bitmap) {
goto out;
}
}
}
if (bitmap) {
abort();
}
out:
bdrv_dirty_bitmaps_unlock(bs);
}
/* Called with BQL taken. */
void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
{

View File

@@ -665,7 +665,7 @@ static int qemu_gluster_parse(BlockdevOptionsGluster *gconf,
if (filename) {
ret = qemu_gluster_parse_uri(gconf, filename);
if (ret < 0) {
error_setg(errp, "invalid URI %s", filename);
error_setg(errp, "invalid URI");
error_append_hint(errp, "Usage: file=gluster[+transport]://"
"[host[:port]]volume/path[?socket=...]"
"[,file.debug=N]"

View File

@@ -2244,7 +2244,7 @@ static BlockDriver bdrv_iser = {
.create_opts = &iscsi_create_opts,
.bdrv_reopen_prepare = iscsi_reopen_prepare,
.bdrv_reopen_commit = iscsi_reopen_commit,
.bdrv_co_invalidate_cache = iscsi_co_invalidate_cache,
.bdrv_invalidate_cache = iscsi_invalidate_cache,
.bdrv_getlength = iscsi_getlength,
.bdrv_get_info = iscsi_get_info,

View File

@@ -869,8 +869,11 @@ static void coroutine_fn mirror_run(void *opaque)
ret = 0;
trace_mirror_before_sleep(s, cnt, s->synced, delay_ns);
if (block_job_is_cancelled(&s->common) && s->common.force) {
break;
if (!s->synced) {
block_job_sleep_ns(&s->common, delay_ns);
if (block_job_is_cancelled(&s->common)) {
break;
}
} else if (!should_complete) {
delay_ns = (s->in_flight == 0 && cnt == 0 ? SLICE_TIME : 0);
block_job_sleep_ns(&s->common, delay_ns);
@@ -884,8 +887,7 @@ immediate_exit:
* or it was cancelled prematurely so that we do not guarantee that
* the target is a copy of the source.
*/
assert(ret < 0 || ((s->common.force || !s->synced) &&
block_job_is_cancelled(&s->common)));
assert(ret < 0 || (!s->synced && block_job_is_cancelled(&s->common)));
assert(need_drain);
mirror_wait_for_all_io(s);
}
@@ -1164,7 +1166,7 @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
}
/* Make sure that the source is not resized while the job is running */
s = block_job_create(job_id, driver, NULL, mirror_top_bs,
s = block_job_create(job_id, driver, mirror_top_bs,
BLK_PERM_CONSISTENT_READ,
BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED |
BLK_PERM_WRITE | BLK_PERM_GRAPH_MOD, speed,

View File

@@ -228,48 +228,6 @@ static int nbd_parse_offset_hole_payload(NBDStructuredReplyChunk *chunk,
return 0;
}
/* nbd_parse_blockstatus_payload
* support only one extent in reply and only for
* base:allocation context
*/
static int nbd_parse_blockstatus_payload(NBDClientSession *client,
NBDStructuredReplyChunk *chunk,
uint8_t *payload, uint64_t orig_length,
NBDExtent *extent, Error **errp)
{
uint32_t context_id;
if (chunk->length != sizeof(context_id) + sizeof(extent)) {
error_setg(errp, "Protocol error: invalid payload for "
"NBD_REPLY_TYPE_BLOCK_STATUS");
return -EINVAL;
}
context_id = payload_advance32(&payload);
if (client->info.meta_base_allocation_id != context_id) {
error_setg(errp, "Protocol error: unexpected context id %d for "
"NBD_REPLY_TYPE_BLOCK_STATUS, when negotiated context "
"id is %d", context_id,
client->info.meta_base_allocation_id);
return -EINVAL;
}
extent->length = payload_advance32(&payload);
extent->flags = payload_advance32(&payload);
if (extent->length == 0 ||
(client->info.min_block && !QEMU_IS_ALIGNED(extent->length,
client->info.min_block)) ||
extent->length > orig_length)
{
error_setg(errp, "Protocol error: server sent status chunk with "
"invalid length");
return -EINVAL;
}
return 0;
}
/* nbd_parse_error_payload
* on success @errp contains message describing nbd error reply
*/
@@ -523,7 +481,6 @@ static coroutine_fn int nbd_co_receive_one_chunk(
typedef struct NBDReplyChunkIter {
int ret;
bool fatal;
Error *err;
bool done, only_structured;
} NBDReplyChunkIter;
@@ -533,12 +490,11 @@ static void nbd_iter_error(NBDReplyChunkIter *iter, bool fatal,
{
assert(ret < 0);
if ((fatal && !iter->fatal) || iter->ret == 0) {
if (fatal || iter->ret == 0) {
if (iter->ret != 0) {
error_free(iter->err);
iter->err = NULL;
}
iter->fatal = fatal;
iter->ret = ret;
error_propagate(&iter->err, *local_err);
} else {
@@ -684,68 +640,6 @@ static int nbd_co_receive_cmdread_reply(NBDClientSession *s, uint64_t handle,
return iter.ret;
}
static int nbd_co_receive_blockstatus_reply(NBDClientSession *s,
uint64_t handle, uint64_t length,
NBDExtent *extent, Error **errp)
{
NBDReplyChunkIter iter;
NBDReply reply;
void *payload = NULL;
Error *local_err = NULL;
bool received = false;
assert(!extent->length);
NBD_FOREACH_REPLY_CHUNK(s, iter, handle, s->info.structured_reply,
NULL, &reply, &payload)
{
int ret;
NBDStructuredReplyChunk *chunk = &reply.structured;
assert(nbd_reply_is_structured(&reply));
switch (chunk->type) {
case NBD_REPLY_TYPE_BLOCK_STATUS:
if (received) {
s->quit = true;
error_setg(&local_err, "Several BLOCK_STATUS chunks in reply");
nbd_iter_error(&iter, true, -EINVAL, &local_err);
}
received = true;
ret = nbd_parse_blockstatus_payload(s, &reply.structured,
payload, length, extent,
&local_err);
if (ret < 0) {
s->quit = true;
nbd_iter_error(&iter, true, ret, &local_err);
}
break;
default:
if (!nbd_reply_type_is_error(chunk->type)) {
s->quit = true;
error_setg(&local_err,
"Unexpected reply type: %d (%s) "
"for CMD_BLOCK_STATUS",
chunk->type, nbd_reply_type_lookup(chunk->type));
nbd_iter_error(&iter, true, -EINVAL, &local_err);
}
}
g_free(payload);
payload = NULL;
}
if (!extent->length && !iter.err) {
error_setg(&iter.err,
"Server did not reply with any status extents");
if (!iter.ret) {
iter.ret = -EIO;
}
}
error_propagate(errp, iter.err);
return iter.ret;
}
static int nbd_co_request(BlockDriverState *bs, NBDRequest *request,
QEMUIOVector *write_qiov)
{
@@ -888,51 +782,6 @@ int nbd_client_co_pdiscard(BlockDriverState *bs, int64_t offset, int bytes)
return nbd_co_request(bs, &request, NULL);
}
int coroutine_fn nbd_client_co_block_status(BlockDriverState *bs,
bool want_zero,
int64_t offset, int64_t bytes,
int64_t *pnum, int64_t *map,
BlockDriverState **file)
{
int64_t ret;
NBDExtent extent = { 0 };
NBDClientSession *client = nbd_get_client_session(bs);
Error *local_err = NULL;
NBDRequest request = {
.type = NBD_CMD_BLOCK_STATUS,
.from = offset,
.len = MIN(MIN_NON_ZERO(QEMU_ALIGN_DOWN(INT_MAX,
bs->bl.request_alignment),
client->info.max_block), bytes),
.flags = NBD_CMD_FLAG_REQ_ONE,
};
if (!client->info.base_allocation) {
*pnum = bytes;
return BDRV_BLOCK_DATA;
}
ret = nbd_co_send_request(bs, &request, NULL);
if (ret < 0) {
return ret;
}
ret = nbd_co_receive_blockstatus_reply(client, request.handle, bytes,
&extent, &local_err);
if (local_err) {
error_report_err(local_err);
}
if (ret < 0) {
return ret;
}
assert(extent.length);
*pnum = extent.length;
return (extent.flags & NBD_STATE_HOLE ? 0 : BDRV_BLOCK_DATA) |
(extent.flags & NBD_STATE_ZERO ? BDRV_BLOCK_ZERO : 0);
}
void nbd_client_detach_aio_context(BlockDriverState *bs)
{
NBDClientSession *client = nbd_get_client_session(bs);
@@ -977,7 +826,6 @@ int nbd_client_init(BlockDriverState *bs,
client->info.request_sizes = true;
client->info.structured_reply = true;
client->info.base_allocation = true;
ret = nbd_receive_negotiate(QIO_CHANNEL(sioc), export,
tlscreds, hostname,
&client->ioc, &client->info, errp);

View File

@@ -61,10 +61,4 @@ void nbd_client_detach_aio_context(BlockDriverState *bs);
void nbd_client_attach_aio_context(BlockDriverState *bs,
AioContext *new_context);
int coroutine_fn nbd_client_co_block_status(BlockDriverState *bs,
bool want_zero,
int64_t offset, int64_t bytes,
int64_t *pnum, int64_t *map,
BlockDriverState **file);
#endif /* NBD_CLIENT_H */

View File

@@ -585,7 +585,6 @@ static BlockDriver bdrv_nbd = {
.bdrv_detach_aio_context = nbd_detach_aio_context,
.bdrv_attach_aio_context = nbd_attach_aio_context,
.bdrv_refresh_filename = nbd_refresh_filename,
.bdrv_co_block_status = nbd_client_co_block_status,
};
static BlockDriver bdrv_nbd_tcp = {
@@ -605,7 +604,6 @@ static BlockDriver bdrv_nbd_tcp = {
.bdrv_detach_aio_context = nbd_detach_aio_context,
.bdrv_attach_aio_context = nbd_attach_aio_context,
.bdrv_refresh_filename = nbd_refresh_filename,
.bdrv_co_block_status = nbd_client_co_block_status,
};
static BlockDriver bdrv_nbd_unix = {
@@ -625,7 +623,6 @@ static BlockDriver bdrv_nbd_unix = {
.bdrv_detach_aio_context = nbd_detach_aio_context,
.bdrv_attach_aio_context = nbd_attach_aio_context,
.bdrv_refresh_filename = nbd_refresh_filename,
.bdrv_co_block_status = nbd_client_co_block_status,
};
static void bdrv_nbd_init(void)

View File

@@ -34,9 +34,6 @@
#include "sysemu/block-backend.h"
#include "qemu/module.h"
#include "qemu/option.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qobject-input-visitor.h"
#include "qapi/qapi-visit-block-core.h"
#include "qemu/bswap.h"
#include "qemu/bitmap.h"
#include "migration/blocker.h"
@@ -82,25 +79,6 @@ static QemuOptsList parallels_runtime_opts = {
},
};
static QemuOptsList parallels_create_opts = {
.name = "parallels-create-opts",
.head = QTAILQ_HEAD_INITIALIZER(parallels_create_opts.head),
.desc = {
{
.name = BLOCK_OPT_SIZE,
.type = QEMU_OPT_SIZE,
.help = "Virtual disk size",
},
{
.name = BLOCK_OPT_CLUSTER_SIZE,
.type = QEMU_OPT_SIZE,
.help = "Parallels image cluster size",
.def_value_str = stringify(DEFAULT_CLUSTER_SIZE),
},
{ /* end of list */ }
}
};
static int64_t bat2sect(BDRVParallelsState *s, uint32_t idx)
{
@@ -502,62 +480,46 @@ out:
}
static int coroutine_fn parallels_co_create(BlockdevCreateOptions* opts,
Error **errp)
static int coroutine_fn parallels_co_create_opts(const char *filename,
QemuOpts *opts,
Error **errp)
{
BlockdevCreateOptionsParallels *parallels_opts;
BlockDriverState *bs;
BlockBackend *blk;
int64_t total_size, cl_size;
uint8_t tmp[BDRV_SECTOR_SIZE];
Error *local_err = NULL;
BlockBackend *file;
uint32_t bat_entries, bat_sectors;
ParallelsHeader header;
uint8_t tmp[BDRV_SECTOR_SIZE];
int ret;
assert(opts->driver == BLOCKDEV_DRIVER_PARALLELS);
parallels_opts = &opts->u.parallels;
/* Sanity checks */
total_size = parallels_opts->size;
if (parallels_opts->has_cluster_size) {
cl_size = parallels_opts->cluster_size;
} else {
cl_size = DEFAULT_CLUSTER_SIZE;
}
total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
BDRV_SECTOR_SIZE);
cl_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_CLUSTER_SIZE,
DEFAULT_CLUSTER_SIZE), BDRV_SECTOR_SIZE);
if (total_size >= MAX_PARALLELS_IMAGE_FACTOR * cl_size) {
error_setg(errp, "Image size is too large for this cluster size");
error_propagate(errp, local_err);
return -E2BIG;
}
if (!QEMU_IS_ALIGNED(total_size, BDRV_SECTOR_SIZE)) {
error_setg(errp, "Image size must be a multiple of 512 bytes");
return -EINVAL;
ret = bdrv_create_file(filename, opts, &local_err);
if (ret < 0) {
error_propagate(errp, local_err);
return ret;
}
if (!QEMU_IS_ALIGNED(cl_size, BDRV_SECTOR_SIZE)) {
error_setg(errp, "Cluster size must be a multiple of 512 bytes");
return -EINVAL;
}
/* Create BlockBackend to write to the image */
bs = bdrv_open_blockdev_ref(parallels_opts->file, errp);
if (bs == NULL) {
file = blk_new_open(filename, NULL, NULL,
BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL,
&local_err);
if (file == NULL) {
error_propagate(errp, local_err);
return -EIO;
}
blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
ret = blk_insert_bs(blk, bs, errp);
if (ret < 0) {
goto out;
}
blk_set_allow_write_beyond_eof(blk, true);
blk_set_allow_write_beyond_eof(file, true);
/* Create image format */
ret = blk_truncate(blk, 0, PREALLOC_MODE_OFF, errp);
ret = blk_truncate(file, 0, PREALLOC_MODE_OFF, errp);
if (ret < 0) {
goto out;
goto exit;
}
bat_entries = DIV_ROUND_UP(total_size, cl_size);
@@ -580,107 +542,24 @@ static int coroutine_fn parallels_co_create(BlockdevCreateOptions* opts,
memset(tmp, 0, sizeof(tmp));
memcpy(tmp, &header, sizeof(header));
ret = blk_pwrite(blk, 0, tmp, BDRV_SECTOR_SIZE, 0);
ret = blk_pwrite(file, 0, tmp, BDRV_SECTOR_SIZE, 0);
if (ret < 0) {
goto exit;
}
ret = blk_pwrite_zeroes(blk, BDRV_SECTOR_SIZE,
ret = blk_pwrite_zeroes(file, BDRV_SECTOR_SIZE,
(bat_sectors - 1) << BDRV_SECTOR_BITS, 0);
if (ret < 0) {
goto exit;
}
ret = 0;
out:
blk_unref(blk);
bdrv_unref(bs);
done:
blk_unref(file);
return ret;
exit:
error_setg_errno(errp, -ret, "Failed to create Parallels image");
goto out;
}
static int coroutine_fn parallels_co_create_opts(const char *filename,
QemuOpts *opts,
Error **errp)
{
BlockdevCreateOptions *create_options = NULL;
Error *local_err = NULL;
BlockDriverState *bs = NULL;
QDict *qdict = NULL;
QObject *qobj;
Visitor *v;
int ret;
static const QDictRenames opt_renames[] = {
{ BLOCK_OPT_CLUSTER_SIZE, "cluster-size" },
{ NULL, NULL },
};
/* Parse options and convert legacy syntax */
qdict = qemu_opts_to_qdict_filtered(opts, NULL, &parallels_create_opts,
true);
if (!qdict_rename_keys(qdict, opt_renames, errp)) {
ret = -EINVAL;
goto done;
}
/* Create and open the file (protocol layer) */
ret = bdrv_create_file(filename, opts, &local_err);
if (ret < 0) {
error_propagate(errp, local_err);
goto done;
}
bs = bdrv_open(filename, NULL, NULL,
BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp);
if (bs == NULL) {
ret = -EIO;
goto done;
}
/* Now get the QAPI type BlockdevCreateOptions */
qdict_put_str(qdict, "driver", "parallels");
qdict_put_str(qdict, "file", bs->node_name);
qobj = qdict_crumple(qdict, errp);
QDECREF(qdict);
qdict = qobject_to(QDict, qobj);
if (qdict == NULL) {
ret = -EINVAL;
goto done;
}
v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
visit_free(v);
if (local_err) {
error_propagate(errp, local_err);
ret = -EINVAL;
goto done;
}
/* Silently round up sizes */
create_options->u.parallels.size =
ROUND_UP(create_options->u.parallels.size, BDRV_SECTOR_SIZE);
create_options->u.parallels.cluster_size =
ROUND_UP(create_options->u.parallels.cluster_size, BDRV_SECTOR_SIZE);
/* Create the Parallels image (format layer) */
ret = parallels_co_create(create_options, errp);
if (ret < 0) {
goto done;
}
ret = 0;
done:
QDECREF(qdict);
bdrv_unref(bs);
qapi_free_BlockdevCreateOptions(create_options);
return ret;
goto done;
}
@@ -892,6 +771,25 @@ static void parallels_close(BlockDriverState *bs)
error_free(s->migration_blocker);
}
static QemuOptsList parallels_create_opts = {
.name = "parallels-create-opts",
.head = QTAILQ_HEAD_INITIALIZER(parallels_create_opts.head),
.desc = {
{
.name = BLOCK_OPT_SIZE,
.type = QEMU_OPT_SIZE,
.help = "Virtual disk size",
},
{
.name = BLOCK_OPT_CLUSTER_SIZE,
.type = QEMU_OPT_SIZE,
.help = "Parallels image cluster size",
.def_value_str = stringify(DEFAULT_CLUSTER_SIZE),
},
{ /* end of list */ }
}
};
static BlockDriver bdrv_parallels = {
.format_name = "parallels",
.instance_size = sizeof(BDRVParallelsState),
@@ -905,7 +803,6 @@ static BlockDriver bdrv_parallels = {
.bdrv_co_readv = parallels_co_readv,
.bdrv_co_writev = parallels_co_writev,
.supports_backing = true,
.bdrv_co_create = parallels_co_create,
.bdrv_co_create_opts = parallels_co_create_opts,
.bdrv_co_check = parallels_co_check,
.create_opts = &parallels_create_opts,

View File

@@ -394,37 +394,6 @@ static void bdrv_query_info(BlockBackend *blk, BlockInfo **p_info,
qapi_free_BlockInfo(info);
}
static uint64List *uint64_list(uint64_t *list, int size)
{
int i;
uint64List *out_list = NULL;
uint64List **pout_list = &out_list;
for (i = 0; i < size; i++) {
uint64List *entry = g_new(uint64List, 1);
entry->value = list[i];
*pout_list = entry;
pout_list = &entry->next;
}
*pout_list = NULL;
return out_list;
}
static void bdrv_latency_histogram_stats(BlockLatencyHistogram *hist,
bool *not_null,
BlockLatencyHistogramInfo **info)
{
*not_null = hist->bins != NULL;
if (*not_null) {
*info = g_new0(BlockLatencyHistogramInfo, 1);
(*info)->boundaries = uint64_list(hist->boundaries, hist->nbins - 1);
(*info)->bins = uint64_list(hist->bins, hist->nbins);
}
}
static void bdrv_query_blk_stats(BlockDeviceStats *ds, BlockBackend *blk)
{
BlockAcctStats *stats = blk_get_stats(blk);
@@ -490,16 +459,6 @@ static void bdrv_query_blk_stats(BlockDeviceStats *ds, BlockBackend *blk)
dev_stats->avg_wr_queue_depth =
block_acct_queue_depth(ts, BLOCK_ACCT_WRITE);
}
bdrv_latency_histogram_stats(&stats->latency_histogram[BLOCK_ACCT_READ],
&ds->has_x_rd_latency_histogram,
&ds->x_rd_latency_histogram);
bdrv_latency_histogram_stats(&stats->latency_histogram[BLOCK_ACCT_WRITE],
&ds->has_x_wr_latency_histogram,
&ds->x_wr_latency_histogram);
bdrv_latency_histogram_stats(&stats->latency_histogram[BLOCK_ACCT_FLUSH],
&ds->has_x_flush_latency_histogram,
&ds->x_flush_latency_histogram);
}
static BlockStats *bdrv_query_bds_stats(BlockDriverState *bs,
@@ -688,29 +647,29 @@ static void dump_qobject(fprintf_function func_fprintf, void *f,
{
switch (qobject_type(obj)) {
case QTYPE_QNUM: {
QNum *value = qobject_to(QNum, obj);
QNum *value = qobject_to_qnum(obj);
char *tmp = qnum_to_string(value);
func_fprintf(f, "%s", tmp);
g_free(tmp);
break;
}
case QTYPE_QSTRING: {
QString *value = qobject_to(QString, obj);
QString *value = qobject_to_qstring(obj);
func_fprintf(f, "%s", qstring_get_str(value));
break;
}
case QTYPE_QDICT: {
QDict *value = qobject_to(QDict, obj);
QDict *value = qobject_to_qdict(obj);
dump_qdict(func_fprintf, f, comp_indent, value);
break;
}
case QTYPE_QLIST: {
QList *value = qobject_to(QList, obj);
QList *value = qobject_to_qlist(obj);
dump_qlist(func_fprintf, f, comp_indent, value);
break;
}
case QTYPE_QBOOL: {
QBool *value = qobject_to(QBool, obj);
QBool *value = qobject_to_qbool(obj);
func_fprintf(f, "%s", qbool_get_bool(value) ? "true" : "false");
break;
}
@@ -771,7 +730,7 @@ void bdrv_image_info_specific_dump(fprintf_function func_fprintf, void *f,
visit_type_ImageInfoSpecific(v, NULL, &info_spec, &error_abort);
visit_complete(v, &obj);
data = qdict_get(qobject_to(QDict, obj), "data");
data = qdict_get(qobject_to_qdict(obj), "data");
dump_qobject(func_fprintf, f, 1, data);
qobject_decref(obj);
visit_free(v);

View File

@@ -33,8 +33,6 @@
#include <zlib.h>
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qstring.h"
#include "qapi/qobject-input-visitor.h"
#include "qapi/qapi-visit-block-core.h"
#include "crypto/block.h"
#include "migration/blocker.h"
#include "block/crypto.h"
@@ -88,8 +86,6 @@ typedef struct BDRVQcowState {
Error *migration_blocker;
} BDRVQcowState;
static QemuOptsList qcow_create_opts;
static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset);
static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
@@ -814,50 +810,62 @@ static void qcow_close(BlockDriverState *bs)
error_free(s->migration_blocker);
}
static int coroutine_fn qcow_co_create(BlockdevCreateOptions *opts,
Error **errp)
static int coroutine_fn qcow_co_create_opts(const char *filename, QemuOpts *opts,
Error **errp)
{
BlockdevCreateOptionsQcow *qcow_opts;
int header_size, backing_filename_len, l1_size, shift, i;
QCowHeader header;
uint8_t *tmp;
int64_t total_size = 0;
char *backing_file = NULL;
Error *local_err = NULL;
int ret;
BlockDriverState *bs;
BlockBackend *qcow_blk;
char *encryptfmt = NULL;
QDict *options;
QDict *encryptopts = NULL;
QCryptoBlockCreateOptions *crypto_opts = NULL;
QCryptoBlock *crypto = NULL;
assert(opts->driver == BLOCKDEV_DRIVER_QCOW);
qcow_opts = &opts->u.qcow;
/* Sanity checks */
total_size = qcow_opts->size;
/* Read out options */
total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
BDRV_SECTOR_SIZE);
if (total_size == 0) {
error_setg(errp, "Image size is too small, cannot be zero length");
return -EINVAL;
ret = -EINVAL;
goto cleanup;
}
if (qcow_opts->has_encrypt &&
qcow_opts->encrypt->format != Q_CRYPTO_BLOCK_FORMAT_QCOW)
{
error_setg(errp, "Unsupported encryption format");
return -EINVAL;
backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
encryptfmt = qemu_opt_get_del(opts, BLOCK_OPT_ENCRYPT_FORMAT);
if (encryptfmt) {
if (qemu_opt_get(opts, BLOCK_OPT_ENCRYPT)) {
error_setg(errp, "Options " BLOCK_OPT_ENCRYPT " and "
BLOCK_OPT_ENCRYPT_FORMAT " are mutually exclusive");
ret = -EINVAL;
goto cleanup;
}
} else if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ENCRYPT, false)) {
encryptfmt = g_strdup("aes");
}
/* Create BlockBackend to write to the image */
bs = bdrv_open_blockdev_ref(qcow_opts->file, errp);
if (bs == NULL) {
return -EIO;
}
qcow_blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
ret = blk_insert_bs(qcow_blk, bs, errp);
ret = bdrv_create_file(filename, opts, &local_err);
if (ret < 0) {
goto exit;
error_propagate(errp, local_err);
goto cleanup;
}
qcow_blk = blk_new_open(filename, NULL, NULL,
BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL,
&local_err);
if (qcow_blk == NULL) {
error_propagate(errp, local_err);
ret = -EIO;
goto cleanup;
}
blk_set_allow_write_beyond_eof(qcow_blk, true);
/* Create image format */
ret = blk_truncate(qcow_blk, 0, PREALLOC_MODE_OFF, errp);
if (ret < 0) {
goto exit;
@@ -869,15 +877,16 @@ static int coroutine_fn qcow_co_create(BlockdevCreateOptions *opts,
header.size = cpu_to_be64(total_size);
header_size = sizeof(header);
backing_filename_len = 0;
if (qcow_opts->has_backing_file) {
if (strcmp(qcow_opts->backing_file, "fat:")) {
if (backing_file) {
if (strcmp(backing_file, "fat:")) {
header.backing_file_offset = cpu_to_be64(header_size);
backing_filename_len = strlen(qcow_opts->backing_file);
backing_filename_len = strlen(backing_file);
header.backing_file_size = cpu_to_be32(backing_filename_len);
header_size += backing_filename_len;
} else {
/* special backing file for vvfat */
qcow_opts->has_backing_file = false;
g_free(backing_file);
backing_file = NULL;
}
header.cluster_bits = 9; /* 512 byte cluster to avoid copying
unmodified sectors */
@@ -892,10 +901,26 @@ static int coroutine_fn qcow_co_create(BlockdevCreateOptions *opts,
header.l1_table_offset = cpu_to_be64(header_size);
if (qcow_opts->has_encrypt) {
options = qemu_opts_to_qdict(opts, NULL);
qdict_extract_subqdict(options, &encryptopts, "encrypt.");
QDECREF(options);
if (encryptfmt) {
if (!g_str_equal(encryptfmt, "aes")) {
error_setg(errp, "Unknown encryption format '%s', expected 'aes'",
encryptfmt);
ret = -EINVAL;
goto exit;
}
header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES);
crypto = qcrypto_block_create(qcow_opts->encrypt, "encrypt.",
crypto_opts = block_crypto_create_opts_init(
Q_CRYPTO_BLOCK_FORMAT_QCOW, encryptopts, errp);
if (!crypto_opts) {
ret = -EINVAL;
goto exit;
}
crypto = qcrypto_block_create(crypto_opts, "encrypt.",
NULL, NULL, NULL, errp);
if (!crypto) {
ret = -EINVAL;
@@ -911,9 +936,9 @@ static int coroutine_fn qcow_co_create(BlockdevCreateOptions *opts,
goto exit;
}
if (qcow_opts->has_backing_file) {
if (backing_file) {
ret = blk_pwrite(qcow_blk, sizeof(header),
qcow_opts->backing_file, backing_filename_len, 0);
backing_file, backing_filename_len, 0);
if (ret != backing_filename_len) {
goto exit;
}
@@ -934,100 +959,12 @@ static int coroutine_fn qcow_co_create(BlockdevCreateOptions *opts,
ret = 0;
exit:
blk_unref(qcow_blk);
cleanup:
QDECREF(encryptopts);
g_free(encryptfmt);
qcrypto_block_free(crypto);
return ret;
}
static int coroutine_fn qcow_co_create_opts(const char *filename,
QemuOpts *opts, Error **errp)
{
BlockdevCreateOptions *create_options = NULL;
BlockDriverState *bs = NULL;
QDict *qdict = NULL;
QObject *qobj;
Visitor *v;
const char *val;
Error *local_err = NULL;
int ret;
static const QDictRenames opt_renames[] = {
{ BLOCK_OPT_BACKING_FILE, "backing-file" },
{ BLOCK_OPT_ENCRYPT, BLOCK_OPT_ENCRYPT_FORMAT },
{ NULL, NULL },
};
/* Parse options and convert legacy syntax */
qdict = qemu_opts_to_qdict_filtered(opts, NULL, &qcow_create_opts, true);
val = qdict_get_try_str(qdict, BLOCK_OPT_ENCRYPT);
if (val && !strcmp(val, "on")) {
qdict_put_str(qdict, BLOCK_OPT_ENCRYPT, "qcow");
} else if (val && !strcmp(val, "off")) {
qdict_del(qdict, BLOCK_OPT_ENCRYPT);
}
val = qdict_get_try_str(qdict, BLOCK_OPT_ENCRYPT_FORMAT);
if (val && !strcmp(val, "aes")) {
qdict_put_str(qdict, BLOCK_OPT_ENCRYPT_FORMAT, "qcow");
}
if (!qdict_rename_keys(qdict, opt_renames, errp)) {
ret = -EINVAL;
goto fail;
}
/* Create and open the file (protocol layer) */
ret = bdrv_create_file(filename, opts, &local_err);
if (ret < 0) {
error_propagate(errp, local_err);
goto fail;
}
bs = bdrv_open(filename, NULL, NULL,
BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp);
if (bs == NULL) {
ret = -EIO;
goto fail;
}
/* Now get the QAPI type BlockdevCreateOptions */
qdict_put_str(qdict, "driver", "qcow");
qdict_put_str(qdict, "file", bs->node_name);
qobj = qdict_crumple(qdict, errp);
QDECREF(qdict);
qdict = qobject_to(QDict, qobj);
if (qdict == NULL) {
ret = -EINVAL;
goto fail;
}
v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
visit_free(v);
if (local_err) {
error_propagate(errp, local_err);
ret = -EINVAL;
goto fail;
}
/* Silently round up size */
assert(create_options->driver == BLOCKDEV_DRIVER_QCOW);
create_options->u.qcow.size =
ROUND_UP(create_options->u.qcow.size, BDRV_SECTOR_SIZE);
/* Create the qcow image (format layer) */
ret = qcow_co_create(create_options, errp);
if (ret < 0) {
goto fail;
}
ret = 0;
fail:
QDECREF(qdict);
bdrv_unref(bs);
qapi_free_BlockdevCreateOptions(create_options);
qapi_free_QCryptoBlockCreateOptions(crypto_opts);
g_free(backing_file);
return ret;
}
@@ -1191,7 +1128,6 @@ static BlockDriver bdrv_qcow = {
.bdrv_close = qcow_close,
.bdrv_child_perm = bdrv_format_default_perms,
.bdrv_reopen_prepare = qcow_reopen_prepare,
.bdrv_co_create = qcow_co_create,
.bdrv_co_create_opts = qcow_co_create_opts,
.bdrv_has_zero_init = bdrv_has_zero_init_1,
.supports_backing = true,

View File

@@ -3125,7 +3125,7 @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
/* Now get the QAPI type BlockdevCreateOptions */
qobj = qdict_crumple(qdict, errp);
QDECREF(qdict);
qdict = qobject_to(QDict, qobj);
qdict = qobject_to_qdict(qobj);
if (qdict == NULL) {
ret = -EINVAL;
goto finish;

View File

@@ -20,11 +20,6 @@
#include "trace.h"
#include "qed.h"
#include "sysemu/block-backend.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qobject-input-visitor.h"
#include "qapi/qapi-visit-block-core.h"
static QemuOptsList qed_create_opts;
static int bdrv_qed_probe(const uint8_t *buf, int buf_size,
const char *filename)
@@ -599,78 +594,43 @@ static void bdrv_qed_close(BlockDriverState *bs)
qemu_vfree(s->l1_table);
}
static int coroutine_fn bdrv_qed_co_create(BlockdevCreateOptions *opts,
Error **errp)
static int qed_create(const char *filename, uint32_t cluster_size,
uint64_t image_size, uint32_t table_size,
const char *backing_file, const char *backing_fmt,
QemuOpts *opts, Error **errp)
{
BlockdevCreateOptionsQed *qed_opts;
BlockBackend *blk = NULL;
BlockDriverState *bs = NULL;
QEDHeader header;
QEDHeader le_header;
uint8_t *l1_table = NULL;
size_t l1_size;
int ret = 0;
assert(opts->driver == BLOCKDEV_DRIVER_QED);
qed_opts = &opts->u.qed;
/* Validate options and set default values */
if (!qed_opts->has_cluster_size) {
qed_opts->cluster_size = QED_DEFAULT_CLUSTER_SIZE;
}
if (!qed_opts->has_table_size) {
qed_opts->table_size = QED_DEFAULT_TABLE_SIZE;
}
if (!qed_is_cluster_size_valid(qed_opts->cluster_size)) {
error_setg(errp, "QED cluster size must be within range [%u, %u] "
"and power of 2",
QED_MIN_CLUSTER_SIZE, QED_MAX_CLUSTER_SIZE);
return -EINVAL;
}
if (!qed_is_table_size_valid(qed_opts->table_size)) {
error_setg(errp, "QED table size must be within range [%u, %u] "
"and power of 2",
QED_MIN_TABLE_SIZE, QED_MAX_TABLE_SIZE);
return -EINVAL;
}
if (!qed_is_image_size_valid(qed_opts->size, qed_opts->cluster_size,
qed_opts->table_size))
{
error_setg(errp, "QED image size must be a non-zero multiple of "
"cluster size and less than %" PRIu64 " bytes",
qed_max_image_size(qed_opts->cluster_size,
qed_opts->table_size));
return -EINVAL;
}
/* Create BlockBackend to write to the image */
bs = bdrv_open_blockdev_ref(qed_opts->file, errp);
if (bs == NULL) {
return -EIO;
}
blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
ret = blk_insert_bs(blk, bs, errp);
if (ret < 0) {
goto out;
}
blk_set_allow_write_beyond_eof(blk, true);
/* Prepare image format */
header = (QEDHeader) {
QEDHeader header = {
.magic = QED_MAGIC,
.cluster_size = qed_opts->cluster_size,
.table_size = qed_opts->table_size,
.cluster_size = cluster_size,
.table_size = table_size,
.header_size = 1,
.features = 0,
.compat_features = 0,
.l1_table_offset = qed_opts->cluster_size,
.image_size = qed_opts->size,
.l1_table_offset = cluster_size,
.image_size = image_size,
};
QEDHeader le_header;
uint8_t *l1_table = NULL;
size_t l1_size = header.cluster_size * header.table_size;
Error *local_err = NULL;
int ret = 0;
BlockBackend *blk;
l1_size = header.cluster_size * header.table_size;
ret = bdrv_create_file(filename, opts, &local_err);
if (ret < 0) {
error_propagate(errp, local_err);
return ret;
}
blk = blk_new_open(filename, NULL, NULL,
BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL,
&local_err);
if (blk == NULL) {
error_propagate(errp, local_err);
return -EIO;
}
blk_set_allow_write_beyond_eof(blk, true);
/* File must start empty and grow, check truncate is supported */
ret = blk_truncate(blk, 0, PREALLOC_MODE_OFF, errp);
@@ -678,16 +638,13 @@ static int coroutine_fn bdrv_qed_co_create(BlockdevCreateOptions *opts,
goto out;
}
if (qed_opts->has_backing_file) {
if (backing_file) {
header.features |= QED_F_BACKING_FILE;
header.backing_filename_offset = sizeof(le_header);
header.backing_filename_size = strlen(qed_opts->backing_file);
header.backing_filename_size = strlen(backing_file);
if (qed_opts->has_backing_fmt) {
const char *backing_fmt = BlockdevDriver_str(qed_opts->backing_fmt);
if (qed_fmt_is_raw(backing_fmt)) {
header.features |= QED_F_BACKING_FORMAT_NO_PROBE;
}
if (qed_fmt_is_raw(backing_fmt)) {
header.features |= QED_F_BACKING_FORMAT_NO_PROBE;
}
}
@@ -696,7 +653,7 @@ static int coroutine_fn bdrv_qed_co_create(BlockdevCreateOptions *opts,
if (ret < 0) {
goto out;
}
ret = blk_pwrite(blk, sizeof(le_header), qed_opts->backing_file,
ret = blk_pwrite(blk, sizeof(le_header), backing_file,
header.backing_filename_size, 0);
if (ret < 0) {
goto out;
@@ -712,7 +669,6 @@ static int coroutine_fn bdrv_qed_co_create(BlockdevCreateOptions *opts,
out:
g_free(l1_table);
blk_unref(blk);
bdrv_unref(bs);
return ret;
}
@@ -720,78 +676,51 @@ static int coroutine_fn bdrv_qed_co_create_opts(const char *filename,
QemuOpts *opts,
Error **errp)
{
BlockdevCreateOptions *create_options = NULL;
QDict *qdict = NULL;
QObject *qobj;
Visitor *v;
BlockDriverState *bs = NULL;
Error *local_err = NULL;
uint64_t image_size = 0;
uint32_t cluster_size = QED_DEFAULT_CLUSTER_SIZE;
uint32_t table_size = QED_DEFAULT_TABLE_SIZE;
char *backing_file = NULL;
char *backing_fmt = NULL;
int ret;
static const QDictRenames opt_renames[] = {
{ BLOCK_OPT_BACKING_FILE, "backing-file" },
{ BLOCK_OPT_BACKING_FMT, "backing-fmt" },
{ BLOCK_OPT_CLUSTER_SIZE, "cluster-size" },
{ BLOCK_OPT_TABLE_SIZE, "table-size" },
{ NULL, NULL },
};
image_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
BDRV_SECTOR_SIZE);
backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
backing_fmt = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FMT);
cluster_size = qemu_opt_get_size_del(opts,
BLOCK_OPT_CLUSTER_SIZE,
QED_DEFAULT_CLUSTER_SIZE);
table_size = qemu_opt_get_size_del(opts, BLOCK_OPT_TABLE_SIZE,
QED_DEFAULT_TABLE_SIZE);
/* Parse options and convert legacy syntax */
qdict = qemu_opts_to_qdict_filtered(opts, NULL, &qed_create_opts, true);
if (!qdict_rename_keys(qdict, opt_renames, errp)) {
if (!qed_is_cluster_size_valid(cluster_size)) {
error_setg(errp, "QED cluster size must be within range [%u, %u] "
"and power of 2",
QED_MIN_CLUSTER_SIZE, QED_MAX_CLUSTER_SIZE);
ret = -EINVAL;
goto fail;
goto finish;
}
/* Create and open the file (protocol layer) */
ret = bdrv_create_file(filename, opts, &local_err);
if (ret < 0) {
error_propagate(errp, local_err);
goto fail;
}
bs = bdrv_open(filename, NULL, NULL,
BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp);
if (bs == NULL) {
ret = -EIO;
goto fail;
}
/* Now get the QAPI type BlockdevCreateOptions */
qdict_put_str(qdict, "driver", "qed");
qdict_put_str(qdict, "file", bs->node_name);
qobj = qdict_crumple(qdict, errp);
QDECREF(qdict);
qdict = qobject_to(QDict, qobj);
if (qdict == NULL) {
if (!qed_is_table_size_valid(table_size)) {
error_setg(errp, "QED table size must be within range [%u, %u] "
"and power of 2",
QED_MIN_TABLE_SIZE, QED_MAX_TABLE_SIZE);
ret = -EINVAL;
goto fail;
goto finish;
}
v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
visit_free(v);
if (local_err) {
error_propagate(errp, local_err);
if (!qed_is_image_size_valid(image_size, cluster_size, table_size)) {
error_setg(errp, "QED image size must be a non-zero multiple of "
"cluster size and less than %" PRIu64 " bytes",
qed_max_image_size(cluster_size, table_size));
ret = -EINVAL;
goto fail;
goto finish;
}
/* Silently round up size */
assert(create_options->driver == BLOCKDEV_DRIVER_QED);
create_options->u.qed.size =
ROUND_UP(create_options->u.qed.size, BDRV_SECTOR_SIZE);
ret = qed_create(filename, cluster_size, image_size, table_size,
backing_file, backing_fmt, opts, errp);
/* Create the qed image (format layer) */
ret = bdrv_qed_co_create(create_options, errp);
fail:
QDECREF(qdict);
bdrv_unref(bs);
qapi_free_BlockdevCreateOptions(create_options);
finish:
g_free(backing_file);
g_free(backing_fmt);
return ret;
}
@@ -1673,7 +1602,6 @@ static BlockDriver bdrv_qed = {
.bdrv_close = bdrv_qed_close,
.bdrv_reopen_prepare = bdrv_qed_reopen_prepare,
.bdrv_child_perm = bdrv_format_default_perms,
.bdrv_co_create = bdrv_qed_co_create,
.bdrv_co_create_opts = bdrv_qed_co_create_opts,
.bdrv_has_zero_init = bdrv_has_zero_init_1,
.bdrv_co_block_status = bdrv_qed_co_block_status,

View File

@@ -1098,11 +1098,10 @@ static void quorum_refresh_filename(BlockDriverState *bs, QDict *options)
static BlockDriver bdrv_quorum = {
.format_name = "quorum",
.protocol_name = "quorum",
.instance_size = sizeof(BDRVQuorumState),
.bdrv_file_open = quorum_open,
.bdrv_open = quorum_open,
.bdrv_close = quorum_close,
.bdrv_refresh_filename = quorum_refresh_filename,

View File

@@ -263,14 +263,14 @@ static int qemu_rbd_set_keypairs(rados_t cluster, const char *keypairs_json,
if (!keypairs_json) {
return ret;
}
keypairs = qobject_to(QList,
qobject_from_json(keypairs_json, &error_abort));
keypairs = qobject_to_qlist(qobject_from_json(keypairs_json,
&error_abort));
remaining = qlist_size(keypairs) / 2;
assert(remaining);
while (remaining--) {
name = qobject_to(QString, qlist_pop(keypairs));
value = qobject_to(QString, qlist_pop(keypairs));
name = qobject_to_qstring(qlist_pop(keypairs));
value = qobject_to_qstring(qlist_pop(keypairs));
assert(name && value);
key = qstring_get_str(name);

View File

@@ -703,7 +703,6 @@ static void replication_stop(ReplicationState *rs, bool failover, Error **errp)
BlockDriver bdrv_replication = {
.format_name = "replication",
.protocol_name = "replication",
.instance_size = sizeof(BDRVReplicationState),
.bdrv_open = replication_open,

View File

@@ -1036,7 +1036,7 @@ static void sd_parse_uri(SheepdogConfig *cfg, const char *filename,
cfg->uri = uri = uri_parse(filename);
if (!uri) {
error_setg(&err, "invalid URI '%s'", filename);
error_setg(&err, "invalid URI");
goto out;
}
@@ -1887,7 +1887,7 @@ static int sd_create_prealloc(BlockdevOptionsSheepdog *location, int64_t size,
return -EINVAL;
}
qdict = qobject_to(QDict, obj);
qdict = qobject_to_qdict(obj);
qdict_flatten(qdict);
qdict_put_str(qdict, "driver", "sheepdog");

View File

@@ -244,7 +244,7 @@ void stream_start(const char *job_id, BlockDriverState *bs,
/* Prevent concurrent jobs trying to modify the graph structure here, we
* already have our own plans. Also don't allow resize as the image size is
* queried only at the job start and then cached. */
s = block_job_create(job_id, &stream_job_driver, NULL, bs,
s = block_job_create(job_id, &stream_job_driver, bs,
BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED |
BLK_PERM_GRAPH_MOD,
BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED |

View File

@@ -215,10 +215,9 @@ static void coroutine_fn throttle_co_drain_end(BlockDriverState *bs)
static BlockDriver bdrv_throttle = {
.format_name = "throttle",
.protocol_name = "throttle",
.instance_size = sizeof(ThrottleGroupMember),
.bdrv_file_open = throttle_open,
.bdrv_open = throttle_open,
.bdrv_close = throttle_close,
.bdrv_co_flush = throttle_co_flush,

View File

@@ -4,16 +4,9 @@
bdrv_open_common(void *bs, const char *filename, int flags, const char *format_name) "bs %p filename \"%s\" flags 0x%x format_name \"%s\""
bdrv_lock_medium(void *bs, bool locked) "bs %p locked %d"
# blockjob.c
block_job_completed(void *job, int ret, int jret) "job %p ret %d corrected ret %d"
block_job_state_transition(void *job, int ret, const char *legal, const char *s0, const char *s1) "job %p (ret: %d) attempting %s transition (%s-->%s)"
block_job_apply_verb(void *job, const char *state, const char *verb, const char *legal) "job %p in state %s; applying verb %s (%s)"
# block/block-backend.c
blk_co_preadv(void *blk, void *bs, int64_t offset, unsigned int bytes, int flags) "blk %p bs %p offset %"PRId64" bytes %u flags 0x%x"
blk_co_pwritev(void *blk, void *bs, int64_t offset, unsigned int bytes, int flags) "blk %p bs %p offset %"PRId64" bytes %u flags 0x%x"
blk_root_attach(void *child, void *blk, void *bs) "child %p blk %p bs %p"
blk_root_detach(void *child, void *blk, void *bs) "child %p blk %p bs %p"
# block/io.c
bdrv_co_preadv(void *bs, int64_t offset, int64_t nbytes, unsigned int flags) "bs %p offset %"PRId64" nbytes %"PRId64" flags 0x%x"
@@ -53,8 +46,6 @@ qmp_block_job_cancel(void *job) "job %p"
qmp_block_job_pause(void *job) "job %p"
qmp_block_job_resume(void *job) "job %p"
qmp_block_job_complete(void *job) "job %p"
qmp_block_job_finalize(void *job) "job %p"
qmp_block_job_dismiss(void *job) "job %p"
qmp_block_stream(void *bs, void *job) "bs %p job %p"
# block/file-win32.c

View File

@@ -51,9 +51,6 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qobject-input-visitor.h"
#include "qapi/qapi-visit-block-core.h"
#include "block/block_int.h"
#include "sysemu/block-backend.h"
#include "qemu/module.h"
@@ -143,8 +140,6 @@
#define VDI_DISK_SIZE_MAX ((uint64_t)VDI_BLOCKS_IN_IMAGE_MAX * \
(uint64_t)DEFAULT_CLUSTER_SIZE)
static QemuOptsList vdi_create_opts;
typedef struct {
char text[0x40];
uint32_t signature;
@@ -721,46 +716,36 @@ nonallocating_write:
return ret;
}
static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options,
size_t block_size, Error **errp)
static int coroutine_fn vdi_co_create_opts(const char *filename, QemuOpts *opts,
Error **errp)
{
BlockdevCreateOptionsVdi *vdi_opts;
int ret = 0;
uint64_t bytes = 0;
uint32_t blocks;
size_t block_size = DEFAULT_CLUSTER_SIZE;
uint32_t image_type = VDI_TYPE_DYNAMIC;
VdiHeader header;
size_t i;
size_t bmap_size;
int64_t offset = 0;
BlockDriverState *bs_file = NULL;
Error *local_err = NULL;
BlockBackend *blk = NULL;
uint32_t *bmap = NULL;
assert(create_options->driver == BLOCKDEV_DRIVER_VDI);
vdi_opts = &create_options->u.vdi;
logout("\n");
/* Validate options and set default values */
bytes = vdi_opts->size;
if (vdi_opts->q_static) {
image_type = VDI_TYPE_STATIC;
}
#ifndef CONFIG_VDI_STATIC_IMAGE
if (image_type == VDI_TYPE_STATIC) {
ret = -ENOTSUP;
error_setg(errp, "Statically allocated images cannot be created in "
"this build");
goto exit;
}
/* Read out options. */
bytes = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
BDRV_SECTOR_SIZE);
#if defined(CONFIG_VDI_BLOCK_SIZE)
/* TODO: Additional checks (SECTOR_SIZE * 2^n, ...). */
block_size = qemu_opt_get_size_del(opts,
BLOCK_OPT_CLUSTER_SIZE,
DEFAULT_CLUSTER_SIZE);
#endif
#ifndef CONFIG_VDI_BLOCK_SIZE
if (block_size != DEFAULT_CLUSTER_SIZE) {
ret = -ENOTSUP;
error_setg(errp,
"A non-default cluster size is not supported in this build");
goto exit;
#if defined(CONFIG_VDI_STATIC_IMAGE)
if (qemu_opt_get_bool_del(opts, BLOCK_OPT_STATIC, false)) {
image_type = VDI_TYPE_STATIC;
}
#endif
@@ -772,16 +757,18 @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options,
goto exit;
}
/* Create BlockBackend to write to the image */
bs_file = bdrv_open_blockdev_ref(vdi_opts->file, errp);
if (!bs_file) {
ret = -EIO;
ret = bdrv_create_file(filename, opts, &local_err);
if (ret < 0) {
error_propagate(errp, local_err);
goto exit;
}
blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
ret = blk_insert_bs(blk, bs_file, errp);
if (ret < 0) {
blk = blk_new_open(filename, NULL, NULL,
BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL,
&local_err);
if (blk == NULL) {
error_propagate(errp, local_err);
ret = -EIO;
goto exit;
}
@@ -818,7 +805,7 @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options,
vdi_header_to_le(&header);
ret = blk_pwrite(blk, offset, &header, sizeof(header), 0);
if (ret < 0) {
error_setg(errp, "Error writing header");
error_setg(errp, "Error writing header to %s", filename);
goto exit;
}
offset += sizeof(header);
@@ -839,7 +826,7 @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options,
}
ret = blk_pwrite(blk, offset, bmap, bmap_size, 0);
if (ret < 0) {
error_setg(errp, "Error writing bmap");
error_setg(errp, "Error writing bmap to %s", filename);
goto exit;
}
offset += bmap_size;
@@ -849,96 +836,17 @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options,
ret = blk_truncate(blk, offset + blocks * block_size,
PREALLOC_MODE_OFF, errp);
if (ret < 0) {
error_prepend(errp, "Failed to statically allocate file");
error_prepend(errp, "Failed to statically allocate %s", filename);
goto exit;
}
}
exit:
blk_unref(blk);
bdrv_unref(bs_file);
g_free(bmap);
return ret;
}
static int coroutine_fn vdi_co_create(BlockdevCreateOptions *create_options,
Error **errp)
{
return vdi_co_do_create(create_options, DEFAULT_CLUSTER_SIZE, errp);
}
static int coroutine_fn vdi_co_create_opts(const char *filename, QemuOpts *opts,
Error **errp)
{
QDict *qdict = NULL;
BlockdevCreateOptions *create_options = NULL;
BlockDriverState *bs_file = NULL;
uint64_t block_size = DEFAULT_CLUSTER_SIZE;
Visitor *v;
Error *local_err = NULL;
int ret;
/* Parse options and convert legacy syntax.
*
* Since CONFIG_VDI_BLOCK_SIZE is disabled by default,
* cluster-size is not part of the QAPI schema; therefore we have
* to parse it before creating the QAPI object. */
#if defined(CONFIG_VDI_BLOCK_SIZE)
block_size = qemu_opt_get_size_del(opts,
BLOCK_OPT_CLUSTER_SIZE,
DEFAULT_CLUSTER_SIZE);
if (block_size < BDRV_SECTOR_SIZE || block_size > UINT32_MAX ||
!is_power_of_2(block_size))
{
error_setg(errp, "Invalid cluster size");
ret = -EINVAL;
goto done;
}
#endif
qdict = qemu_opts_to_qdict_filtered(opts, NULL, &vdi_create_opts, true);
/* Create and open the file (protocol layer) */
ret = bdrv_create_file(filename, opts, errp);
if (ret < 0) {
goto done;
}
bs_file = bdrv_open(filename, NULL, NULL,
BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp);
if (!bs_file) {
ret = -EIO;
goto done;
}
qdict_put_str(qdict, "driver", "vdi");
qdict_put_str(qdict, "file", bs_file->node_name);
/* Get the QAPI object */
v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
visit_free(v);
if (local_err) {
error_propagate(errp, local_err);
ret = -EINVAL;
goto done;
}
/* Silently round up size */
assert(create_options->driver == BLOCKDEV_DRIVER_VDI);
create_options->u.vdi.size = ROUND_UP(create_options->u.vdi.size,
BDRV_SECTOR_SIZE);
/* Create the vdi image (format layer) */
ret = vdi_co_do_create(create_options, block_size, errp);
done:
QDECREF(qdict);
qapi_free_BlockdevCreateOptions(create_options);
bdrv_unref(bs_file);
return ret;
}
static void vdi_close(BlockDriverState *bs)
{
BDRVVdiState *s = bs->opaque;
@@ -987,7 +895,6 @@ static BlockDriver bdrv_vdi = {
.bdrv_close = vdi_close,
.bdrv_reopen_prepare = vdi_reopen_prepare,
.bdrv_child_perm = bdrv_format_default_perms,
.bdrv_co_create = vdi_co_create,
.bdrv_co_create_opts = vdi_co_create_opts,
.bdrv_has_zero_init = bdrv_has_zero_init_1,
.bdrv_co_block_status = vdi_co_block_status,

View File

@@ -26,9 +26,6 @@
#include "block/vhdx.h"
#include "migration/blocker.h"
#include "qemu/uuid.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qobject-input-visitor.h"
#include "qapi/qapi-visit-block-core.h"
/* Options for VHDX creation */
@@ -42,8 +39,6 @@ typedef enum VHDXImageType {
VHDX_TYPE_DIFFERENCING, /* Currently unsupported */
} VHDXImageType;
static QemuOptsList vhdx_create_opts;
/* Several metadata and region table data entries are identified by
* guids in a MS-specific GUID format. */
@@ -1797,71 +1792,59 @@ exit:
* .---- ~ ----------- ~ ------------ ~ ---------------- ~ -----------.
* 1MB
*/
static int coroutine_fn vhdx_co_create(BlockdevCreateOptions *opts,
Error **errp)
static int coroutine_fn vhdx_co_create_opts(const char *filename, QemuOpts *opts,
Error **errp)
{
BlockdevCreateOptionsVhdx *vhdx_opts;
BlockBackend *blk = NULL;
BlockDriverState *bs = NULL;
int ret = 0;
uint64_t image_size;
uint32_t log_size;
uint32_t block_size;
uint64_t image_size = (uint64_t) 2 * GiB;
uint32_t log_size = 1 * MiB;
uint32_t block_size = 0;
uint64_t signature;
uint64_t metadata_offset;
bool use_zero_blocks = false;
gunichar2 *creator = NULL;
glong creator_items;
BlockBackend *blk;
char *type = NULL;
VHDXImageType image_type;
Error *local_err = NULL;
assert(opts->driver == BLOCKDEV_DRIVER_VHDX);
vhdx_opts = &opts->u.vhdx;
image_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
BDRV_SECTOR_SIZE);
log_size = qemu_opt_get_size_del(opts, VHDX_BLOCK_OPT_LOG_SIZE, 0);
block_size = qemu_opt_get_size_del(opts, VHDX_BLOCK_OPT_BLOCK_SIZE, 0);
type = qemu_opt_get_del(opts, BLOCK_OPT_SUBFMT);
use_zero_blocks = qemu_opt_get_bool_del(opts, VHDX_BLOCK_OPT_ZERO, true);
/* Validate options and set default values */
image_size = vhdx_opts->size;
if (image_size > VHDX_MAX_IMAGE_SIZE) {
error_setg_errno(errp, EINVAL, "Image size too large; max of 64TB");
return -EINVAL;
ret = -EINVAL;
goto exit;
}
if (!vhdx_opts->has_log_size) {
log_size = DEFAULT_LOG_SIZE;
} else {
log_size = vhdx_opts->log_size;
}
if (log_size < MiB || (log_size % MiB) != 0) {
error_setg_errno(errp, EINVAL, "Log size must be a multiple of 1 MB");
return -EINVAL;
if (type == NULL) {
type = g_strdup("dynamic");
}
if (!vhdx_opts->has_block_state_zero) {
use_zero_blocks = true;
} else {
use_zero_blocks = vhdx_opts->block_state_zero;
}
if (!vhdx_opts->has_subformat) {
vhdx_opts->subformat = BLOCKDEV_VHDX_SUBFORMAT_DYNAMIC;
}
switch (vhdx_opts->subformat) {
case BLOCKDEV_VHDX_SUBFORMAT_DYNAMIC:
if (!strcmp(type, "dynamic")) {
image_type = VHDX_TYPE_DYNAMIC;
break;
case BLOCKDEV_VHDX_SUBFORMAT_FIXED:
} else if (!strcmp(type, "fixed")) {
image_type = VHDX_TYPE_FIXED;
break;
default:
g_assert_not_reached();
} else if (!strcmp(type, "differencing")) {
error_setg_errno(errp, ENOTSUP,
"Differencing files not yet supported");
ret = -ENOTSUP;
goto exit;
} else {
error_setg(errp, "Invalid subformat '%s'", type);
ret = -EINVAL;
goto exit;
}
/* These are pretty arbitrary, and mainly designed to keep the BAT
* size reasonable to load into RAM */
if (vhdx_opts->has_block_size) {
block_size = vhdx_opts->block_size;
} else {
if (block_size == 0) {
if (image_size > 32 * TiB) {
block_size = 64 * MiB;
} else if (image_size > (uint64_t) 100 * GiB) {
@@ -1873,27 +1856,30 @@ static int coroutine_fn vhdx_co_create(BlockdevCreateOptions *opts,
}
}
if (block_size < MiB || (block_size % MiB) != 0) {
error_setg_errno(errp, EINVAL, "Block size must be a multiple of 1 MB");
return -EINVAL;
}
if (block_size > VHDX_BLOCK_SIZE_MAX) {
error_setg_errno(errp, EINVAL, "Block size must not exceed %d",
VHDX_BLOCK_SIZE_MAX);
return -EINVAL;
}
/* Create BlockBackend to write to the image */
bs = bdrv_open_blockdev_ref(vhdx_opts->file, errp);
if (bs == NULL) {
return -EIO;
}
/* make the log size close to what was specified, but must be
* min 1MB, and multiple of 1MB */
log_size = ROUND_UP(log_size, MiB);
blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
ret = blk_insert_bs(blk, bs, errp);
block_size = ROUND_UP(block_size, MiB);
block_size = block_size > VHDX_BLOCK_SIZE_MAX ? VHDX_BLOCK_SIZE_MAX :
block_size;
ret = bdrv_create_file(filename, opts, &local_err);
if (ret < 0) {
goto delete_and_exit;
error_propagate(errp, local_err);
goto exit;
}
blk = blk_new_open(filename, NULL, NULL,
BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL,
&local_err);
if (blk == NULL) {
error_propagate(errp, local_err);
ret = -EIO;
goto exit;
}
blk_set_allow_write_beyond_eof(blk, true);
/* Create (A) */
@@ -1945,109 +1931,12 @@ static int coroutine_fn vhdx_co_create(BlockdevCreateOptions *opts,
delete_and_exit:
blk_unref(blk);
bdrv_unref(bs);
exit:
g_free(type);
g_free(creator);
return ret;
}
static int coroutine_fn vhdx_co_create_opts(const char *filename,
QemuOpts *opts,
Error **errp)
{
BlockdevCreateOptions *create_options = NULL;
QDict *qdict = NULL;
QObject *qobj;
Visitor *v;
BlockDriverState *bs = NULL;
Error *local_err = NULL;
int ret;
static const QDictRenames opt_renames[] = {
{ VHDX_BLOCK_OPT_LOG_SIZE, "log-size" },
{ VHDX_BLOCK_OPT_BLOCK_SIZE, "block-size" },
{ VHDX_BLOCK_OPT_ZERO, "block-state-zero" },
{ NULL, NULL },
};
/* Parse options and convert legacy syntax */
qdict = qemu_opts_to_qdict_filtered(opts, NULL, &vhdx_create_opts, true);
if (!qdict_rename_keys(qdict, opt_renames, errp)) {
ret = -EINVAL;
goto fail;
}
/* Create and open the file (protocol layer) */
ret = bdrv_create_file(filename, opts, &local_err);
if (ret < 0) {
error_propagate(errp, local_err);
goto fail;
}
bs = bdrv_open(filename, NULL, NULL,
BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp);
if (bs == NULL) {
ret = -EIO;
goto fail;
}
/* Now get the QAPI type BlockdevCreateOptions */
qdict_put_str(qdict, "driver", "vhdx");
qdict_put_str(qdict, "file", bs->node_name);
qobj = qdict_crumple(qdict, errp);
QDECREF(qdict);
qdict = qobject_to(QDict, qobj);
if (qdict == NULL) {
ret = -EINVAL;
goto fail;
}
v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
visit_free(v);
if (local_err) {
error_propagate(errp, local_err);
ret = -EINVAL;
goto fail;
}
/* Silently round up sizes:
* The image size is rounded to 512 bytes. Make the block and log size
* close to what was specified, but must be at least 1MB, and a multiple of
* 1 MB. Also respect VHDX_BLOCK_SIZE_MAX for block sizes. block_size = 0
* means auto, which is represented by a missing key in QAPI. */
assert(create_options->driver == BLOCKDEV_DRIVER_VHDX);
create_options->u.vhdx.size =
ROUND_UP(create_options->u.vhdx.size, BDRV_SECTOR_SIZE);
if (create_options->u.vhdx.has_log_size) {
create_options->u.vhdx.log_size =
ROUND_UP(create_options->u.vhdx.log_size, MiB);
}
if (create_options->u.vhdx.has_block_size) {
create_options->u.vhdx.block_size =
ROUND_UP(create_options->u.vhdx.block_size, MiB);
if (create_options->u.vhdx.block_size == 0) {
create_options->u.vhdx.has_block_size = false;
}
if (create_options->u.vhdx.block_size > VHDX_BLOCK_SIZE_MAX) {
create_options->u.vhdx.block_size = VHDX_BLOCK_SIZE_MAX;
}
}
/* Create the vhdx image (format layer) */
ret = vhdx_co_create(create_options, errp);
fail:
QDECREF(qdict);
bdrv_unref(bs);
qapi_free_BlockdevCreateOptions(create_options);
return ret;
}
/* If opened r/w, the VHDX driver will automatically replay the log,
* if one is present, inside the vhdx_open() call.
*
@@ -2116,7 +2005,6 @@ static BlockDriver bdrv_vhdx = {
.bdrv_child_perm = bdrv_format_default_perms,
.bdrv_co_readv = vhdx_co_readv,
.bdrv_co_writev = vhdx_co_writev,
.bdrv_co_create = vhdx_co_create,
.bdrv_co_create_opts = vhdx_co_create_opts,
.bdrv_get_info = vhdx_get_info,
.bdrv_co_check = vhdx_co_check,

View File

@@ -32,9 +32,6 @@
#include "migration/blocker.h"
#include "qemu/bswap.h"
#include "qemu/uuid.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qobject-input-visitor.h"
#include "qapi/qapi-visit-block-core.h"
/**************************************************************/
@@ -169,8 +166,6 @@ static QemuOptsList vpc_runtime_opts = {
}
};
static QemuOptsList vpc_create_opts;
static uint32_t vpc_checksum(uint8_t* buf, size_t size)
{
uint32_t res = 0;
@@ -902,19 +897,60 @@ static int create_fixed_disk(BlockBackend *blk, uint8_t *buf,
return ret;
}
static int calculate_rounded_image_size(BlockdevCreateOptionsVpc *vpc_opts,
uint16_t *out_cyls,
uint8_t *out_heads,
uint8_t *out_secs_per_cyl,
int64_t *out_total_sectors,
Error **errp)
static int coroutine_fn vpc_co_create_opts(const char *filename, QemuOpts *opts,
Error **errp)
{
int64_t total_size = vpc_opts->size;
uint8_t buf[1024];
VHDFooter *footer = (VHDFooter *) buf;
char *disk_type_param;
int i;
uint16_t cyls = 0;
uint8_t heads = 0;
uint8_t secs_per_cyl = 0;
int64_t total_sectors;
int i;
int64_t total_size;
int disk_type;
int ret = -EIO;
bool force_size;
Error *local_err = NULL;
BlockBackend *blk = NULL;
/* Read out options */
total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
BDRV_SECTOR_SIZE);
disk_type_param = qemu_opt_get_del(opts, BLOCK_OPT_SUBFMT);
if (disk_type_param) {
if (!strcmp(disk_type_param, "dynamic")) {
disk_type = VHD_DYNAMIC;
} else if (!strcmp(disk_type_param, "fixed")) {
disk_type = VHD_FIXED;
} else {
error_setg(errp, "Invalid disk type, %s", disk_type_param);
ret = -EINVAL;
goto out;
}
} else {
disk_type = VHD_DYNAMIC;
}
force_size = qemu_opt_get_bool_del(opts, VPC_OPT_FORCE_SIZE, false);
ret = bdrv_create_file(filename, opts, &local_err);
if (ret < 0) {
error_propagate(errp, local_err);
goto out;
}
blk = blk_new_open(filename, NULL, NULL,
BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL,
&local_err);
if (blk == NULL) {
error_propagate(errp, local_err);
ret = -EIO;
goto out;
}
blk_set_allow_write_beyond_eof(blk, true);
/*
* Calculate matching total_size and geometry. Increase the number of
@@ -925,7 +961,7 @@ static int calculate_rounded_image_size(BlockdevCreateOptionsVpc *vpc_opts,
* we set the geometry to 65535 x 16 x 255 (CxHxS) sectors and use
* the image size from the VHD footer to calculate total_sectors.
*/
if (vpc_opts->force_size) {
if (force_size) {
/* This will force the use of total_size for sector count, below */
cyls = VHD_CHS_MAX_C;
heads = VHD_CHS_MAX_H;
@@ -942,95 +978,19 @@ static int calculate_rounded_image_size(BlockdevCreateOptionsVpc *vpc_opts,
/* Allow a maximum disk size of 2040 GiB */
if (total_sectors > VHD_MAX_SECTORS) {
error_setg(errp, "Disk size is too large, max size is 2040 GiB");
return -EFBIG;
ret = -EFBIG;
goto out;
}
} else {
total_sectors = (int64_t) cyls * heads * secs_per_cyl;
}
*out_total_sectors = total_sectors;
if (out_cyls) {
*out_cyls = cyls;
*out_heads = heads;
*out_secs_per_cyl = secs_per_cyl;
}
return 0;
}
static int coroutine_fn vpc_co_create(BlockdevCreateOptions *opts,
Error **errp)
{
BlockdevCreateOptionsVpc *vpc_opts;
BlockBackend *blk = NULL;
BlockDriverState *bs = NULL;
uint8_t buf[1024];
VHDFooter *footer = (VHDFooter *) buf;
uint16_t cyls = 0;
uint8_t heads = 0;
uint8_t secs_per_cyl = 0;
int64_t total_sectors;
int64_t total_size;
int disk_type;
int ret = -EIO;
assert(opts->driver == BLOCKDEV_DRIVER_VPC);
vpc_opts = &opts->u.vpc;
/* Validate options and set default values */
total_size = vpc_opts->size;
if (!vpc_opts->has_subformat) {
vpc_opts->subformat = BLOCKDEV_VPC_SUBFORMAT_DYNAMIC;
}
switch (vpc_opts->subformat) {
case BLOCKDEV_VPC_SUBFORMAT_DYNAMIC:
disk_type = VHD_DYNAMIC;
break;
case BLOCKDEV_VPC_SUBFORMAT_FIXED:
disk_type = VHD_FIXED;
break;
default:
g_assert_not_reached();
}
/* Create BlockBackend to write to the image */
bs = bdrv_open_blockdev_ref(vpc_opts->file, errp);
if (bs == NULL) {
return -EIO;
}
blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
ret = blk_insert_bs(blk, bs, errp);
if (ret < 0) {
goto out;
}
blk_set_allow_write_beyond_eof(blk, true);
/* Get geometry and check that it matches the image size*/
ret = calculate_rounded_image_size(vpc_opts, &cyls, &heads, &secs_per_cyl,
&total_sectors, errp);
if (ret < 0) {
goto out;
}
if (total_size != total_sectors * BDRV_SECTOR_SIZE) {
error_setg(errp, "The requested image size cannot be represented in "
"CHS geometry");
error_append_hint(errp, "Try size=%llu or force-size=on (the "
"latter makes the image incompatible with "
"Virtual PC)",
total_sectors * BDRV_SECTOR_SIZE);
ret = -EINVAL;
goto out;
total_sectors = (int64_t)cyls * heads * secs_per_cyl;
total_size = total_sectors * BDRV_SECTOR_SIZE;
}
/* Prepare the Hard Disk Footer */
memset(buf, 0, 1024);
memcpy(footer->creator, "conectix", 8);
if (vpc_opts->force_size) {
if (force_size) {
memcpy(footer->creator_app, "qem2", 4);
} else {
memcpy(footer->creator_app, "qemu", 4);
@@ -1072,98 +1032,10 @@ static int coroutine_fn vpc_co_create(BlockdevCreateOptions *opts,
out:
blk_unref(blk);
bdrv_unref(bs);
g_free(disk_type_param);
return ret;
}
static int coroutine_fn vpc_co_create_opts(const char *filename,
QemuOpts *opts, Error **errp)
{
BlockdevCreateOptions *create_options = NULL;
QDict *qdict = NULL;
QObject *qobj;
Visitor *v;
BlockDriverState *bs = NULL;
Error *local_err = NULL;
int ret;
static const QDictRenames opt_renames[] = {
{ VPC_OPT_FORCE_SIZE, "force-size" },
{ NULL, NULL },
};
/* Parse options and convert legacy syntax */
qdict = qemu_opts_to_qdict_filtered(opts, NULL, &vpc_create_opts, true);
if (!qdict_rename_keys(qdict, opt_renames, errp)) {
ret = -EINVAL;
goto fail;
}
/* Create and open the file (protocol layer) */
ret = bdrv_create_file(filename, opts, &local_err);
if (ret < 0) {
error_propagate(errp, local_err);
goto fail;
}
bs = bdrv_open(filename, NULL, NULL,
BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp);
if (bs == NULL) {
ret = -EIO;
goto fail;
}
/* Now get the QAPI type BlockdevCreateOptions */
qdict_put_str(qdict, "driver", "vpc");
qdict_put_str(qdict, "file", bs->node_name);
qobj = qdict_crumple(qdict, errp);
QDECREF(qdict);
qdict = qobject_to(QDict, qobj);
if (qdict == NULL) {
ret = -EINVAL;
goto fail;
}
v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
visit_free(v);
if (local_err) {
error_propagate(errp, local_err);
ret = -EINVAL;
goto fail;
}
/* Silently round up size */
assert(create_options->driver == BLOCKDEV_DRIVER_VPC);
create_options->u.vpc.size =
ROUND_UP(create_options->u.vpc.size, BDRV_SECTOR_SIZE);
if (!create_options->u.vpc.force_size) {
int64_t total_sectors;
ret = calculate_rounded_image_size(&create_options->u.vpc, NULL, NULL,
NULL, &total_sectors, errp);
if (ret < 0) {
goto fail;
}
create_options->u.vpc.size = total_sectors * BDRV_SECTOR_SIZE;
}
/* Create the vpc image (format layer) */
ret = vpc_co_create(create_options, errp);
fail:
QDECREF(qdict);
bdrv_unref(bs);
qapi_free_BlockdevCreateOptions(create_options);
return ret;
}
static int vpc_has_zero_init(BlockDriverState *bs)
{
BDRVVPCState *s = bs->opaque;
@@ -1224,7 +1096,6 @@ static BlockDriver bdrv_vpc = {
.bdrv_close = vpc_close,
.bdrv_reopen_prepare = vpc_reopen_prepare,
.bdrv_child_perm = bdrv_format_default_perms,
.bdrv_co_create = vpc_co_create,
.bdrv_co_create_opts = vpc_co_create_opts,
.bdrv_co_preadv = vpc_co_preadv,

View File

@@ -3129,7 +3129,7 @@ static void vvfat_qcow_options(int *child_flags, QDict *child_options,
int parent_flags, QDict *parent_options)
{
qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "off");
qdict_set_default_str(child_options, BDRV_OPT_CACHE_NO_FLUSH, "on");
*child_flags = BDRV_O_NO_FLUSH;
}
static const BdrvChildRole child_vvfat_qcow = {

View File

@@ -150,7 +150,7 @@ void blockdev_mark_auto_del(BlockBackend *blk)
aio_context_acquire(aio_context);
if (bs->job) {
block_job_cancel(bs->job, false);
block_job_cancel(bs->job);
}
aio_context_release(aio_context);
@@ -334,8 +334,7 @@ static bool parse_stats_intervals(BlockAcctStats *stats, QList *intervals,
case QTYPE_QSTRING: {
unsigned long long length;
const char *str = qstring_get_str(qobject_to(QString,
entry->value));
const char *str = qstring_get_str(qobject_to_qstring(entry->value));
if (parse_uint_full(str, &length, 10) == 0 &&
length > 0 && length <= UINT_MAX) {
block_acct_add_interval(stats, (unsigned) length);
@@ -347,7 +346,7 @@ static bool parse_stats_intervals(BlockAcctStats *stats, QList *intervals,
}
case QTYPE_QNUM: {
int64_t length = qnum_get_int(qobject_to(QNum, entry->value));
int64_t length = qnum_get_int(qobject_to_qnum(entry->value));
if (length > 0 && length <= UINT_MAX) {
block_acct_add_interval(stats, (unsigned) length);
@@ -2119,9 +2118,6 @@ static void block_dirty_bitmap_clear_prepare(BlkActionState *common,
if (bdrv_dirty_bitmap_frozen(state->bitmap)) {
error_setg(errp, "Cannot modify a frozen bitmap");
return;
} else if (bdrv_dirty_bitmap_qmp_locked(state->bitmap)) {
error_setg(errp, "Cannot modify a locked bitmap");
return;
} else if (!bdrv_dirty_bitmap_enabled(state->bitmap)) {
error_setg(errp, "Cannot clear a disabled bitmap");
return;
@@ -2866,11 +2862,6 @@ void qmp_block_dirty_bitmap_remove(const char *node, const char *name,
"Bitmap '%s' is currently frozen and cannot be removed",
name);
return;
} else if (bdrv_dirty_bitmap_qmp_locked(bitmap)) {
error_setg(errp,
"Bitmap '%s' is currently locked and cannot be removed",
name);
return;
}
if (bdrv_dirty_bitmap_get_persistance(bitmap)) {
@@ -2905,11 +2896,6 @@ void qmp_block_dirty_bitmap_clear(const char *node, const char *name,
"Bitmap '%s' is currently frozen and cannot be modified",
name);
return;
} else if (bdrv_dirty_bitmap_qmp_locked(bitmap)) {
error_setg(errp,
"Bitmap '%s' is currently locked and cannot be modified",
name);
return;
} else if (!bdrv_dirty_bitmap_enabled(bitmap)) {
error_setg(errp,
"Bitmap '%s' is currently disabled and cannot be cleared",
@@ -3275,7 +3261,7 @@ static BlockJob *do_drive_backup(DriveBackup *backup, BlockJobTxn *txn,
AioContext *aio_context;
QDict *options = NULL;
Error *local_err = NULL;
int flags, job_flags = BLOCK_JOB_DEFAULT;
int flags;
int64_t size;
bool set_backing_hd = false;
@@ -3294,12 +3280,6 @@ static BlockJob *do_drive_backup(DriveBackup *backup, BlockJobTxn *txn,
if (!backup->has_job_id) {
backup->job_id = NULL;
}
if (!backup->has_auto_finalize) {
backup->auto_finalize = true;
}
if (!backup->has_auto_dismiss) {
backup->auto_dismiss = true;
}
if (!backup->has_compress) {
backup->compress = false;
}
@@ -3390,24 +3370,12 @@ static BlockJob *do_drive_backup(DriveBackup *backup, BlockJobTxn *txn,
bdrv_unref(target_bs);
goto out;
}
if (bdrv_dirty_bitmap_qmp_locked(bmap)) {
error_setg(errp,
"Bitmap '%s' is currently locked and cannot be used for "
"backup", backup->bitmap);
goto out;
}
}
if (!backup->auto_finalize) {
job_flags |= BLOCK_JOB_MANUAL_FINALIZE;
}
if (!backup->auto_dismiss) {
job_flags |= BLOCK_JOB_MANUAL_DISMISS;
}
job = backup_job_create(backup->job_id, bs, target_bs, backup->speed,
backup->sync, bmap, backup->compress,
backup->on_source_error, backup->on_target_error,
job_flags, NULL, NULL, txn, &local_err);
BLOCK_JOB_DEFAULT, NULL, NULL, txn, &local_err);
bdrv_unref(target_bs);
if (local_err != NULL) {
error_propagate(errp, local_err);
@@ -3442,7 +3410,6 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, BlockJobTxn *txn,
Error *local_err = NULL;
AioContext *aio_context;
BlockJob *job = NULL;
int job_flags = BLOCK_JOB_DEFAULT;
if (!backup->has_speed) {
backup->speed = 0;
@@ -3456,12 +3423,6 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, BlockJobTxn *txn,
if (!backup->has_job_id) {
backup->job_id = NULL;
}
if (!backup->has_auto_finalize) {
backup->auto_finalize = true;
}
if (!backup->has_auto_dismiss) {
backup->auto_dismiss = true;
}
if (!backup->has_compress) {
backup->compress = false;
}
@@ -3490,16 +3451,10 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, BlockJobTxn *txn,
goto out;
}
}
if (!backup->auto_finalize) {
job_flags |= BLOCK_JOB_MANUAL_FINALIZE;
}
if (!backup->auto_dismiss) {
job_flags |= BLOCK_JOB_MANUAL_DISMISS;
}
job = backup_job_create(backup->job_id, bs, target_bs, backup->speed,
backup->sync, NULL, backup->compress,
backup->on_source_error, backup->on_target_error,
job_flags, NULL, NULL, txn, &local_err);
BLOCK_JOB_DEFAULT, NULL, NULL, txn, &local_err);
if (local_err != NULL) {
error_propagate(errp, local_err);
}
@@ -3851,7 +3806,7 @@ void qmp_block_job_cancel(const char *device,
}
trace_qmp_block_job_cancel(job);
block_job_user_cancel(job, force, errp);
block_job_cancel(job);
out:
aio_context_release(aio_context);
}
@@ -3861,12 +3816,12 @@ void qmp_block_job_pause(const char *device, Error **errp)
AioContext *aio_context;
BlockJob *job = find_block_job(device, &aio_context, errp);
if (!job) {
if (!job || block_job_user_paused(job)) {
return;
}
trace_qmp_block_job_pause(job);
block_job_user_pause(job, errp);
block_job_user_pause(job);
aio_context_release(aio_context);
}
@@ -3875,12 +3830,12 @@ void qmp_block_job_resume(const char *device, Error **errp)
AioContext *aio_context;
BlockJob *job = find_block_job(device, &aio_context, errp);
if (!job) {
if (!job || !block_job_user_paused(job)) {
return;
}
trace_qmp_block_job_resume(job);
block_job_user_resume(job, errp);
block_job_user_resume(job);
aio_context_release(aio_context);
}
@@ -3898,34 +3853,6 @@ void qmp_block_job_complete(const char *device, Error **errp)
aio_context_release(aio_context);
}
void qmp_block_job_finalize(const char *id, Error **errp)
{
AioContext *aio_context;
BlockJob *job = find_block_job(id, &aio_context, errp);
if (!job) {
return;
}
trace_qmp_block_job_finalize(job);
block_job_finalize(job, errp);
aio_context_release(aio_context);
}
void qmp_block_job_dismiss(const char *id, Error **errp)
{
AioContext *aio_context;
BlockJob *job = find_block_job(id, &aio_context, errp);
if (!job) {
return;
}
trace_qmp_block_job_dismiss(job);
block_job_dismiss(&job, errp);
aio_context_release(aio_context);
}
void qmp_change_backing_file(const char *device,
const char *image_node_name,
const char *backing_file,
@@ -4045,6 +3972,7 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
QObject *obj;
Visitor *v = qobject_output_visitor_new(&obj);
QDict *qdict;
const QDictEntry *ent;
Error *local_err = NULL;
visit_type_BlockdevOptions(v, NULL, &options, &local_err);
@@ -4054,10 +3982,23 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
}
visit_complete(v, &obj);
qdict = qobject_to(QDict, obj);
qdict = qobject_to_qdict(obj);
qdict_flatten(qdict);
/*
* Rewrite "backing": null to "backing": ""
* TODO Rewrite "" to null instead, and perhaps not even here
*/
for (ent = qdict_first(qdict); ent; ent = qdict_next(qdict, ent)) {
char *dot = strrchr(ent->key, '.');
if (!strcmp(dot ? dot + 1 : ent->key, "backing")
&& qobject_type(ent->value) == QTYPE_QNULL) {
qdict_put(qdict, ent->key, qstring_new());
}
}
if (!qdict_get_try_str(qdict, "node-name")) {
error_setg(errp, "'node-name' must be specified for the root node");
goto fail;
@@ -4239,49 +4180,6 @@ void qmp_x_blockdev_set_iothread(const char *node_name, StrOrNull *iothread,
aio_context_release(old_context);
}
void qmp_x_block_latency_histogram_set(
const char *device,
bool has_boundaries, uint64List *boundaries,
bool has_boundaries_read, uint64List *boundaries_read,
bool has_boundaries_write, uint64List *boundaries_write,
bool has_boundaries_flush, uint64List *boundaries_flush,
Error **errp)
{
BlockBackend *blk = blk_by_name(device);
BlockAcctStats *stats;
if (!blk) {
error_setg(errp, "Device '%s' not found", device);
return;
}
stats = blk_get_stats(blk);
if (!has_boundaries && !has_boundaries_read && !has_boundaries_write &&
!has_boundaries_flush)
{
block_latency_histograms_clear(stats);
return;
}
if (has_boundaries || has_boundaries_read) {
block_latency_histogram_set(
stats, BLOCK_ACCT_READ,
has_boundaries_read ? boundaries_read : boundaries);
}
if (has_boundaries || has_boundaries_write) {
block_latency_histogram_set(
stats, BLOCK_ACCT_WRITE,
has_boundaries_write ? boundaries_write : boundaries);
}
if (has_boundaries || has_boundaries_flush) {
block_latency_histogram_set(
stats, BLOCK_ACCT_FLUSH,
has_boundaries_flush ? boundaries_flush : boundaries);
}
}
QemuOptsList qemu_common_drive_opts = {
.name = "drive",
.head = QTAILQ_HEAD_INITIALIZER(qemu_common_drive_opts.head),

View File

@@ -28,7 +28,6 @@
#include "block/block.h"
#include "block/blockjob_int.h"
#include "block/block_int.h"
#include "block/trace.h"
#include "sysemu/block-backend.h"
#include "qapi/error.h"
#include "qapi/qapi-events-block-core.h"
@@ -42,64 +41,6 @@
* block_job_enter. */
static QemuMutex block_job_mutex;
/* BlockJob State Transition Table */
bool BlockJobSTT[BLOCK_JOB_STATUS__MAX][BLOCK_JOB_STATUS__MAX] = {
/* U, C, R, P, Y, S, W, D, X, E, N */
/* U: */ [BLOCK_JOB_STATUS_UNDEFINED] = {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
/* C: */ [BLOCK_JOB_STATUS_CREATED] = {0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1},
/* R: */ [BLOCK_JOB_STATUS_RUNNING] = {0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0},
/* P: */ [BLOCK_JOB_STATUS_PAUSED] = {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0},
/* Y: */ [BLOCK_JOB_STATUS_READY] = {0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0},
/* S: */ [BLOCK_JOB_STATUS_STANDBY] = {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0},
/* W: */ [BLOCK_JOB_STATUS_WAITING] = {0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0},
/* D: */ [BLOCK_JOB_STATUS_PENDING] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0},
/* X: */ [BLOCK_JOB_STATUS_ABORTING] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0},
/* E: */ [BLOCK_JOB_STATUS_CONCLUDED] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
/* N: */ [BLOCK_JOB_STATUS_NULL] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
};
bool BlockJobVerbTable[BLOCK_JOB_VERB__MAX][BLOCK_JOB_STATUS__MAX] = {
/* U, C, R, P, Y, S, W, D, X, E, N */
[BLOCK_JOB_VERB_CANCEL] = {0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0},
[BLOCK_JOB_VERB_PAUSE] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
[BLOCK_JOB_VERB_RESUME] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
[BLOCK_JOB_VERB_SET_SPEED] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
[BLOCK_JOB_VERB_COMPLETE] = {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0},
[BLOCK_JOB_VERB_FINALIZE] = {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0},
[BLOCK_JOB_VERB_DISMISS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0},
};
static void block_job_state_transition(BlockJob *job, BlockJobStatus s1)
{
BlockJobStatus s0 = job->status;
assert(s1 >= 0 && s1 <= BLOCK_JOB_STATUS__MAX);
trace_block_job_state_transition(job, job->ret, BlockJobSTT[s0][s1] ?
"allowed" : "disallowed",
qapi_enum_lookup(&BlockJobStatus_lookup,
s0),
qapi_enum_lookup(&BlockJobStatus_lookup,
s1));
assert(BlockJobSTT[s0][s1]);
job->status = s1;
}
static int block_job_apply_verb(BlockJob *job, BlockJobVerb bv, Error **errp)
{
assert(bv >= 0 && bv <= BLOCK_JOB_VERB__MAX);
trace_block_job_apply_verb(job, qapi_enum_lookup(&BlockJobStatus_lookup,
job->status),
qapi_enum_lookup(&BlockJobVerb_lookup, bv),
BlockJobVerbTable[bv][job->status] ?
"allowed" : "prohibited");
if (BlockJobVerbTable[bv][job->status]) {
return 0;
}
error_setg(errp, "Job '%s' in state '%s' cannot accept command verb '%s'",
job->id, qapi_enum_lookup(&BlockJobStatus_lookup, job->status),
qapi_enum_lookup(&BlockJobVerb_lookup, bv));
return -EPERM;
}
static void block_job_lock(void)
{
qemu_mutex_lock(&block_job_mutex);
@@ -117,7 +58,6 @@ static void __attribute__((__constructor__)) block_job_init(void)
static void block_job_event_cancelled(BlockJob *job);
static void block_job_event_completed(BlockJob *job, const char *msg);
static int block_job_event_pending(BlockJob *job);
static void block_job_enter_cond(BlockJob *job, bool(*fn)(BlockJob *job));
/* Transactional group of block jobs */
@@ -231,7 +171,6 @@ static void block_job_detach_aio_context(void *opaque);
void block_job_unref(BlockJob *job)
{
if (--job->refcnt == 0) {
assert(job->status == BLOCK_JOB_STATUS_NULL);
BlockDriverState *bs = blk_bs(job->blk);
QLIST_REMOVE(job, job_list);
bs->job = NULL;
@@ -381,88 +320,25 @@ void block_job_start(BlockJob *job)
job->pause_count--;
job->busy = true;
job->paused = false;
block_job_state_transition(job, BLOCK_JOB_STATUS_RUNNING);
bdrv_coroutine_enter(blk_bs(job->blk), job->co);
}
static void block_job_decommission(BlockJob *job)
{
assert(job);
job->completed = true;
job->busy = false;
job->paused = false;
job->deferred_to_main_loop = true;
block_job_state_transition(job, BLOCK_JOB_STATUS_NULL);
block_job_unref(job);
}
static void block_job_do_dismiss(BlockJob *job)
{
block_job_decommission(job);
}
static void block_job_conclude(BlockJob *job)
{
block_job_state_transition(job, BLOCK_JOB_STATUS_CONCLUDED);
if (job->auto_dismiss || !block_job_started(job)) {
block_job_do_dismiss(job);
}
}
static void block_job_update_rc(BlockJob *job)
{
if (!job->ret && block_job_is_cancelled(job)) {
job->ret = -ECANCELED;
}
if (job->ret) {
block_job_state_transition(job, BLOCK_JOB_STATUS_ABORTING);
}
}
static int block_job_prepare(BlockJob *job)
{
if (job->ret == 0 && job->driver->prepare) {
job->ret = job->driver->prepare(job);
}
return job->ret;
}
static void block_job_commit(BlockJob *job)
{
assert(!job->ret);
if (job->driver->commit) {
job->driver->commit(job);
}
}
static void block_job_abort(BlockJob *job)
{
assert(job->ret);
if (job->driver->abort) {
job->driver->abort(job);
}
}
static void block_job_clean(BlockJob *job)
{
if (job->driver->clean) {
job->driver->clean(job);
}
}
static int block_job_finalize_single(BlockJob *job)
static void block_job_completed_single(BlockJob *job)
{
assert(job->completed);
/* Ensure abort is called for late-transactional failures */
block_job_update_rc(job);
if (!job->ret) {
block_job_commit(job);
if (job->driver->commit) {
job->driver->commit(job);
}
} else {
block_job_abort(job);
if (job->driver->abort) {
job->driver->abort(job);
}
}
if (job->driver->clean) {
job->driver->clean(job);
}
block_job_clean(job);
if (job->cb) {
job->cb(job->opaque, job->ret);
@@ -481,13 +357,14 @@ static int block_job_finalize_single(BlockJob *job)
}
}
QLIST_REMOVE(job, txn_list);
block_job_txn_unref(job->txn);
block_job_conclude(job);
return 0;
if (job->txn) {
QLIST_REMOVE(job, txn_list);
block_job_txn_unref(job->txn);
}
block_job_unref(job);
}
static void block_job_cancel_async(BlockJob *job, bool force)
static void block_job_cancel_async(BlockJob *job)
{
if (job->iostatus != BLOCK_DEVICE_IO_STATUS_OK) {
block_job_iostatus_reset(job);
@@ -498,30 +375,6 @@ static void block_job_cancel_async(BlockJob *job, bool force)
job->pause_count--;
}
job->cancelled = true;
/* To prevent 'force == false' overriding a previous 'force == true' */
job->force |= force;
}
static int block_job_txn_apply(BlockJobTxn *txn, int fn(BlockJob *), bool lock)
{
AioContext *ctx;
BlockJob *job, *next;
int rc = 0;
QLIST_FOREACH_SAFE(job, &txn->jobs, txn_list, next) {
if (lock) {
ctx = blk_get_aio_context(job->blk);
aio_context_acquire(ctx);
}
rc = fn(job);
if (lock) {
aio_context_release(ctx);
}
if (rc) {
break;
}
}
return rc;
}
static int block_job_finish_sync(BlockJob *job,
@@ -583,7 +436,7 @@ static void block_job_completed_txn_abort(BlockJob *job)
* on the caller, so leave it. */
QLIST_FOREACH(other_job, &txn->jobs, txn_list) {
if (other_job != job) {
block_job_cancel_async(other_job, false);
block_job_cancel_async(other_job);
}
}
while (!QLIST_EMPTY(&txn->jobs)) {
@@ -593,39 +446,18 @@ static void block_job_completed_txn_abort(BlockJob *job)
assert(other_job->cancelled);
block_job_finish_sync(other_job, NULL, NULL);
}
block_job_finalize_single(other_job);
block_job_completed_single(other_job);
aio_context_release(ctx);
}
block_job_txn_unref(txn);
}
static int block_job_needs_finalize(BlockJob *job)
{
return !job->auto_finalize;
}
static void block_job_do_finalize(BlockJob *job)
{
int rc;
assert(job && job->txn);
/* prepare the transaction to complete */
rc = block_job_txn_apply(job->txn, block_job_prepare, true);
if (rc) {
block_job_completed_txn_abort(job);
} else {
block_job_txn_apply(job->txn, block_job_finalize_single, true);
}
}
static void block_job_completed_txn_success(BlockJob *job)
{
AioContext *ctx;
BlockJobTxn *txn = job->txn;
BlockJob *other_job;
block_job_state_transition(job, BLOCK_JOB_STATUS_WAITING);
BlockJob *other_job, *next;
/*
* Successful completion, see if there are other running jobs in this
* txn.
@@ -634,14 +466,14 @@ static void block_job_completed_txn_success(BlockJob *job)
if (!other_job->completed) {
return;
}
assert(other_job->ret == 0);
}
block_job_txn_apply(txn, block_job_event_pending, false);
/* If no jobs need manual finalization, automatically do so */
if (block_job_txn_apply(txn, block_job_needs_finalize, false) == 0) {
block_job_do_finalize(job);
/* We are the last completed job, commit the transaction. */
QLIST_FOREACH_SAFE(other_job, &txn->jobs, txn_list, next) {
ctx = blk_get_aio_context(other_job->blk);
aio_context_acquire(ctx);
assert(other_job->ret == 0);
block_job_completed_single(other_job);
aio_context_release(ctx);
}
}
@@ -660,9 +492,6 @@ void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
error_setg(errp, QERR_UNSUPPORTED);
return;
}
if (block_job_apply_verb(job, BLOCK_JOB_VERB_SET_SPEED, errp)) {
return;
}
job->driver->set_speed(job, speed, &local_err);
if (local_err) {
error_propagate(errp, local_err);
@@ -670,7 +499,7 @@ void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
}
job->speed = speed;
if (speed && speed <= old_speed) {
if (speed <= old_speed) {
return;
}
@@ -682,10 +511,8 @@ void block_job_complete(BlockJob *job, Error **errp)
{
/* Should not be reachable via external interface for internal jobs */
assert(job->id);
if (block_job_apply_verb(job, BLOCK_JOB_VERB_COMPLETE, errp)) {
return;
}
if (job->pause_count || job->cancelled || !job->driver->complete) {
if (job->pause_count || job->cancelled ||
!block_job_started(job) || !job->driver->complete) {
error_setg(errp, "The active block job '%s' cannot be completed",
job->id);
return;
@@ -694,37 +521,8 @@ void block_job_complete(BlockJob *job, Error **errp)
job->driver->complete(job, errp);
}
void block_job_finalize(BlockJob *job, Error **errp)
void block_job_user_pause(BlockJob *job)
{
assert(job && job->id && job->txn);
if (block_job_apply_verb(job, BLOCK_JOB_VERB_FINALIZE, errp)) {
return;
}
block_job_do_finalize(job);
}
void block_job_dismiss(BlockJob **jobptr, Error **errp)
{
BlockJob *job = *jobptr;
/* similarly to _complete, this is QMP-interface only. */
assert(job->id);
if (block_job_apply_verb(job, BLOCK_JOB_VERB_DISMISS, errp)) {
return;
}
block_job_do_dismiss(job);
*jobptr = NULL;
}
void block_job_user_pause(BlockJob *job, Error **errp)
{
if (block_job_apply_verb(job, BLOCK_JOB_VERB_PAUSE, errp)) {
return;
}
if (job->user_paused) {
error_setg(errp, "Job is already paused");
return;
}
job->user_paused = true;
block_job_pause(job);
}
@@ -734,51 +532,31 @@ bool block_job_user_paused(BlockJob *job)
return job->user_paused;
}
void block_job_user_resume(BlockJob *job, Error **errp)
void block_job_user_resume(BlockJob *job)
{
assert(job);
if (!job->user_paused || job->pause_count <= 0) {
error_setg(errp, "Can't resume a job that was not paused");
return;
if (job && job->user_paused && job->pause_count > 0) {
block_job_iostatus_reset(job);
job->user_paused = false;
block_job_resume(job);
}
if (block_job_apply_verb(job, BLOCK_JOB_VERB_RESUME, errp)) {
return;
}
block_job_iostatus_reset(job);
job->user_paused = false;
block_job_resume(job);
}
void block_job_cancel(BlockJob *job, bool force)
void block_job_cancel(BlockJob *job)
{
if (job->status == BLOCK_JOB_STATUS_CONCLUDED) {
block_job_do_dismiss(job);
return;
}
block_job_cancel_async(job, force);
if (!block_job_started(job)) {
block_job_completed(job, -ECANCELED);
} else if (job->deferred_to_main_loop) {
block_job_completed_txn_abort(job);
} else {
if (block_job_started(job)) {
block_job_cancel_async(job);
block_job_enter(job);
} else {
block_job_completed(job, -ECANCELED);
}
}
void block_job_user_cancel(BlockJob *job, bool force, Error **errp)
{
if (block_job_apply_verb(job, BLOCK_JOB_VERB_CANCEL, errp)) {
return;
}
block_job_cancel(job, force);
}
/* A wrapper around block_job_cancel() taking an Error ** parameter so it may be
* used with block_job_finish_sync() without the need for (rather nasty)
* function pointer casts there. */
static void block_job_cancel_err(BlockJob *job, Error **errp)
{
block_job_cancel(job, false);
block_job_cancel(job);
}
int block_job_cancel_sync(BlockJob *job)
@@ -822,9 +600,6 @@ BlockJobInfo *block_job_query(BlockJob *job, Error **errp)
info->speed = job->speed;
info->io_status = job->iostatus;
info->ready = job->ready;
info->status = job->status;
info->auto_finalize = job->auto_finalize;
info->auto_dismiss = job->auto_dismiss;
return info;
}
@@ -866,24 +641,13 @@ static void block_job_event_completed(BlockJob *job, const char *msg)
&error_abort);
}
static int block_job_event_pending(BlockJob *job)
{
block_job_state_transition(job, BLOCK_JOB_STATUS_PENDING);
if (!job->auto_finalize && !block_job_is_internal(job)) {
qapi_event_send_block_job_pending(job->driver->job_type,
job->id,
&error_abort);
}
return 0;
}
/*
* API for block job drivers and the block layer. These functions are
* declared in blockjob_int.h.
*/
void *block_job_create(const char *job_id, const BlockJobDriver *driver,
BlockJobTxn *txn, BlockDriverState *bs, uint64_t perm,
BlockDriverState *bs, uint64_t perm,
uint64_t shared_perm, int64_t speed, int flags,
BlockCompletionFunc *cb, void *opaque, Error **errp)
{
@@ -938,9 +702,6 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
job->paused = true;
job->pause_count = 1;
job->refcnt = 1;
job->auto_finalize = !(flags & BLOCK_JOB_MANUAL_FINALIZE);
job->auto_dismiss = !(flags & BLOCK_JOB_MANUAL_DISMISS);
block_job_state_transition(job, BLOCK_JOB_STATUS_CREATED);
aio_timer_init(qemu_get_aio_context(), &job->sleep_timer,
QEMU_CLOCK_REALTIME, SCALE_NS,
block_job_sleep_timer_cb, job);
@@ -963,22 +724,11 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
block_job_set_speed(job, speed, &local_err);
if (local_err) {
block_job_early_fail(job);
block_job_unref(job);
error_propagate(errp, local_err);
return NULL;
}
}
/* Single jobs are modeled as single-job transactions for sake of
* consolidating the job management logic */
if (!txn) {
txn = block_job_txn_new();
block_job_txn_add_job(txn, job);
block_job_txn_unref(txn);
} else {
block_job_txn_add_job(txn, job);
}
return job;
}
@@ -997,19 +747,18 @@ void block_job_pause_all(void)
void block_job_early_fail(BlockJob *job)
{
assert(job->status == BLOCK_JOB_STATUS_CREATED);
block_job_decommission(job);
block_job_unref(job);
}
void block_job_completed(BlockJob *job, int ret)
{
assert(job && job->txn && !job->completed);
assert(blk_bs(job->blk)->job == job);
assert(!job->completed);
job->completed = true;
job->ret = ret;
block_job_update_rc(job);
trace_block_job_completed(job, ret, job->ret);
if (job->ret) {
if (!job->txn) {
block_job_completed_single(job);
} else if (ret < 0 || block_job_is_cancelled(job)) {
block_job_completed_txn_abort(job);
} else {
block_job_completed_txn_success(job);
@@ -1057,14 +806,9 @@ void coroutine_fn block_job_pause_point(BlockJob *job)
}
if (block_job_should_pause(job) && !block_job_is_cancelled(job)) {
BlockJobStatus status = job->status;
block_job_state_transition(job, status == BLOCK_JOB_STATUS_READY ? \
BLOCK_JOB_STATUS_STANDBY : \
BLOCK_JOB_STATUS_PAUSED);
job->paused = true;
block_job_do_yield(job, -1);
job->paused = false;
block_job_state_transition(job, status);
}
if (job->driver->resume) {
@@ -1170,7 +914,6 @@ void block_job_iostatus_reset(BlockJob *job)
void block_job_event_ready(BlockJob *job)
{
block_job_state_transition(job, BLOCK_JOB_STATUS_READY);
job->ready = true;
if (block_job_is_internal(job)) {
@@ -1214,9 +957,8 @@ BlockErrorAction block_job_error_action(BlockJob *job, BlockdevOnError on_err,
action, &error_abort);
}
if (action == BLOCK_ERROR_ACTION_STOP) {
block_job_pause(job);
/* make the pause user visible, which will be resumed from QMP. */
job->user_paused = true;
block_job_user_pause(job);
block_job_iostatus_set_err(job, error);
}
return action;

View File

@@ -649,7 +649,7 @@ void cpu_loop(CPUSPARCState *env)
static void usage(void)
{
printf("qemu-" TARGET_NAME " version " QEMU_FULL_VERSION
printf("qemu-" TARGET_NAME " version " QEMU_VERSION QEMU_PKGVERSION
"\n" QEMU_COPYRIGHT "\n"
"usage: qemu-" TARGET_NAME " [options] program [arguments...]\n"
"BSD CPU emulator (compiled for %s emulation)\n"
@@ -723,7 +723,6 @@ int main(int argc, char **argv)
{
const char *filename;
const char *cpu_model;
const char *cpu_type;
const char *log_file = NULL;
const char *log_mask = NULL;
struct target_pt_regs regs1, *regs = &regs1;
@@ -901,8 +900,7 @@ int main(int argc, char **argv)
tcg_exec_init(0);
/* NOTE: we need to init the CPU at this stage to get
qemu_host_page_size */
cpu_type = parse_cpu_model(cpu_model);
cpu = cpu_create(cpu_type);
cpu = cpu_init(cpu_model);
env = cpu->env_ptr;
#if defined(TARGET_SPARC) || defined(TARGET_PPC)
cpu_reset(cpu);

View File

@@ -27,7 +27,6 @@
#include "qemu/option.h"
#include "chardev/char.h"
#include "sysemu/block-backend.h"
#include "sysemu/sysemu.h"
#include "chardev/char-mux.h"
/* MUX driver for serial I/O splitting */
@@ -231,12 +230,14 @@ static void mux_chr_read(void *opaque, const uint8_t *buf, int size)
}
}
bool muxes_realized;
void mux_chr_send_all_event(Chardev *chr, int event)
{
MuxChardev *d = MUX_CHARDEV(chr);
int i;
if (!machine_init_done) {
if (!muxes_realized) {
return;
}
@@ -326,7 +327,7 @@ static void qemu_chr_open_mux(Chardev *chr,
/* only default to opened state if we've realized the initial
* set of muxes
*/
*be_opened = machine_init_done;
*be_opened = muxes_realized;
qemu_chr_fe_init(&d->chr, drv, errp);
}
@@ -346,31 +347,6 @@ static void qemu_chr_parse_mux(QemuOpts *opts, ChardevBackend *backend,
mux->chardev = g_strdup(chardev);
}
/**
* Called after processing of default and command-line-specified
* chardevs to deliver CHR_EVENT_OPENED events to any FEs attached
* to a mux chardev. This is done here to ensure that
* output/prompts/banners are only displayed for the FE that has
* focus when initial command-line processing/machine init is
* completed.
*
* After this point, any new FE attached to any new or existing
* mux will receive CHR_EVENT_OPENED notifications for the BE
* immediately.
*/
static int open_muxes(Chardev *chr)
{
/* send OPENED to all already-attached FEs */
mux_chr_send_all_event(chr, CHR_EVENT_OPENED);
/*
* mark mux as OPENED so any new FEs will immediately receive
* OPENED event
*/
qemu_chr_be_event(chr, CHR_EVENT_OPENED);
return 0;
}
static void char_mux_class_init(ObjectClass *oc, void *data)
{
ChardevClass *cc = CHARDEV_CLASS(oc);
@@ -381,7 +357,6 @@ static void char_mux_class_init(ObjectClass *oc, void *data)
cc->chr_accept_input = mux_chr_accept_input;
cc->chr_add_watch = mux_chr_add_watch;
cc->chr_be_event = mux_chr_be_event;
cc->chr_machine_done = open_muxes;
}
static const TypeInfo char_mux_type_info = {

View File

@@ -32,7 +32,6 @@
#include "qapi/error.h"
#include "qapi/clone-visitor.h"
#include "qapi/qapi-visit-sockets.h"
#include "sysemu/sysemu.h"
#include "chardev/char-io.h"
@@ -41,11 +40,6 @@
#define TCP_MAX_FDS 16
typedef struct {
char buf[21];
size_t buflen;
} TCPChardevTelnetInit;
typedef struct {
Chardev parent;
QIOChannel *ioc; /* Client I/O channel */
@@ -66,8 +60,6 @@ typedef struct {
bool is_listen;
bool is_telnet;
bool is_tn3270;
GSource *telnet_source;
TCPChardevTelnetInit *telnet_init;
GSource *reconnect_timer;
int64_t reconnect_time;
@@ -78,7 +70,6 @@ typedef struct {
OBJECT_CHECK(SocketChardev, (obj), TYPE_CHARDEV_SOCKET)
static gboolean socket_reconnect_timeout(gpointer opaque);
static void tcp_chr_telnet_init(Chardev *chr);
static void tcp_chr_reconn_timer_cancel(SocketChardev *s)
{
@@ -432,8 +423,8 @@ static void tcp_chr_disconnect(Chardev *chr)
tcp_chr_free_connection(chr);
if (s->listener) {
qio_net_listener_set_client_func_full(s->listener, tcp_chr_accept,
chr, NULL, chr->gcontext);
qio_net_listener_set_client_func(s->listener, tcp_chr_accept,
chr, NULL);
}
update_disconnected_filename(s);
if (emit_close) {
@@ -459,7 +450,7 @@ static gboolean tcp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
len = s->max_size;
}
size = tcp_chr_recv(chr, (void *)buf, len);
if (size == 0 || (size == -1 && errno != EAGAIN)) {
if (size == 0 || size == -1) {
/* connection closed */
tcp_chr_disconnect(chr);
} else if (size > 0) {
@@ -565,33 +556,10 @@ static void tcp_chr_connect(void *opaque)
qemu_chr_be_event(chr, CHR_EVENT_OPENED);
}
static void tcp_chr_telnet_destroy(SocketChardev *s)
{
if (s->telnet_source) {
g_source_destroy(s->telnet_source);
g_source_unref(s->telnet_source);
s->telnet_source = NULL;
}
}
static void tcp_chr_update_read_handler(Chardev *chr)
{
SocketChardev *s = SOCKET_CHARDEV(chr);
if (s->listener) {
/*
* It's possible that chardev context is changed in
* qemu_chr_be_update_read_handlers(). Reset it for QIO net
* listener if there is.
*/
qio_net_listener_set_client_func_full(s->listener, tcp_chr_accept,
chr, NULL, chr->gcontext);
}
if (s->telnet_source) {
tcp_chr_telnet_init(CHARDEV(s));
}
if (!s->connected) {
return;
}
@@ -605,30 +573,32 @@ static void tcp_chr_update_read_handler(Chardev *chr)
}
}
typedef struct {
Chardev *chr;
char buf[21];
size_t buflen;
} TCPChardevTelnetInit;
static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc,
GIOCondition cond G_GNUC_UNUSED,
gpointer user_data)
{
SocketChardev *s = user_data;
Chardev *chr = CHARDEV(s);
TCPChardevTelnetInit *init = s->telnet_init;
TCPChardevTelnetInit *init = user_data;
ssize_t ret;
assert(init);
ret = qio_channel_write(ioc, init->buf, init->buflen, NULL);
if (ret < 0) {
if (ret == QIO_CHANNEL_ERR_BLOCK) {
ret = 0;
} else {
tcp_chr_disconnect(chr);
tcp_chr_disconnect(init->chr);
goto end;
}
}
init->buflen -= ret;
if (init->buflen == 0) {
tcp_chr_connect(chr);
tcp_chr_connect(init->chr);
goto end;
}
@@ -637,30 +607,16 @@ static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc,
return G_SOURCE_CONTINUE;
end:
g_free(s->telnet_init);
s->telnet_init = NULL;
g_source_unref(s->telnet_source);
s->telnet_source = NULL;
g_free(init);
return G_SOURCE_REMOVE;
}
static void tcp_chr_telnet_init(Chardev *chr)
{
SocketChardev *s = SOCKET_CHARDEV(chr);
TCPChardevTelnetInit *init;
TCPChardevTelnetInit *init = g_new0(TCPChardevTelnetInit, 1);
size_t n = 0;
/* Destroy existing task */
tcp_chr_telnet_destroy(s);
if (s->telnet_init) {
/* We are possibly during a handshake already */
goto cont;
}
s->telnet_init = g_new0(TCPChardevTelnetInit, 1);
init = s->telnet_init;
#define IACSET(x, a, b, c) \
do { \
x[n++] = a; \
@@ -668,6 +624,7 @@ static void tcp_chr_telnet_init(Chardev *chr)
x[n++] = c; \
} while (0)
init->chr = chr;
if (!s->is_tn3270) {
init->buflen = 12;
/* Prep the telnet negotion to put telnet in binary,
@@ -690,11 +647,10 @@ static void tcp_chr_telnet_init(Chardev *chr)
#undef IACSET
cont:
s->telnet_source = qio_channel_add_watch_source(s->ioc, G_IO_OUT,
tcp_chr_telnet_init_io,
s, NULL,
chr->gcontext);
qio_channel_add_watch(
s->ioc, G_IO_OUT,
tcp_chr_telnet_init_io,
init, NULL);
}
@@ -707,7 +663,8 @@ static void tcp_chr_tls_handshake(QIOTask *task,
if (qio_task_propagate_error(task, NULL)) {
tcp_chr_disconnect(chr);
} else {
if (s->do_telnetopt) {
/* tn3270 does not support TLS yet */
if (s->do_telnetopt && !s->is_tn3270) {
tcp_chr_telnet_init(chr);
} else {
tcp_chr_connect(chr);
@@ -723,11 +680,6 @@ static void tcp_chr_tls_init(Chardev *chr)
Error *err = NULL;
gchar *name;
if (!machine_init_done) {
/* This will be postponed to machine_done notifier */
return;
}
if (s->is_listen) {
tioc = qio_channel_tls_new_server(
s->ioc, s->tls_creds,
@@ -756,7 +708,7 @@ static void tcp_chr_tls_init(Chardev *chr)
tcp_chr_tls_handshake,
chr,
NULL,
chr->gcontext);
NULL);
}
@@ -792,8 +744,7 @@ static int tcp_chr_new_client(Chardev *chr, QIOChannelSocket *sioc)
qio_channel_set_delay(s->ioc, false);
}
if (s->listener) {
qio_net_listener_set_client_func_full(s->listener, NULL, NULL,
NULL, chr->gcontext);
qio_net_listener_set_client_func(s->listener, NULL, NULL, NULL);
}
if (s->tls_creds) {
@@ -873,11 +824,8 @@ static void char_socket_finalize(Object *obj)
tcp_chr_free_connection(chr);
tcp_chr_reconn_timer_cancel(s);
qapi_free_SocketAddress(s->addr);
tcp_chr_telnet_destroy(s);
g_free(s->telnet_init);
if (s->listener) {
qio_net_listener_set_client_func_full(s->listener, NULL, NULL,
NULL, chr->gcontext);
qio_net_listener_set_client_func(s->listener, NULL, NULL, NULL);
object_unref(OBJECT(s->listener));
}
if (s->tls_creds) {
@@ -907,22 +855,11 @@ cleanup:
object_unref(OBJECT(sioc));
}
static void tcp_chr_connect_async(Chardev *chr)
{
SocketChardev *s = SOCKET_CHARDEV(chr);
QIOChannelSocket *sioc;
sioc = qio_channel_socket_new();
tcp_chr_set_client_ioc_name(chr, sioc);
qio_channel_socket_connect_async(sioc, s->addr,
qemu_chr_socket_connected,
chr, NULL, chr->gcontext);
}
static gboolean socket_reconnect_timeout(gpointer opaque)
{
Chardev *chr = CHARDEV(opaque);
SocketChardev *s = SOCKET_CHARDEV(opaque);
QIOChannelSocket *sioc;
g_source_unref(s->reconnect_timer);
s->reconnect_timer = NULL;
@@ -931,7 +868,11 @@ static gboolean socket_reconnect_timeout(gpointer opaque)
return false;
}
tcp_chr_connect_async(chr);
sioc = qio_channel_socket_new();
tcp_chr_set_client_ioc_name(chr, sioc);
qio_channel_socket_connect_async(sioc, s->addr,
qemu_chr_socket_connected,
chr, NULL, NULL);
return false;
}
@@ -1010,8 +951,13 @@ static void qmp_chardev_open_socket(Chardev *chr,
s->reconnect_time = reconnect;
}
/* If reconnect_time is set, will do that in chr_machine_done. */
if (!s->reconnect_time) {
if (s->reconnect_time) {
sioc = qio_channel_socket_new();
tcp_chr_set_client_ioc_name(chr, sioc);
qio_channel_socket_connect_async(sioc, s->addr,
qemu_chr_socket_connected,
chr, NULL, NULL);
} else {
if (s->is_listen) {
char *name;
s->listener = qio_net_listener_new();
@@ -1035,10 +981,8 @@ static void qmp_chardev_open_socket(Chardev *chr,
return;
}
if (!s->ioc) {
qio_net_listener_set_client_func_full(s->listener,
tcp_chr_accept,
chr, NULL,
chr->gcontext);
qio_net_listener_set_client_func(s->listener, tcp_chr_accept,
chr, NULL);
}
} else if (qemu_chr_wait_connected(chr, errp) < 0) {
goto error;
@@ -1065,36 +1009,25 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
const char *path = qemu_opt_get(opts, "path");
const char *host = qemu_opt_get(opts, "host");
const char *port = qemu_opt_get(opts, "port");
const char *fd = qemu_opt_get(opts, "fd");
const char *tls_creds = qemu_opt_get(opts, "tls-creds");
SocketAddressLegacy *addr;
ChardevSocket *sock;
if ((!!path + !!fd + !!host) != 1) {
error_setg(errp,
"Exactly one of 'path', 'fd' or 'host' required");
return;
}
backend->type = CHARDEV_BACKEND_KIND_SOCKET;
if (path) {
if (tls_creds) {
error_setg(errp, "TLS can only be used over TCP socket");
if (!path) {
if (!host) {
error_setg(errp, "chardev: socket: no host given");
return;
}
} else if (host) {
if (!port) {
error_setg(errp, "chardev: socket: no port given");
return;
}
} else if (fd) {
/* We don't know what host to validate against when in client mode */
if (tls_creds && !is_listen) {
error_setg(errp, "TLS can not be used with pre-opened client FD");
} else {
if (tls_creds) {
error_setg(errp, "TLS can only be used over TCP socket");
return;
}
} else {
g_assert_not_reached();
}
sock = backend->u.socket.data = g_new0(ChardevSocket, 1);
@@ -1120,7 +1053,7 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
addr->type = SOCKET_ADDRESS_LEGACY_KIND_UNIX;
q_unix = addr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
q_unix->path = g_strdup(path);
} else if (host) {
} else {
addr->type = SOCKET_ADDRESS_LEGACY_KIND_INET;
addr->u.inet.data = g_new(InetSocketAddress, 1);
*addr->u.inet.data = (InetSocketAddress) {
@@ -1133,12 +1066,6 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
.has_ipv6 = qemu_opt_get(opts, "ipv6"),
.ipv6 = qemu_opt_get_bool(opts, "ipv6", 0),
};
} else if (fd) {
addr->type = SOCKET_ADDRESS_LEGACY_KIND_FD;
addr->u.fd.data = g_new(String, 1);
addr->u.fd.data->str = g_strdup(fd);
} else {
g_assert_not_reached();
}
sock->addr = addr;
}
@@ -1160,21 +1087,6 @@ char_socket_get_connected(Object *obj, Error **errp)
return s->connected;
}
static int tcp_chr_machine_done_hook(Chardev *chr)
{
SocketChardev *s = SOCKET_CHARDEV(chr);
if (s->reconnect_time) {
tcp_chr_connect_async(chr);
}
if (s->ioc && s->tls_creds) {
tcp_chr_tls_init(chr);
}
return 0;
}
static void char_socket_class_init(ObjectClass *oc, void *data)
{
ChardevClass *cc = CHARDEV_CLASS(oc);
@@ -1190,7 +1102,6 @@ static void char_socket_class_init(ObjectClass *oc, void *data)
cc->chr_add_client = tcp_chr_add_client;
cc->chr_add_watch = tcp_chr_add_watch;
cc->chr_update_read_handler = tcp_chr_update_read_handler;
cc->chr_machine_done = tcp_chr_machine_done_hook;
object_class_property_add(oc, "addr", "SocketAddress",
char_socket_get_addr, NULL,

View File

@@ -281,31 +281,40 @@ static const TypeInfo char_type_info = {
.class_init = char_class_init,
};
static int chardev_machine_done_notify_one(Object *child, void *opaque)
/**
* Called after processing of default and command-line-specified
* chardevs to deliver CHR_EVENT_OPENED events to any FEs attached
* to a mux chardev. This is done here to ensure that
* output/prompts/banners are only displayed for the FE that has
* focus when initial command-line processing/machine init is
* completed.
*
* After this point, any new FE attached to any new or existing
* mux will receive CHR_EVENT_OPENED notifications for the BE
* immediately.
*/
static int open_muxes(Object *child, void *opaque)
{
Chardev *chr = (Chardev *)child;
ChardevClass *class = CHARDEV_GET_CLASS(chr);
if (class->chr_machine_done) {
return class->chr_machine_done(chr);
if (CHARDEV_IS_MUX(child)) {
/* send OPENED to all already-attached FEs */
mux_chr_send_all_event(CHARDEV(child), CHR_EVENT_OPENED);
/* mark mux as OPENED so any new FEs will immediately receive
* OPENED event
*/
qemu_chr_be_event(CHARDEV(child), CHR_EVENT_OPENED);
}
return 0;
}
static void chardev_machine_done_hook(Notifier *notifier, void *unused)
static void muxes_realize_done(Notifier *notifier, void *unused)
{
int ret = object_child_foreach(get_chardevs_root(),
chardev_machine_done_notify_one, NULL);
if (ret) {
error_report("Failed to call chardev machine_done hooks");
exit(1);
}
muxes_realized = true;
object_child_foreach(get_chardevs_root(), open_muxes, NULL);
}
static Notifier chardev_machine_done_notify = {
.notify = chardev_machine_done_hook,
static Notifier muxes_realize_notify = {
.notify = muxes_realize_done,
};
static bool qemu_chr_is_busy(Chardev *s)
@@ -798,9 +807,6 @@ QemuOptsList qemu_chardev_opts = {
},{
.name = "port",
.type = QEMU_OPT_STRING,
},{
.name = "fd",
.type = QEMU_OPT_STRING,
},{
.name = "localaddr",
.type = QEMU_OPT_STRING,
@@ -1112,7 +1118,7 @@ static void register_types(void)
* as part of realize functions like serial_isa_realizefn when -nographic
* is specified
*/
qemu_add_machine_init_done_notifier(&chardev_machine_done_notify);
qemu_add_machine_init_done_notifier(&muxes_realize_notify);
}
type_init(register_types);

45
configure vendored
View File

@@ -342,7 +342,7 @@ attr=""
libattr=""
xfs=""
tcg="yes"
membarrier=""
vhost_net="no"
vhost_crypto="no"
vhost_scsi="no"
@@ -1161,13 +1161,9 @@ for opt do
;;
--enable-attr) attr="yes"
;;
--disable-membarrier) membarrier="no"
;;
--enable-membarrier) membarrier="yes"
;;
--disable-blobs) blobs="no"
;;
--with-pkgversion=*) pkgversion="$optarg"
--with-pkgversion=*) pkgversion=" ($optarg)"
;;
--with-coroutine=*) coroutine="$optarg"
;;
@@ -1581,7 +1577,6 @@ disabled with --disable-FEATURE, default is enabled if available:
xen-pci-passthrough
brlapi BrlAPI (Braile)
curl curl connectivity
membarrier membarrier system call (for Linux 4.14+ or Windows)
fdt fdt device tree
bluez bluez stack connectivity
kvm KVM acceleration support
@@ -5143,37 +5138,6 @@ if compile_prog "" "" ; then
have_fsxattr=yes
fi
##########################################
# check for usable membarrier system call
if test "$membarrier" = "yes"; then
have_membarrier=no
if test "$mingw32" = "yes" ; then
have_membarrier=yes
elif test "$linux" = "yes" ; then
cat > $TMPC << EOF
#include <linux/membarrier.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <stdlib.h>
int main(void) {
syscall(__NR_membarrier, MEMBARRIER_CMD_QUERY, 0);
syscall(__NR_membarrier, MEMBARRIER_CMD_SHARED, 0);
exit(0);
}
EOF
if compile_prog "" "" ; then
have_membarrier=yes
fi
fi
if test "$have_membarrier" = "no"; then
feature_not_found "membarrier" "membarrier system call not available"
fi
else
# Do not enable it by default even for Mingw32, because it doesn't
# work on Wine.
membarrier=no
fi
##########################################
# check if rtnetlink.h exists and is useful
have_rtnetlink=no
@@ -5800,7 +5764,6 @@ fi
echo "malloc trim support $malloc_trim"
echo "RDMA support $rdma"
echo "fdt support $fdt"
echo "membarrier $membarrier"
echo "preadv support $preadv"
echo "fdatasync $fdatasync"
echo "madvise $madvise"
@@ -6288,9 +6251,6 @@ fi
if test "$fdt" = "yes" ; then
echo "CONFIG_FDT=y" >> $config_host_mak
fi
if test "$membarrier" = "yes" ; then
echo "CONFIG_MEMBARRIER=y" >> $config_host_mak
fi
if test "$signalfd" = "yes" ; then
echo "CONFIG_SIGNALFD=y" >> $config_host_mak
fi
@@ -6880,7 +6840,6 @@ case "$target_name" in
;;
xtensa|xtensaeb)
TARGET_ARCH=xtensa
mttcg="yes"
;;
*)
error_exit "Unsupported target CPU"

View File

@@ -26,20 +26,9 @@
#include <sys/socket.h>
#include <sys/eventfd.h>
#include <sys/mman.h>
#include "qemu/compiler.h"
#if defined(__linux__)
#include <sys/syscall.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/vhost.h>
#ifdef __NR_userfaultfd
#include <linux/userfaultfd.h>
#endif
#endif
#include "qemu/compiler.h"
#include "qemu/atomic.h"
#include "libvhost-user.h"
@@ -97,9 +86,6 @@ vu_request_to_string(unsigned int req)
REQ(VHOST_USER_SET_VRING_ENDIAN),
REQ(VHOST_USER_GET_CONFIG),
REQ(VHOST_USER_SET_CONFIG),
REQ(VHOST_USER_POSTCOPY_ADVISE),
REQ(VHOST_USER_POSTCOPY_LISTEN),
REQ(VHOST_USER_POSTCOPY_END),
REQ(VHOST_USER_MAX),
};
#undef REQ
@@ -185,35 +171,6 @@ vmsg_close_fds(VhostUserMsg *vmsg)
}
}
/* A test to see if we have userfault available */
static bool
have_userfault(void)
{
#if defined(__linux__) && defined(__NR_userfaultfd) &&\
defined(UFFD_FEATURE_MISSING_SHMEM) &&\
defined(UFFD_FEATURE_MISSING_HUGETLBFS)
/* Now test the kernel we're running on really has the features */
int ufd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK);
struct uffdio_api api_struct;
if (ufd < 0) {
return false;
}
api_struct.api = UFFD_API;
api_struct.features = UFFD_FEATURE_MISSING_SHMEM |
UFFD_FEATURE_MISSING_HUGETLBFS;
if (ioctl(ufd, UFFDIO_API, &api_struct)) {
close(ufd);
return false;
}
close(ufd);
return true;
#else
return false;
#endif
}
static bool
vu_message_read(VuDev *dev, int conn_fd, VhostUserMsg *vmsg)
{
@@ -288,31 +245,6 @@ vu_message_write(VuDev *dev, int conn_fd, VhostUserMsg *vmsg)
{
int rc;
uint8_t *p = (uint8_t *)vmsg;
char control[CMSG_SPACE(VHOST_MEMORY_MAX_NREGIONS * sizeof(int))] = { };
struct iovec iov = {
.iov_base = (char *)vmsg,
.iov_len = VHOST_USER_HDR_SIZE,
};
struct msghdr msg = {
.msg_iov = &iov,
.msg_iovlen = 1,
.msg_control = control,
};
struct cmsghdr *cmsg;
memset(control, 0, sizeof(control));
assert(vmsg->fd_num <= VHOST_MEMORY_MAX_NREGIONS);
if (vmsg->fd_num > 0) {
size_t fdsize = vmsg->fd_num * sizeof(int);
msg.msg_controllen = CMSG_SPACE(fdsize);
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_len = CMSG_LEN(fdsize);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
memcpy(CMSG_DATA(cmsg), vmsg->fds, fdsize);
} else {
msg.msg_controllen = 0;
}
/* Set the version in the flags when sending the reply */
vmsg->flags &= ~VHOST_USER_VERSION_MASK;
@@ -320,7 +252,7 @@ vu_message_write(VuDev *dev, int conn_fd, VhostUserMsg *vmsg)
vmsg->flags |= VHOST_USER_REPLY_MASK;
do {
rc = sendmsg(conn_fd, &msg, 0);
rc = write(conn_fd, p, VHOST_USER_HDR_SIZE);
} while (rc < 0 && (errno == EINTR || errno == EAGAIN));
do {
@@ -413,7 +345,6 @@ vu_get_features_exec(VuDev *dev, VhostUserMsg *vmsg)
}
vmsg->size = sizeof(vmsg->payload.u64);
vmsg->fd_num = 0;
DPRINT("Sending back to guest u64: 0x%016"PRIx64"\n", vmsg->payload.u64);
@@ -478,148 +409,6 @@ vu_reset_device_exec(VuDev *dev, VhostUserMsg *vmsg)
return false;
}
static bool
vu_set_mem_table_exec_postcopy(VuDev *dev, VhostUserMsg *vmsg)
{
int i;
VhostUserMemory *memory = &vmsg->payload.memory;
dev->nregions = memory->nregions;
DPRINT("Nregions: %d\n", memory->nregions);
for (i = 0; i < dev->nregions; i++) {
void *mmap_addr;
VhostUserMemoryRegion *msg_region = &memory->regions[i];
VuDevRegion *dev_region = &dev->regions[i];
DPRINT("Region %d\n", i);
DPRINT(" guest_phys_addr: 0x%016"PRIx64"\n",
msg_region->guest_phys_addr);
DPRINT(" memory_size: 0x%016"PRIx64"\n",
msg_region->memory_size);
DPRINT(" userspace_addr 0x%016"PRIx64"\n",
msg_region->userspace_addr);
DPRINT(" mmap_offset 0x%016"PRIx64"\n",
msg_region->mmap_offset);
dev_region->gpa = msg_region->guest_phys_addr;
dev_region->size = msg_region->memory_size;
dev_region->qva = msg_region->userspace_addr;
dev_region->mmap_offset = msg_region->mmap_offset;
/* We don't use offset argument of mmap() since the
* mapped address has to be page aligned, and we use huge
* pages.
* In postcopy we're using PROT_NONE here to catch anyone
* accessing it before we userfault
*/
mmap_addr = mmap(0, dev_region->size + dev_region->mmap_offset,
PROT_NONE, MAP_SHARED,
vmsg->fds[i], 0);
if (mmap_addr == MAP_FAILED) {
vu_panic(dev, "region mmap error: %s", strerror(errno));
} else {
dev_region->mmap_addr = (uint64_t)(uintptr_t)mmap_addr;
DPRINT(" mmap_addr: 0x%016"PRIx64"\n",
dev_region->mmap_addr);
}
/* Return the address to QEMU so that it can translate the ufd
* fault addresses back.
*/
msg_region->userspace_addr = (uintptr_t)(mmap_addr +
dev_region->mmap_offset);
close(vmsg->fds[i]);
}
/* Send the message back to qemu with the addresses filled in */
vmsg->fd_num = 0;
if (!vu_message_write(dev, dev->sock, vmsg)) {
vu_panic(dev, "failed to respond to set-mem-table for postcopy");
return false;
}
/* Wait for QEMU to confirm that it's registered the handler for the
* faults.
*/
if (!vu_message_read(dev, dev->sock, vmsg) ||
vmsg->size != sizeof(vmsg->payload.u64) ||
vmsg->payload.u64 != 0) {
vu_panic(dev, "failed to receive valid ack for postcopy set-mem-table");
return false;
}
/* OK, now we can go and register the memory and generate faults */
for (i = 0; i < dev->nregions; i++) {
VuDevRegion *dev_region = &dev->regions[i];
int ret;
#ifdef UFFDIO_REGISTER
/* We should already have an open ufd. Mark each memory
* range as ufd.
* Discard any mapping we have here; note I can't use MADV_REMOVE
* or fallocate to make the hole since I don't want to lose
* data that's already arrived in the shared process.
* TODO: How to do hugepage
*/
ret = madvise((void *)dev_region->mmap_addr,
dev_region->size + dev_region->mmap_offset,
MADV_DONTNEED);
if (ret) {
fprintf(stderr,
"%s: Failed to madvise(DONTNEED) region %d: %s\n",
__func__, i, strerror(errno));
}
/* Turn off transparent hugepages so we dont get lose wakeups
* in neighbouring pages.
* TODO: Turn this backon later.
*/
ret = madvise((void *)dev_region->mmap_addr,
dev_region->size + dev_region->mmap_offset,
MADV_NOHUGEPAGE);
if (ret) {
/* Note: This can happen legally on kernels that are configured
* without madvise'able hugepages
*/
fprintf(stderr,
"%s: Failed to madvise(NOHUGEPAGE) region %d: %s\n",
__func__, i, strerror(errno));
}
struct uffdio_register reg_struct;
reg_struct.range.start = (uintptr_t)dev_region->mmap_addr;
reg_struct.range.len = dev_region->size + dev_region->mmap_offset;
reg_struct.mode = UFFDIO_REGISTER_MODE_MISSING;
if (ioctl(dev->postcopy_ufd, UFFDIO_REGISTER, &reg_struct)) {
vu_panic(dev, "%s: Failed to userfault region %d "
"@%p + size:%zx offset: %zx: (ufd=%d)%s\n",
__func__, i,
dev_region->mmap_addr,
dev_region->size, dev_region->mmap_offset,
dev->postcopy_ufd, strerror(errno));
return false;
}
if (!(reg_struct.ioctls & ((__u64)1 << _UFFDIO_COPY))) {
vu_panic(dev, "%s Region (%d) doesn't support COPY",
__func__, i);
return false;
}
DPRINT("%s: region %d: Registered userfault for %llx + %llx\n",
__func__, i, reg_struct.range.start, reg_struct.range.len);
/* Now it's registered we can let the client at it */
if (mprotect((void *)dev_region->mmap_addr,
dev_region->size + dev_region->mmap_offset,
PROT_READ | PROT_WRITE)) {
vu_panic(dev, "failed to mprotect region %d for postcopy (%s)",
i, strerror(errno));
return false;
}
/* TODO: Stash 'zero' support flags somewhere */
#endif
}
return false;
}
static bool
vu_set_mem_table_exec(VuDev *dev, VhostUserMsg *vmsg)
{
@@ -636,10 +425,6 @@ vu_set_mem_table_exec(VuDev *dev, VhostUserMsg *vmsg)
}
dev->nregions = memory->nregions;
if (dev->postcopy_listening) {
return vu_set_mem_table_exec_postcopy(dev, vmsg);
}
DPRINT("Nregions: %d\n", memory->nregions);
for (i = 0; i < dev->nregions; i++) {
void *mmap_addr;
@@ -715,7 +500,6 @@ vu_set_log_base_exec(VuDev *dev, VhostUserMsg *vmsg)
dev->log_size = log_mmap_size;
vmsg->size = sizeof(vmsg->payload.u64);
vmsg->fd_num = 0;
return true;
}
@@ -968,17 +752,12 @@ vu_get_protocol_features_exec(VuDev *dev, VhostUserMsg *vmsg)
uint64_t features = 1ULL << VHOST_USER_PROTOCOL_F_LOG_SHMFD |
1ULL << VHOST_USER_PROTOCOL_F_SLAVE_REQ;
if (have_userfault()) {
features |= 1ULL << VHOST_USER_PROTOCOL_F_PAGEFAULT;
}
if (dev->iface->get_protocol_features) {
features |= dev->iface->get_protocol_features(dev);
}
vmsg->payload.u64 = features;
vmsg->size = sizeof(vmsg->payload.u64);
vmsg->fd_num = 0;
return true;
}
@@ -1077,77 +856,6 @@ vu_set_config(VuDev *dev, VhostUserMsg *vmsg)
return false;
}
static bool
vu_set_postcopy_advise(VuDev *dev, VhostUserMsg *vmsg)
{
dev->postcopy_ufd = -1;
#ifdef UFFDIO_API
struct uffdio_api api_struct;
dev->postcopy_ufd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK);
vmsg->size = 0;
#endif
if (dev->postcopy_ufd == -1) {
vu_panic(dev, "Userfaultfd not available: %s", strerror(errno));
goto out;
}
#ifdef UFFDIO_API
api_struct.api = UFFD_API;
api_struct.features = 0;
if (ioctl(dev->postcopy_ufd, UFFDIO_API, &api_struct)) {
vu_panic(dev, "Failed UFFDIO_API: %s", strerror(errno));
close(dev->postcopy_ufd);
dev->postcopy_ufd = -1;
goto out;
}
/* TODO: Stash feature flags somewhere */
#endif
out:
/* Return a ufd to the QEMU */
vmsg->fd_num = 1;
vmsg->fds[0] = dev->postcopy_ufd;
return true; /* = send a reply */
}
static bool
vu_set_postcopy_listen(VuDev *dev, VhostUserMsg *vmsg)
{
vmsg->payload.u64 = -1;
vmsg->size = sizeof(vmsg->payload.u64);
if (dev->nregions) {
vu_panic(dev, "Regions already registered at postcopy-listen");
return true;
}
dev->postcopy_listening = true;
vmsg->flags = VHOST_USER_VERSION | VHOST_USER_REPLY_MASK;
vmsg->payload.u64 = 0; /* Success */
return true;
}
static bool
vu_set_postcopy_end(VuDev *dev, VhostUserMsg *vmsg)
{
DPRINT("%s: Entry\n", __func__);
dev->postcopy_listening = false;
if (dev->postcopy_ufd > 0) {
close(dev->postcopy_ufd);
dev->postcopy_ufd = -1;
DPRINT("%s: Done close\n", __func__);
}
vmsg->fd_num = 0;
vmsg->payload.u64 = 0;
vmsg->size = sizeof(vmsg->payload.u64);
vmsg->flags = VHOST_USER_VERSION | VHOST_USER_REPLY_MASK;
DPRINT("%s: exit\n", __func__);
return true;
}
static bool
vu_process_message(VuDev *dev, VhostUserMsg *vmsg)
{
@@ -1219,12 +927,6 @@ vu_process_message(VuDev *dev, VhostUserMsg *vmsg)
return vu_set_config(dev, vmsg);
case VHOST_USER_NONE:
break;
case VHOST_USER_POSTCOPY_ADVISE:
return vu_set_postcopy_advise(dev, vmsg);
case VHOST_USER_POSTCOPY_LISTEN:
return vu_set_postcopy_listen(dev, vmsg);
case VHOST_USER_POSTCOPY_END:
return vu_set_postcopy_end(dev, vmsg);
default:
vmsg_close_fds(vmsg);
vu_panic(dev, "Unhandled request: %d", vmsg->request);

View File

@@ -48,8 +48,6 @@ enum VhostUserProtocolFeature {
VHOST_USER_PROTOCOL_F_NET_MTU = 4,
VHOST_USER_PROTOCOL_F_SLAVE_REQ = 5,
VHOST_USER_PROTOCOL_F_CROSS_ENDIAN = 6,
VHOST_USER_PROTOCOL_F_CRYPTO_SESSION = 7,
VHOST_USER_PROTOCOL_F_PAGEFAULT = 8,
VHOST_USER_PROTOCOL_F_MAX
};
@@ -83,11 +81,6 @@ typedef enum VhostUserRequest {
VHOST_USER_SET_VRING_ENDIAN = 23,
VHOST_USER_GET_CONFIG = 24,
VHOST_USER_SET_CONFIG = 25,
VHOST_USER_CREATE_CRYPTO_SESSION = 26,
VHOST_USER_CLOSE_CRYPTO_SESSION = 27,
VHOST_USER_POSTCOPY_ADVISE = 28,
VHOST_USER_POSTCOPY_LISTEN = 29,
VHOST_USER_POSTCOPY_END = 30,
VHOST_USER_MAX
} VhostUserRequest;
@@ -284,10 +277,6 @@ struct VuDev {
* re-initialize */
vu_panic_cb panic;
const VuDevIface *iface;
/* Postcopy data */
int postcopy_ufd;
bool postcopy_listening;
};
typedef struct VuVirtqElement {

24
cpus.c
View File

@@ -1317,8 +1317,6 @@ static void prepare_icount_for_run(CPUState *cpu)
insns_left = MIN(0xffff, cpu->icount_budget);
cpu->icount_decr.u16.low = insns_left;
cpu->icount_extra = cpu->icount_budget - insns_left;
replay_mutex_lock();
}
}
@@ -1334,8 +1332,6 @@ static void process_icount_data(CPUState *cpu)
cpu->icount_budget = 0;
replay_account_executed_instructions();
replay_mutex_unlock();
}
}
@@ -1350,9 +1346,11 @@ static int tcg_cpu_exec(CPUState *cpu)
#ifdef CONFIG_PROFILER
ti = profile_getclock();
#endif
qemu_mutex_unlock_iothread();
cpu_exec_start(cpu);
ret = cpu_exec(cpu);
cpu_exec_end(cpu);
qemu_mutex_lock_iothread();
#ifdef CONFIG_PROFILER
tcg_time += profile_getclock() - ti;
#endif
@@ -1419,9 +1417,6 @@ static void *qemu_tcg_rr_cpu_thread_fn(void *arg)
cpu->exit_request = 1;
while (1) {
qemu_mutex_unlock_iothread();
replay_mutex_lock();
qemu_mutex_lock_iothread();
/* Account partial waits to QEMU_CLOCK_VIRTUAL. */
qemu_account_warp_timer();
@@ -1430,8 +1425,6 @@ static void *qemu_tcg_rr_cpu_thread_fn(void *arg)
*/
handle_icount_deadline();
replay_mutex_unlock();
if (!cpu) {
cpu = first_cpu;
}
@@ -1447,13 +1440,11 @@ static void *qemu_tcg_rr_cpu_thread_fn(void *arg)
if (cpu_can_run(cpu)) {
int r;
qemu_mutex_unlock_iothread();
prepare_icount_for_run(cpu);
r = tcg_cpu_exec(cpu);
process_icount_data(cpu);
qemu_mutex_lock_iothread();
if (r == EXCP_DEBUG) {
cpu_handle_guest_debug(cpu);
@@ -1643,9 +1634,7 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
while (1) {
if (cpu_can_run(cpu)) {
int r;
qemu_mutex_unlock_iothread();
r = tcg_cpu_exec(cpu);
qemu_mutex_lock_iothread();
switch (r) {
case EXCP_DEBUG:
cpu_handle_guest_debug(cpu);
@@ -1792,21 +1781,12 @@ void pause_all_vcpus(void)
}
}
/* We need to drop the replay_lock so any vCPU threads woken up
* can finish their replay tasks
*/
replay_mutex_unlock();
while (!all_vcpus_paused()) {
qemu_cond_wait(&qemu_pause_cond, &qemu_global_mutex);
CPU_FOREACH(cpu) {
qemu_cpu_kick(cpu);
}
}
qemu_mutex_unlock_iothread();
replay_mutex_lock();
qemu_mutex_lock_iothread();
}
void cpu_resume(CPUState *cpu)

View File

@@ -4,12 +4,7 @@ include pci.mak
include usb.mak
CONFIG_SERIAL=y
CONFIG_SERIAL_ISA=y
CONFIG_I82374=y
CONFIG_I8254=y
CONFIG_I8257=y
CONFIG_PARALLEL=y
CONFIG_PARALLEL_ISA=y
CONFIG_FDC=y
CONFIG_PCKBD=y
CONFIG_VGA_CIRRUS=y
CONFIG_IDE_CORE=y

View File

@@ -63,6 +63,3 @@ CONFIG_PXB=y
CONFIG_ACPI_VMGENID=y
CONFIG_FW_CFG_DMA=y
CONFIG_I2C=y
CONFIG_SEV=$(CONFIG_KVM)
CONFIG_VTD=y
CONFIG_AMD_IOMMU=y

View File

@@ -63,6 +63,3 @@ CONFIG_PXB=y
CONFIG_ACPI_VMGENID=y
CONFIG_FW_CFG_DMA=y
CONFIG_I2C=y
CONFIG_SEV=$(CONFIG_KVM)
CONFIG_VTD=y
CONFIG_AMD_IOMMU=y

View File

@@ -1 +0,0 @@
# Default configuration for xtensa-linux-user

View File

@@ -1 +0,0 @@
# Default configuration for xtensa-linux-user

View File

@@ -1,109 +0,0 @@
Secure Encrypted Virtualization (SEV) is a feature found on AMD processors.
SEV is an extension to the AMD-V architecture which supports running encrypted
virtual machine (VMs) under the control of KVM. Encrypted VMs have their pages
(code and data) secured such that only the guest itself has access to the
unencrypted version. Each encrypted VM is associated with a unique encryption
key; if its data is accessed to a different entity using a different key the
encrypted guests data will be incorrectly decrypted, leading to unintelligible
data.
The key management of this feature is handled by separate processor known as
AMD secure processor (AMD-SP) which is present in AMD SOCs. Firmware running
inside the AMD-SP provide commands to support common VM lifecycle. This
includes commands for launching, snapshotting, migrating and debugging the
encrypted guest. Those SEV command can be issued via KVM_MEMORY_ENCRYPT_OP
ioctls.
Launching
---------
Boot images (such as bios) must be encrypted before guest can be booted.
MEMORY_ENCRYPT_OP ioctl provides commands to encrypt the images :LAUNCH_START,
LAUNCH_UPDATE_DATA, LAUNCH_MEASURE and LAUNCH_FINISH. These four commands
together generate a fresh memory encryption key for the VM, encrypt the boot
images and provide a measurement than can be used as an attestation of the
successful launch.
LAUNCH_START is called first to create a cryptographic launch context within
the firmware. To create this context, guest owner must provides guest policy,
its public Diffie-Hellman key (PDH) and session parameters. These inputs
should be treated as binary blob and must be passed as-is to the SEV firmware.
The guest policy is passed as plaintext and hypervisor may able to read it
but should not modify it (any modification of the policy bits will result
in bad measurement). The guest policy is a 4-byte data structure containing
several flags that restricts what can be done on running SEV guest.
See KM Spec section 3 and 6.2 for more details.
The guest policy can be provided via the 'policy' property (see below)
# ${QEMU} \
sev-guest,id=sev0,policy=0x1...\
Guest owners provided DH certificate and session parameters will be used to
establish a cryptographic session with the guest owner to negotiate keys used
for the attestation.
The DH certificate and session blob can be provided via 'dh-cert-file' and
'session-file' property (see below
# ${QEMU} \
sev-guest,id=sev0,dh-cert-file=<file1>,session-file=<file2>
LAUNCH_UPDATE_DATA encrypts the memory region using the cryptographic context
created via LAUNCH_START command. If required, this command can be called
multiple times to encrypt different memory regions. The command also calculates
the measurement of the memory contents as it encrypts.
LAUNCH_MEASURE command can be used to retrieve the measurement of encrypted
memory. This measurement is a signature of the memory contents that can be
sent to the guest owner as an attestation that the memory was encrypted
correctly by the firmware. The guest owner may wait to provide the guest
confidential information until it can verify the attestation measurement.
Since the guest owner knows the initial contents of the guest at boot, the
attestation measurement can be verified by comparing it to what the guest owner
expects.
LAUNCH_FINISH command finalizes the guest launch and destroy's the cryptographic
context.
See SEV KM API Spec [1] 'Launching a guest' usage flow (Appendix A) for the
complete flow chart.
To launch a SEV guest
# ${QEMU} \
-machine ...,memory-encryption=sev0 \
-object sev-guest,id=sev0,cbitpos=47,reduced-phys-bits=1
Debugging
-----------
Since memory contents of SEV guest is encrypted hence hypervisor access to the
guest memory will get a cipher text. If guest policy allows debugging, then
hypervisor can use DEBUG_DECRYPT and DEBUG_ENCRYPT commands access the guest
memory region for debug purposes. This is not supported in QEMU yet.
Snapshot/Restore
-----------------
TODO
Live Migration
----------------
TODO
References
-----------------
AMD Memory Encryption whitepaper:
http://amd-dev.wpengine.netdna-cdn.com/wordpress/media/2013/12/AMD_Memory_Encryption_Whitepaper_v7-Public.pdf
Secure Encrypted Virutualization Key Management:
[1] http://support.amd.com/TechDocs/55766_SEV-KM API_Specification.pdf
KVM Forum slides:
http://www.linux-kvm.org/images/7/74/02x08A-Thomas_Lendacky-AMDs_Virtualizatoin_Memory_Encryption_Technology.pdf
AMD64 Architecture Programmer's Manual:
http://support.amd.com/TechDocs/24593.pdf
SME is section 7.10
SEV is section 15.34

View File

@@ -122,30 +122,20 @@ In general, if the algorithm you are writing includes both writes
and reads on the same side, it is generally simpler to use sequentially
consistent primitives.
When using this model, variables are accessed with:
- atomic_read() and atomic_set(); these prevent the compiler from
optimizing accesses out of existence and creating unsolicited
accesses, but do not otherwise impose any ordering on loads and
stores: both the compiler and the processor are free to reorder
them.
- atomic_load_acquire(), which guarantees the LOAD to appear to
happen, with respect to the other components of the system,
before all the LOAD or STORE operations specified afterwards.
Operations coming before atomic_load_acquire() can still be
reordered after it.
- atomic_store_release(), which guarantees the STORE to appear to
happen, with respect to the other components of the system,
after all the LOAD or STORE operations specified afterwards.
Operations coming after atomic_store_release() can still be
reordered after it.
Restrictions to the ordering of accesses can also be specified
When using this model, variables are accessed with atomic_read() and
atomic_set(), and restrictions to the ordering of accesses is enforced
using the memory barrier macros: smp_rmb(), smp_wmb(), smp_mb(),
smp_mb_acquire(), smp_mb_release(), smp_read_barrier_depends().
atomic_read() and atomic_set() prevents the compiler from using
optimizations that might otherwise optimize accesses out of existence
on the one hand, or that might create unsolicited accesses on the other.
In general this should not have any effect, because the same compiler
barriers are already implied by memory barriers. However, it is useful
to do so, because it tells readers which variables are shared with
other threads, and which are local to the current thread or protected
by other, more mundane means.
Memory barriers control the order of references to shared memory.
They come in six kinds:
@@ -242,7 +232,7 @@ make atomic_mb_set() the more expensive operation.
There are two common cases in which atomic_mb_read and atomic_mb_set
generate too many memory barriers, and thus it can be useful to manually
place barriers, or use atomic_load_acquire/atomic_store_release instead:
place barriers instead:
- when a data structure has one thread that is always a writer
and one thread that is always a reader, manual placement of
@@ -253,15 +243,18 @@ place barriers, or use atomic_load_acquire/atomic_store_release instead:
thread 1 thread 1
------------------------- ------------------------
(other writes)
atomic_mb_set(&a, x) atomic_store_release(&a, x)
atomic_mb_set(&b, y) atomic_store_release(&b, y)
smp_mb_release()
atomic_mb_set(&a, x) atomic_set(&a, x)
smp_wmb()
atomic_mb_set(&b, y) atomic_set(&b, y)
=>
thread 2 thread 2
------------------------- ------------------------
y = atomic_mb_read(&b) y = atomic_load_acquire(&b)
x = atomic_mb_read(&a) x = atomic_load_acquire(&a)
(other reads)
y = atomic_mb_read(&b) y = atomic_read(&b)
smp_rmb()
x = atomic_mb_read(&a) x = atomic_read(&a)
smp_mb_acquire()
Note that the barrier between the stores in thread 1, and between
the loads in thread 2, has been optimized here to a write or a
@@ -283,6 +276,7 @@ place barriers, or use atomic_load_acquire/atomic_store_release instead:
smp_mb_acquire();
Similarly, atomic_mb_set() can be transformed as follows:
smp_mb():
smp_mb_release();
for (i = 0; i < 10; i++) => for (i = 0; i < 10; i++)
@@ -290,8 +284,6 @@ place barriers, or use atomic_load_acquire/atomic_store_release instead:
smp_mb();
The other thread can still use atomic_mb_read()/atomic_mb_set().
The two tricks can be combined. In this case, splitting a loop in
two lets you hoist the barriers out of the loops _and_ eliminate the
expensive smp_mb():
@@ -304,6 +296,8 @@ expensive smp_mb():
atomic_set(&a[i], false);
smp_mb();
The other thread can still use atomic_mb_read()/atomic_mb_set()
Memory barrier pairing
----------------------
@@ -392,7 +386,10 @@ and memory barriers, and the equivalents in QEMU:
note that smp_store_mb() is a little weaker than atomic_mb_set().
atomic_mb_read() compiles to the same instructions as Linux's
smp_load_acquire(), but this should be treated as an implementation
detail.
detail. QEMU does have atomic_load_acquire() and atomic_store_release()
macros, but for now they are only used within atomic.h. This may
change in the future.
SOURCES
=======

View File

@@ -577,44 +577,3 @@ Postcopy now works with hugetlbfs backed memory:
hugepages works well, however 1GB hugepages are likely to be problematic
since it takes ~1 second to transfer a 1GB hugepage across a 10Gbps link,
and until the full page is transferred the destination thread is blocked.
Postcopy with shared memory
---------------------------
Postcopy migration with shared memory needs explicit support from the other
processes that share memory and from QEMU. There are restrictions on the type of
memory that userfault can support shared.
The Linux kernel userfault support works on `/dev/shm` memory and on `hugetlbfs`
(although the kernel doesn't provide an equivalent to `madvise(MADV_DONTNEED)`
for hugetlbfs which may be a problem in some configurations).
The vhost-user code in QEMU supports clients that have Postcopy support,
and the `vhost-user-bridge` (in `tests/`) and the DPDK package have changes
to support postcopy.
The client needs to open a userfaultfd and register the areas
of memory that it maps with userfault. The client must then pass the
userfaultfd back to QEMU together with a mapping table that allows
fault addresses in the clients address space to be converted back to
RAMBlock/offsets. The client's userfaultfd is added to the postcopy
fault-thread and page requests are made on behalf of the client by QEMU.
QEMU performs 'wake' operations on the client's userfaultfd to allow it
to continue after a page has arrived.
.. note::
There are two future improvements that would be nice:
a) Some way to make QEMU ignorant of the addresses in the clients
address space
b) Avoiding the need for QEMU to perform ufd-wake calls after the
pages have arrived
Retro-fitting postcopy to existing clients is possible:
a) A mechanism is needed for the registration with userfault as above,
and the registration needs to be coordinated with the phases of
postcopy. In vhost-user extra messages are added to the existing
control channel.
b) Any thread that can block due to guest memory accesses must be
identified and the implication understood; for example if the
guest memory access is made while holding a lock then all other
threads waiting for that lock will also be blocked.

View File

@@ -554,12 +554,9 @@ following example objects:
=== Commands ===
--- General Command Layout ---
Usage: { 'command': STRING, '*data': COMPLEX-TYPE-NAME-OR-DICT,
'*returns': TYPE-NAME, '*boxed': true,
'*gen': false, '*success-response': false,
'*allow-oob': true }
'*gen': false, '*success-response': false }
Commands are defined by using a dictionary containing several members,
where three members are most common. The 'command' member is a
@@ -639,49 +636,6 @@ possible, the command expression should include the optional key
'success-response' with boolean value false. So far, only QGA makes
use of this member.
A command can be declared to support Out-Of-Band (OOB) execution. By
default, commands do not support OOB. To declare a command that
supports it, the schema includes an extra 'allow-oob' field. For
example:
{ 'command': 'migrate_recover',
'data': { 'uri': 'str' }, 'allow-oob': true }
To execute a command with out-of-band priority, the client specifies
the "control" field in the request, with "run-oob" set to
true. Example:
=> { "execute": "command-support-oob",
"arguments": { ... },
"control": { "run-oob": true } }
<= { "return": { } }
Without it, even the commands that support out-of-band execution will
still be run in-band.
Under normal QMP command execution, the following apply to each
command:
- They are executed in order,
- They run only in main thread of QEMU,
- They have the BQL taken during execution.
When a command is executed with OOB, the following changes occur:
- They can be completed before a pending in-band command,
- They run in a dedicated monitor thread,
- They do not take the BQL during execution.
OOB command handlers must satisfy the following conditions:
- It executes extremely fast,
- It does not take any lock, or, it can take very small locks if all
critical regions also follow the rules for OOB command handler code,
- It does not invoke system calls that may block,
- It does not access guest RAM that may block when userfaultfd is
enabled for postcopy live migration.
If in doubt, do not implement OOB execution support.
=== Events ===
@@ -785,12 +739,10 @@ references by name.
QAPI schema definitions not reachable that way are omitted.
The SchemaInfo for a command has meta-type "command", and variant
members "arg-type", "ret-type" and "allow-oob". On the wire, the
"arguments" member of a client's "execute" command must conform to the
object type named by "arg-type". The "return" member that the server
passes in a success response conforms to the type named by
"ret-type". When "allow-oob" is set, it means the command supports
out-of-band execution.
members "arg-type" and "ret-type". On the wire, the "arguments"
member of a client's "execute" command must conform to the object type
named by "arg-type". The "return" member that the server passes in a
success response conforms to the type named by "ret-type".
If the command takes no arguments, "arg-type" names an object type
without members. Likewise, if the command returns nothing, "ret-type"
@@ -1367,27 +1319,18 @@ Example:
#ifndef EXAMPLE_QMP_INTROSPECT_H
#define EXAMPLE_QMP_INTROSPECT_H
extern const QLitObject qmp_schema_qlit;
extern const char example_qmp_schema_json[];
#endif
$ cat qapi-generated/example-qapi-introspect.c
[Uninteresting stuff omitted...]
const QLitObject example_qmp_schema_qlit = QLIT_QLIST(((QLitObject[]) {
QLIT_QDICT(((QLitDictEntry[]) {
{ "arg-type", QLIT_QSTR("0") },
{ "meta-type", QLIT_QSTR("event") },
{ "name", QLIT_QSTR("Event") },
{ }
})),
QLIT_QDICT(((QLitDictEntry[]) {
{ "members", QLIT_QLIST(((QLitObject[]) {
{ }
})) },
{ "meta-type", QLIT_QSTR("object") },
{ "name", QLIT_QSTR("0") },
{ }
})),
...
{ }
}));
const char example_qmp_schema_json[] = "["
"{\"arg-type\": \"0\", \"meta-type\": \"event\", \"name\": \"MY_EVENT\"}, "
"{\"arg-type\": \"1\", \"meta-type\": \"command\", \"name\": \"my-command\", \"ret-type\": \"2\"}, "
"{\"members\": [], \"meta-type\": \"object\", \"name\": \"0\"}, "
"{\"members\": [{\"name\": \"arg1\", \"type\": \"[2]\"}], \"meta-type\": \"object\", \"name\": \"1\"}, "
"{\"members\": [{\"name\": \"integer\", \"type\": \"int\"}, {\"default\": null, \"name\": \"string\", \"type\": \"str\"}], \"meta-type\": \"object\", \"name\": \"2\"}, "
"{\"element-type\": \"2\", \"meta-type\": \"array\", \"name\": \"[2]\"}, "
"{\"json-type\": \"int\", \"meta-type\": \"builtin\", \"name\": \"int\"}, "
"{\"json-type\": \"string\", \"meta-type\": \"builtin\", \"name\": \"str\"}]";

View File

@@ -83,27 +83,16 @@ The greeting message format is:
2.2.1 Capabilities
------------------
Currently supported capabilities are:
As of the date this document was last revised, no server or client
capability strings have been defined.
- "oob": the QMP server supports "Out-Of-Band" (OOB) command
execution. For more details, please see the "run-oob" parameter in
the "Issuing Commands" section below. Not all commands allow this
"oob" execution. The "query-qmp-schema" command can be used to
inspect which commands support "oob" execution.
QMP clients can get a list of supported QMP capabilities of the QMP
server in the greeting message mentioned above. By default, all the
capabilities are off. To enable any QMP capabilities, the QMP client
needs to send the "qmp_capabilities" command with an extra parameter
for the requested capabilities.
2.3 Issuing Commands
--------------------
The format for command execution is:
{ "execute": json-string, "arguments": json-object, "id": json-value,
"control": json-object }
{ "execute": json-string, "arguments": json-object, "id": json-value }
Where,
@@ -113,16 +102,10 @@ The format for command execution is:
required. Each command documents what contents will be considered
valid when handling the json-argument
- The "id" member is a transaction identification associated with the
command execution. It is required for all commands if the OOB -
capability was enabled at startup, and optional otherwise. The same
"id" field will be part of the response if provided. The "id" member
can be any json-value, although most clients merely use a
json-number incremented for each successive command
- The "control" member is optional, and currently only used for
out-of-band execution. The handling or response of an "oob" command
can overtake prior in-band commands. To enable "oob" handling of a
particular command, just provide a control field with: { "control":
{ "run-oob": true } }
command execution, it is optional and will be part of the response if
provided. The "id" member can be any json-value, although most
clients merely use a json-number incremented for each successive
command
2.4 Commands Responses
----------------------
@@ -130,11 +113,6 @@ The format for command execution is:
There are two possible responses which the Server will issue as the result
of a command execution: success or error.
As long as the commands were issued with a proper "id" field, then the
same "id" field will be attached in the corresponding response message
so that requests and responses can match. Clients should drop all the
responses that have an unknown "id" field.
2.4.1 success
-------------

View File

@@ -290,15 +290,6 @@ Once the source has finished migration, rings will be stopped by
the source. No further update must be done before rings are
restarted.
In postcopy migration the slave is started before all the memory has been
received from the source host, and care must be taken to avoid accessing pages
that have yet to be received. The slave opens a 'userfault'-fd and registers
the memory with it; this fd is then passed back over to the master.
The master services requests on the userfaultfd for pages that are accessed
and when the page is available it performs WAKE ioctl's on the userfaultfd
to wake the stalled slave. The client indicates support for this via the
VHOST_USER_PROTOCOL_F_PAGEFAULT feature.
Memory access
-------------
@@ -378,7 +369,6 @@ Protocol features
#define VHOST_USER_PROTOCOL_F_SLAVE_REQ 5
#define VHOST_USER_PROTOCOL_F_CROSS_ENDIAN 6
#define VHOST_USER_PROTOCOL_F_CRYPTO_SESSION 7
#define VHOST_USER_PROTOCOL_F_PAGEFAULT 8
Master message types
--------------------
@@ -455,21 +445,12 @@ Master message types
Id: 5
Equivalent ioctl: VHOST_SET_MEM_TABLE
Master payload: memory regions description
Slave payload: (postcopy only) memory regions description
Sets the memory map regions on the slave so it can translate the vring
addresses. In the ancillary data there is an array of file descriptors
for each memory mapped region. The size and ordering of the fds matches
the number and ordering of memory regions.
When VHOST_USER_POSTCOPY_LISTEN has been received, SET_MEM_TABLE replies with
the bases of the memory mapped regions to the master. The slave must
have mmap'd the regions but not yet accessed them and should not yet generate
a userfault event. Note NEED_REPLY_MASK is not set in this case.
QEMU will then reply back to the list of mappings with an empty
VHOST_USER_SET_MEM_TABLE as an acknowledgment; only upon reception of this
message may the guest start accessing the memory and generating faults.
* VHOST_USER_SET_LOG_BASE
Id: 6
@@ -708,39 +689,6 @@ Master message types
feature has been successfully negotiated.
It's a required feature for crypto devices.
* VHOST_USER_POSTCOPY_ADVISE
Id: 28
Master payload: N/A
Slave payload: userfault fd
When VHOST_USER_PROTOCOL_F_PAGEFAULT is supported, the
master advises slave that a migration with postcopy enabled is underway,
the slave must open a userfaultfd for later use.
Note that at this stage the migration is still in precopy mode.
* VHOST_USER_POSTCOPY_LISTEN
Id: 29
Master payload: N/A
Master advises slave that a transition to postcopy mode has happened.
The slave must ensure that shared memory is registered with userfaultfd
to cause faulting of non-present pages.
This is always sent sometime after a VHOST_USER_POSTCOPY_ADVISE, and
thus only when VHOST_USER_PROTOCOL_F_PAGEFAULT is supported.
* VHOST_USER_POSTCOPY_END
Id: 30
Slave payload: u64
Master advises that postcopy migration has now completed. The
slave must disable the userfaultfd. The response is an acknowledgement
only.
When VHOST_USER_PROTOCOL_F_PAGEFAULT is supported, this message
is sent at the end of the migration, after VHOST_USER_POSTCOPY_LISTEN
was previously sent.
The value returned is an error indication; 0 is success.
Slave message types
-------------------

View File

@@ -7,10 +7,14 @@ See the COPYING file in the top-level directory.
Record/replay
-------------
Record/replay functions are used for the deterministic replay of qemu execution.
Record/replay functions are used for the reverse execution and deterministic
replay of qemu execution. This implementation of deterministic replay can
be used for deterministic debugging of guest code through a gdb remote
interface.
Execution recording writes a non-deterministic events log, which can be later
used for replaying the execution anywhere and for unlimited number of times.
It also supports checkpointing for faster rewind to the specific replay moment.
It also supports checkpointing for faster rewinding during reverse debugging.
Execution replaying reads the log and replays all non-deterministic events
including external input, hardware clocks, and interrupts.
@@ -24,36 +28,16 @@ Deterministic replay has the following features:
input devices.
Usage of the record/replay:
* First, record the execution with the following command line:
qemu-system-i386 \
-icount shift=7,rr=record,rrfile=replay.bin \
-drive file=disk.qcow2,if=none,id=img-direct \
-drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay \
-device ide-hd,drive=img-blkreplay \
-netdev user,id=net1 -device rtl8139,netdev=net1 \
-object filter-replay,id=replay,netdev=net1
* After recording, you can replay it by using another command line:
qemu-system-i386 \
-icount shift=7,rr=replay,rrfile=replay.bin \
-drive file=disk.qcow2,if=none,id=img-direct \
-drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay \
-device ide-hd,drive=img-blkreplay \
-netdev user,id=net1 -device rtl8139,netdev=net1 \
-object filter-replay,id=replay,netdev=net1
The only difference with recording is changing the rr option
from record to replay.
* Block device images are not actually changed in the recording mode,
* First, record the execution, by adding the following arguments to the command line:
'-icount shift=7,rr=record,rrfile=replay.bin -net none'.
Block devices' images are not actually changed in the recording mode,
because all of the changes are written to the temporary overlay file.
This behavior is enabled by using blkreplay driver. It should be used
for every enabled block device, as described in 'Block devices' section.
* '-net none' option should be specified when network is not used,
because QEMU adds network card by default. When network is needed,
it should be configured explicitly with replay filter, as described
in 'Network devices' section.
* Interaction with audio devices and serial ports are recorded and replayed
automatically when such devices are enabled.
* Then you can replay it by using another command
line option: '-icount shift=7,rr=replay,rrfile=replay.bin -net none'
* '-net none' option should also be specified if network replay patches
are not applied.
Academic papers with description of deterministic replay implementation:
Papers with description of deterministic replay implementation:
http://www.computer.org/csdl/proceedings/csmr/2012/4666/00/4666a553-abs.html
http://dl.acm.org/citation.cfm?id=2786805.2803179
@@ -62,33 +46,8 @@ Modifications of qemu include:
* saving different asynchronous events (e.g. system shutdown) into the log
* synchronization of the bottom halves execution
* synchronization of the threads from thread pool
* recording/replaying user input (mouse, keyboard, and microphone)
* recording/replaying user input (mouse and keyboard)
* adding internal checkpoints for cpu and io synchronization
* network filter for recording and replaying the packets
* block driver for making block layer deterministic
* serial port input record and replay
Locking and thread synchronisation
----------------------------------
Previously the synchronisation of the main thread and the vCPU thread
was ensured by the holding of the BQL. However the trend has been to
reduce the time the BQL was held across the system including under TCG
system emulation. As it is important that batches of events are kept
in sequence (e.g. expiring timers and checkpoints in the main thread
while instruction checkpoints are written by the vCPU thread) we need
another lock to keep things in lock-step. This role is now handled by
the replay_mutex_lock. It used to be held only for each event being
written but now it is held for a whole execution period. This results
in a deterministic ping-pong between the two main threads.
As the BQL is now a finer grained lock than the replay_lock it is almost
certainly a bug, and a source of deadlocks, to take the
replay_mutex_lock while the BQL is held. This is enforced by an assert.
While the unlocks are usually in the reverse order, this is not
necessary; you can drop the replay_lock while holding the BQL, without
doing a more complicated unlock_iothread/replay_unlock/lock_iothread
sequence.
Non-deterministic events
------------------------
@@ -96,11 +55,12 @@ Non-deterministic events
Our record/replay system is based on saving and replaying non-deterministic
events (e.g. keyboard input) and simulating deterministic ones (e.g. reading
from HDD or memory of the VM). Saving only non-deterministic events makes
log file smaller and simulation faster.
log file smaller, simulation faster, and allows using reverse debugging even
for realtime applications.
The following non-deterministic data from peripheral devices is saved into
the log: mouse and keyboard input, network packets, audio controller input,
serial port input, and hardware clocks (they are non-deterministic
USB packets, serial port input, and hardware clocks (they are non-deterministic
too, because their values are taken from the host machine). Inputs from
simulated hardware, memory of VM, software interrupts, and execution of
instructions are not saved into the log, because they are deterministic and
@@ -223,7 +183,7 @@ Block devices record/replay module intercepts calls of
bdrv coroutine functions at the top of block drivers stack.
To record and replay block operations the drive must be configured
as following:
-drive file=disk.qcow2,if=none,id=img-direct
-drive file=disk.qcow,if=none,id=img-direct
-drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay
-device ide-hd,drive=img-blkreplay
@@ -252,12 +212,6 @@ This snapshot is created at start of recording and restored at start
of replaying. It also can be loaded while replaying to roll back
the execution.
Use QEMU monitor to create additional snapshots. 'savevm <name>' command
created the snapshot and 'loadvm <name>' restores it. To prevent corruption
of the original disk image, use overlay files linked to the original images.
Therefore all new snapshots (including the starting one) will be saved in
overlays and the original image remains unchanged.
Network devices
---------------
@@ -278,80 +232,3 @@ Audio devices
Audio data is recorded and replay automatically. The command line for recording
and replaying must contain identical specifications of audio hardware, e.g.:
-soundhw ac97
Serial ports
------------
Serial ports input is recorded and replay automatically. The command lines
for recording and replaying must contain identical number of ports in record
and replay modes, but their backends may differ.
E.g., '-serial stdio' in record mode, and '-serial null' in replay mode.
Replay log format
-----------------
Record/replay log consits of the header and the sequence of execution
events. The header includes 4-byte replay version id and 8-byte reserved
field. Version is updated every time replay log format changes to prevent
using replay log created by another build of qemu.
The sequence of the events describes virtual machine state changes.
It includes all non-deterministic inputs of VM, synchronization marks and
instruction counts used to correctly inject inputs at replay.
Synchronization marks (checkpoints) are used for synchronizing qemu threads
that perform operations with virtual hardware. These operations may change
system's state (e.g., change some register or generate interrupt) and
therefore should execute synchronously with CPU thread.
Every event in the log includes 1-byte event id and optional arguments.
When argument is an array, it is stored as 4-byte array length
and corresponding number of bytes with data.
Here is the list of events that are written into the log:
- EVENT_INSTRUCTION. Instructions executed since last event.
Argument: 4-byte number of executed instructions.
- EVENT_INTERRUPT. Used to synchronize interrupt processing.
- EVENT_EXCEPTION. Used to synchronize exception handling.
- EVENT_ASYNC. This is a group of events. They are always processed
together with checkpoints. When such an event is generated, it is
stored in the queue and processed only when checkpoint occurs.
Every such event is followed by 1-byte checkpoint id and 1-byte
async event id from the following list:
- REPLAY_ASYNC_EVENT_BH. Bottom-half callback. This event synchronizes
callbacks that affect virtual machine state, but normally called
asyncronously.
Argument: 8-byte operation id.
- REPLAY_ASYNC_EVENT_INPUT. Input device event. Contains
parameters of keyboard and mouse input operations
(key press/release, mouse pointer movement).
Arguments: 9-16 bytes depending of input event.
- REPLAY_ASYNC_EVENT_INPUT_SYNC. Internal input synchronization event.
- REPLAY_ASYNC_EVENT_CHAR_READ. Character (e.g., serial port) device input
initiated by the sender.
Arguments: 1-byte character device id.
Array with bytes were read.
- REPLAY_ASYNC_EVENT_BLOCK. Block device operation. Used to synchronize
operations with disk and flash drives with CPU.
Argument: 8-byte operation id.
- REPLAY_ASYNC_EVENT_NET. Incoming network packet.
Arguments: 1-byte network adapter id.
4-byte packet flags.
Array with packet bytes.
- EVENT_SHUTDOWN. Occurs when user sends shutdown event to qemu,
e.g., by closing the window.
- EVENT_CHAR_WRITE. Used to synchronize character output operations.
Arguments: 4-byte output function return value.
4-byte offset in the output array.
- EVENT_CHAR_READ_ALL. Used to synchronize character input operations,
initiated by qemu.
Argument: Array with bytes that were read.
- EVENT_CHAR_READ_ALL_ERROR. Unsuccessful character input operation,
initiated by qemu.
Argument: 4-byte error code.
- EVENT_CLOCK + clock_id. Group of events for host clock read operations.
Argument: 8-byte clock value.
- EVENT_CHECKPOINT + checkpoint_id. Checkpoint for synchronization of
CPU, internal threads, and asynchronous input events. May be followed
by one or more EVENT_ASYNC events.
- EVENT_END. Last event in the log.

14
dump.c
View File

@@ -1609,18 +1609,10 @@ static void vmcoreinfo_update_phys_base(DumpState *s)
lines = g_strsplit((char *)vmci, "\n", -1);
for (i = 0; lines[i]; i++) {
const char *prefix = NULL;
if (s->dump_info.d_machine == EM_X86_64) {
prefix = "NUMBER(phys_base)=";
} else if (s->dump_info.d_machine == EM_AARCH64) {
prefix = "NUMBER(PHYS_OFFSET)=";
}
if (prefix && g_str_has_prefix(lines[i], prefix)) {
if (qemu_strtou64(lines[i] + strlen(prefix), NULL, 16,
if (g_str_has_prefix(lines[i], "NUMBER(phys_base)=")) {
if (qemu_strtou64(lines[i] + 18, NULL, 16,
&phys_base) < 0) {
warn_report("Failed to read %s", prefix);
warn_report("Failed to read NUMBER(phys_base)=");
} else {
s->dump_info.phys_base = phys_base;
}

109
exec.c
View File

@@ -99,11 +99,6 @@ static MemoryRegion io_mem_unassigned;
*/
#define RAM_RESIZEABLE (1 << 2)
/* UFFDIO_ZEROPAGE is available on this RAMBlock to atomically
* zero the page and wake waiting processes.
* (Set during postcopy)
*/
#define RAM_UF_ZEROPAGE (1 << 3)
#endif
#ifdef TARGET_PAGE_BITS_VARY
@@ -822,29 +817,6 @@ void cpu_exec_realizefn(CPUState *cpu, Error **errp)
#endif
}
const char *parse_cpu_model(const char *cpu_model)
{
ObjectClass *oc;
CPUClass *cc;
gchar **model_pieces;
const char *cpu_type;
model_pieces = g_strsplit(cpu_model, ",", 2);
oc = cpu_class_by_name(CPU_RESOLVING_TYPE, model_pieces[0]);
if (oc == NULL) {
error_report("unable to find CPU model '%s'", model_pieces[0]);
g_strfreev(model_pieces);
exit(EXIT_FAILURE);
}
cpu_type = object_class_get_name(oc);
cc = CPU_CLASS(oc);
cc->parse_features(cpu_type, model_pieces[1], &error_fatal);
g_strfreev(model_pieces);
return cpu_type;
}
#if defined(CONFIG_USER_ONLY)
static void breakpoint_invalidate(CPUState *cpu, target_ulong pc)
{
@@ -1795,17 +1767,6 @@ bool qemu_ram_is_shared(RAMBlock *rb)
return rb->flags & RAM_SHARED;
}
/* Note: Only set at the start of postcopy */
bool qemu_ram_is_uf_zeroable(RAMBlock *rb)
{
return rb->flags & RAM_UF_ZEROPAGE;
}
void qemu_ram_set_uf_zeroable(RAMBlock *rb)
{
rb->flags |= RAM_UF_ZEROPAGE;
}
/* Called with iothread lock held. */
void qemu_ram_set_idstr(RAMBlock *new_block, const char *name, DeviceState *dev)
{
@@ -2336,16 +2297,6 @@ static void *qemu_ram_ptr_length(RAMBlock *ram_block, ram_addr_t addr,
return ramblock_ptr(block, addr);
}
/* Return the offset of a hostpointer within a ramblock */
ram_addr_t qemu_ram_block_host_offset(RAMBlock *rb, void *host)
{
ram_addr_t res = (uint8_t *)host - (uint8_t *)rb->host;
assert((uintptr_t)host >= (uintptr_t)rb->host);
assert(res < rb->max_length);
return res;
}
/*
* Translates a host ptr back to a RAMBlock, a ram_addr and an offset
* in that RAMBlock.
@@ -3770,7 +3721,6 @@ int ram_block_discard_range(RAMBlock *rb, uint64_t start, size_t length)
}
if ((start + length) <= rb->used_length) {
bool need_madvise, need_fallocate;
uint8_t *host_endaddr = host_startaddr + length;
if ((uintptr_t)host_endaddr & (rb->page_size - 1)) {
error_report("ram_block_discard_range: Unaligned end address: %p",
@@ -3780,60 +3730,29 @@ int ram_block_discard_range(RAMBlock *rb, uint64_t start, size_t length)
errno = ENOTSUP; /* If we are missing MADVISE etc */
/* The logic here is messy;
* madvise DONTNEED fails for hugepages
* fallocate works on hugepages and shmem
*/
need_madvise = (rb->page_size == qemu_host_page_size);
need_fallocate = rb->fd != -1;
if (need_fallocate) {
/* For a file, this causes the area of the file to be zero'd
* if read, and for hugetlbfs also causes it to be unmapped
* so a userfault will trigger.
if (rb->page_size == qemu_host_page_size) {
#if defined(CONFIG_MADVISE)
/* Note: We need the madvise MADV_DONTNEED behaviour of definitely
* freeing the page.
*/
ret = madvise(host_startaddr, length, MADV_DONTNEED);
#endif
} else {
/* Huge page case - unfortunately it can't do DONTNEED, but
* it can do the equivalent by FALLOC_FL_PUNCH_HOLE in the
* huge page file.
*/
#ifdef CONFIG_FALLOCATE_PUNCH_HOLE
ret = fallocate(rb->fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
start, length);
if (ret) {
ret = -errno;
error_report("ram_block_discard_range: Failed to fallocate "
"%s:%" PRIx64 " +%zx (%d)",
rb->idstr, start, length, ret);
goto err;
}
#else
ret = -ENOSYS;
error_report("ram_block_discard_range: fallocate not available/file"
"%s:%" PRIx64 " +%zx (%d)",
rb->idstr, start, length, ret);
goto err;
#endif
}
if (need_madvise) {
/* For normal RAM this causes it to be unmapped,
* for shared memory it causes the local mapping to disappear
* and to fall back on the file contents (which we just
* fallocate'd away).
*/
#if defined(CONFIG_MADVISE)
ret = madvise(host_startaddr, length, MADV_DONTNEED);
if (ret) {
ret = -errno;
error_report("ram_block_discard_range: Failed to discard range "
"%s:%" PRIx64 " +%zx (%d)",
rb->idstr, start, length, ret);
goto err;
}
#else
ret = -ENOSYS;
error_report("ram_block_discard_range: MADVISE not available"
if (ret) {
ret = -errno;
error_report("ram_block_discard_range: Failed to discard range "
"%s:%" PRIx64 " +%zx (%d)",
rb->idstr, start, length, ret);
goto err;
#endif
}
trace_ram_block_discard_range(rb->idstr, host_startaddr, length,
need_madvise, need_fallocate, ret);
} else {
error_report("ram_block_discard_range: Overrun block '%s' (%" PRIu64
"/%zx/" RAM_ADDR_FMT")",

View File

@@ -867,22 +867,6 @@ Display the amount of initially allocated and present hotpluggable (if
enabled) memory in bytes.
ETEXI
#if defined(TARGET_I386)
{
.name = "sev",
.args_type = "",
.params = "",
.help = "show SEV information",
.cmd = hmp_info_sev,
},
#endif
STEXI
@item info sev
@findex info sev
Show SEV information.
ETEXI
STEXI
@end table
ETEXI

View File

@@ -106,8 +106,7 @@ ETEXI
.args_type = "force:-f,device:B",
.params = "[-f] device",
.help = "stop an active background block operation (use -f"
"\n\t\t\t if you want to abort the operation immediately"
"\n\t\t\t instead of keep running until data is in sync)",
"\n\t\t\t if the operation is currently paused)",
.cmd = hmp_block_job_cancel,
},

16
hmp.c
View File

@@ -1321,7 +1321,7 @@ void hmp_savevm(Monitor *mon, const QDict *qdict)
void hmp_delvm(Monitor *mon, const QDict *qdict)
{
BlockDriverState *bs;
Error *err = NULL;
Error *err;
const char *name = qdict_get_str(qdict, "name");
if (bdrv_all_delete_snapshot(name, &bs, &err) < 0) {
@@ -2423,18 +2423,7 @@ void hmp_info_memory_devices(Monitor *mon, const QDict *qdict)
switch (value->type) {
case MEMORY_DEVICE_INFO_KIND_DIMM:
di = value->u.dimm.data;
break;
case MEMORY_DEVICE_INFO_KIND_NVDIMM:
di = value->u.nvdimm.data;
break;
default:
di = NULL;
break;
}
if (di) {
monitor_printf(mon, "Memory device [%s]: \"%s\"\n",
MemoryDeviceInfoKind_str(value->type),
di->id ? di->id : "");
@@ -2447,6 +2436,9 @@ void hmp_info_memory_devices(Monitor *mon, const QDict *qdict)
di->hotplugged ? "true" : "false");
monitor_printf(mon, " hotpluggable: %s\n",
di->hotpluggable ? "true" : "false");
break;
default:
break;
}
}
}

1
hmp.h
View File

@@ -143,6 +143,5 @@ void hmp_info_ramblock(Monitor *mon, const QDict *qdict);
void hmp_hotpluggable_cpus(Monitor *mon, const QDict *qdict);
void hmp_info_vm_generation_id(Monitor *mon, const QDict *qdict);
void hmp_info_memory_size_summary(Monitor *mon, const QDict *qdict);
void hmp_info_sev(Monitor *mon, const QDict *qdict);
#endif

View File

@@ -258,22 +258,6 @@ static void build_append_int(GArray *table, uint64_t value)
}
}
/* Generic Address Structure (GAS)
* ACPI 2.0/3.0: 5.2.3.1 Generic Address Structure
* 2.0 compat note:
* @access_width must be 0, see ACPI 2.0:Table 5-1
*/
void build_append_gas(GArray *table, AmlAddressSpace as,
uint8_t bit_width, uint8_t bit_offset,
uint8_t access_width, uint64_t address)
{
build_append_int_noprefix(table, as, 1);
build_append_int_noprefix(table, bit_width, 1);
build_append_int_noprefix(table, bit_offset, 1);
build_append_int_noprefix(table, access_width, 1);
build_append_int_noprefix(table, address, 8);
}
/*
* Build NAME(XXXX, 0x00000000) where 0x00000000 is encoded as a dword,
* and return the offset to 0x00000000 for runtime patching.
@@ -1678,127 +1662,3 @@ void build_slit(GArray *table_data, BIOSLinker *linker)
"SLIT",
table_data->len - slit_start, 1, NULL, NULL);
}
/* build rev1/rev3/rev5.1 FADT */
void build_fadt(GArray *tbl, BIOSLinker *linker, const AcpiFadtData *f,
const char *oem_id, const char *oem_table_id)
{
int off;
int fadt_start = tbl->len;
acpi_data_push(tbl, sizeof(AcpiTableHeader));
/* FACS address to be filled by Guest linker at runtime */
off = tbl->len;
build_append_int_noprefix(tbl, 0, 4); /* FIRMWARE_CTRL */
if (f->facs_tbl_offset) { /* don't patch if not supported by platform */
bios_linker_loader_add_pointer(linker,
ACPI_BUILD_TABLE_FILE, off, 4,
ACPI_BUILD_TABLE_FILE, *f->facs_tbl_offset);
}
/* DSDT address to be filled by Guest linker at runtime */
off = tbl->len;
build_append_int_noprefix(tbl, 0, 4); /* DSDT */
if (f->dsdt_tbl_offset) { /* don't patch if not supported by platform */
bios_linker_loader_add_pointer(linker,
ACPI_BUILD_TABLE_FILE, off, 4,
ACPI_BUILD_TABLE_FILE, *f->dsdt_tbl_offset);
}
/* ACPI1.0: INT_MODEL, ACPI2.0+: Reserved */
build_append_int_noprefix(tbl, f->int_model /* Multiple APIC */, 1);
/* Preferred_PM_Profile */
build_append_int_noprefix(tbl, 0 /* Unspecified */, 1);
build_append_int_noprefix(tbl, f->sci_int, 2); /* SCI_INT */
build_append_int_noprefix(tbl, f->smi_cmd, 4); /* SMI_CMD */
build_append_int_noprefix(tbl, f->acpi_enable_cmd, 1); /* ACPI_ENABLE */
build_append_int_noprefix(tbl, f->acpi_disable_cmd, 1); /* ACPI_DISABLE */
build_append_int_noprefix(tbl, 0 /* not supported */, 1); /* S4BIOS_REQ */
/* ACPI1.0: Reserved, ACPI2.0+: PSTATE_CNT */
build_append_int_noprefix(tbl, 0, 1);
build_append_int_noprefix(tbl, f->pm1a_evt.address, 4); /* PM1a_EVT_BLK */
build_append_int_noprefix(tbl, 0, 4); /* PM1b_EVT_BLK */
build_append_int_noprefix(tbl, f->pm1a_cnt.address, 4); /* PM1a_CNT_BLK */
build_append_int_noprefix(tbl, 0, 4); /* PM1b_CNT_BLK */
build_append_int_noprefix(tbl, 0, 4); /* PM2_CNT_BLK */
build_append_int_noprefix(tbl, f->pm_tmr.address, 4); /* PM_TMR_BLK */
build_append_int_noprefix(tbl, f->gpe0_blk.address, 4); /* GPE0_BLK */
build_append_int_noprefix(tbl, 0, 4); /* GPE1_BLK */
/* PM1_EVT_LEN */
build_append_int_noprefix(tbl, f->pm1a_evt.bit_width / 8, 1);
/* PM1_CNT_LEN */
build_append_int_noprefix(tbl, f->pm1a_cnt.bit_width / 8, 1);
build_append_int_noprefix(tbl, 0, 1); /* PM2_CNT_LEN */
build_append_int_noprefix(tbl, f->pm_tmr.bit_width / 8, 1); /* PM_TMR_LEN */
/* GPE0_BLK_LEN */
build_append_int_noprefix(tbl, f->gpe0_blk.bit_width / 8, 1);
build_append_int_noprefix(tbl, 0, 1); /* GPE1_BLK_LEN */
build_append_int_noprefix(tbl, 0, 1); /* GPE1_BASE */
build_append_int_noprefix(tbl, 0, 1); /* CST_CNT */
build_append_int_noprefix(tbl, f->plvl2_lat, 2); /* P_LVL2_LAT */
build_append_int_noprefix(tbl, f->plvl3_lat, 2); /* P_LVL3_LAT */
build_append_int_noprefix(tbl, 0, 2); /* FLUSH_SIZE */
build_append_int_noprefix(tbl, 0, 2); /* FLUSH_STRIDE */
build_append_int_noprefix(tbl, 0, 1); /* DUTY_OFFSET */
build_append_int_noprefix(tbl, 0, 1); /* DUTY_WIDTH */
build_append_int_noprefix(tbl, 0, 1); /* DAY_ALRM */
build_append_int_noprefix(tbl, 0, 1); /* MON_ALRM */
build_append_int_noprefix(tbl, f->rtc_century, 1); /* CENTURY */
build_append_int_noprefix(tbl, 0, 2); /* IAPC_BOOT_ARCH */
build_append_int_noprefix(tbl, 0, 1); /* Reserved */
build_append_int_noprefix(tbl, f->flags, 4); /* Flags */
if (f->rev == 1) {
goto build_hdr;
}
build_append_gas_from_struct(tbl, &f->reset_reg); /* RESET_REG */
build_append_int_noprefix(tbl, f->reset_val, 1); /* RESET_VALUE */
/* Since ACPI 5.1 */
if ((f->rev >= 6) || ((f->rev == 5) && f->minor_ver > 0)) {
build_append_int_noprefix(tbl, f->arm_boot_arch, 2); /* ARM_BOOT_ARCH */
/* FADT Minor Version */
build_append_int_noprefix(tbl, f->minor_ver, 1);
} else {
build_append_int_noprefix(tbl, 0, 3); /* Reserved upto ACPI 5.0 */
}
build_append_int_noprefix(tbl, 0, 8); /* X_FIRMWARE_CTRL */
/* XDSDT address to be filled by Guest linker at runtime */
off = tbl->len;
build_append_int_noprefix(tbl, 0, 8); /* X_DSDT */
if (f->xdsdt_tbl_offset) {
bios_linker_loader_add_pointer(linker,
ACPI_BUILD_TABLE_FILE, off, 8,
ACPI_BUILD_TABLE_FILE, *f->xdsdt_tbl_offset);
}
build_append_gas_from_struct(tbl, &f->pm1a_evt); /* X_PM1a_EVT_BLK */
/* X_PM1b_EVT_BLK */
build_append_gas(tbl, AML_AS_SYSTEM_MEMORY, 0 , 0, 0, 0);
build_append_gas_from_struct(tbl, &f->pm1a_cnt); /* X_PM1a_CNT_BLK */
/* X_PM1b_CNT_BLK */
build_append_gas(tbl, AML_AS_SYSTEM_MEMORY, 0 , 0, 0, 0);
/* X_PM2_CNT_BLK */
build_append_gas(tbl, AML_AS_SYSTEM_MEMORY, 0 , 0, 0, 0);
build_append_gas_from_struct(tbl, &f->pm_tmr); /* X_PM_TMR_BLK */
build_append_gas_from_struct(tbl, &f->gpe0_blk); /* X_GPE0_BLK */
build_append_gas(tbl, AML_AS_SYSTEM_MEMORY, 0 , 0, 0, 0); /* X_GPE1_BLK */
if (f->rev <= 4) {
goto build_hdr;
}
/* SLEEP_CONTROL_REG */
build_append_gas(tbl, AML_AS_SYSTEM_MEMORY, 0 , 0, 0, 0);
/* SLEEP_STATUS_REG */
build_append_gas(tbl, AML_AS_SYSTEM_MEMORY, 0 , 0, 0, 0);
/* TODO: extra fields need to be added to support revisions above rev5 */
assert(f->rev == 5);
build_hdr:
build_header(linker, tbl, (void *)(tbl->data + fadt_start),
"FACP", tbl->len - fadt_start, f->rev, oem_id, oem_table_id);
}

View File

@@ -19,8 +19,7 @@
#include "hw/timer/mc146818rtc.h"
#include "hw/ide.h"
#include "hw/timer/i8254.h"
#include "hw/isa/superio.h"
#include "hw/dma/i8257.h"
#include "hw/char/serial.h"
#include "qemu/cutils.h"
#define MAX_IDE_BUS 2
@@ -82,21 +81,19 @@ static void clipper_init(MachineState *machine)
mc146818_rtc_init(isa_bus, 1900, rtc_irq);
i8254_pit_init(isa_bus, 0x40, 0, NULL);
isa_create_simple(isa_bus, "i8042");
/* VGA setup. Don't bother loading the bios. */
pci_vga_init(pci_bus);
/* Serial code setup. */
serial_hds_isa_init(isa_bus, 0, MAX_SERIAL_PORTS);
/* Network setup. e1000 is good enough, failing Tulip support. */
for (i = 0; i < nb_nics; i++) {
pci_nic_init_nofail(&nd_table[i], pci_bus, "e1000", NULL);
}
/* 2 82C37 (dma) */
isa_create_simple(isa_bus, "i82374");
/* Super I/O */
isa_create_simple(isa_bus, TYPE_SMC37C669_SUPERIO);
/* IDE disk setup. */
{
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];

View File

@@ -23,40 +23,9 @@
/* "QA7" (Pi2) interrupt controller and mailboxes etc. */
#define BCM2836_CONTROL_BASE 0x40000000
struct BCM283XInfo {
const char *name;
const char *cpu_type;
int clusterid;
};
static const BCM283XInfo bcm283x_socs[] = {
{
.name = TYPE_BCM2836,
.cpu_type = ARM_CPU_TYPE_NAME("cortex-a15"),
.clusterid = 0xf,
},
#ifdef TARGET_AARCH64
{
.name = TYPE_BCM2837,
.cpu_type = ARM_CPU_TYPE_NAME("cortex-a53"),
.clusterid = 0x0,
},
#endif
};
static void bcm2836_init(Object *obj)
{
BCM283XState *s = BCM283X(obj);
BCM283XClass *bc = BCM283X_GET_CLASS(obj);
const BCM283XInfo *info = bc->info;
int n;
for (n = 0; n < BCM283X_NCPUS; n++) {
object_initialize(&s->cpus[n], sizeof(s->cpus[n]),
info->cpu_type);
object_property_add_child(obj, "cpu[*]", OBJECT(&s->cpus[n]),
&error_abort);
}
BCM2836State *s = BCM2836(obj);
object_initialize(&s->control, sizeof(s->control), TYPE_BCM2836_CONTROL);
object_property_add_child(obj, "control", OBJECT(&s->control), NULL);
@@ -75,15 +44,21 @@ static void bcm2836_init(Object *obj)
static void bcm2836_realize(DeviceState *dev, Error **errp)
{
BCM283XState *s = BCM283X(dev);
BCM283XClass *bc = BCM283X_GET_CLASS(dev);
const BCM283XInfo *info = bc->info;
BCM2836State *s = BCM2836(dev);
Object *obj;
Error *err = NULL;
int n;
/* common peripherals from bcm2835 */
obj = OBJECT(dev);
for (n = 0; n < BCM2836_NCPUS; n++) {
object_initialize(&s->cpus[n], sizeof(s->cpus[n]),
s->cpu_type);
object_property_add_child(obj, "cpu[*]", OBJECT(&s->cpus[n]),
&error_abort);
}
obj = object_property_get_link(OBJECT(dev), "ram", &err);
if (obj == NULL) {
error_setg(errp, "%s: required ram link not found: %s",
@@ -127,9 +102,11 @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 1,
qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-fiq", 0));
for (n = 0; n < BCM283X_NCPUS; n++) {
/* TODO: this should be converted to a property of ARM_CPU */
s->cpus[n].mp_affinity = (info->clusterid << 8) | n;
for (n = 0; n < BCM2836_NCPUS; n++) {
/* Mirror bcm2836, which has clusterid set to 0xf
* TODO: this should be converted to a property of ARM_CPU
*/
s->cpus[n].mp_affinity = 0xF00 | n;
/* set periphbase/CBAR value for CPU-local registers */
object_property_set_int(OBJECT(&s->cpus[n]),
@@ -173,44 +150,30 @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
}
static Property bcm2836_props[] = {
DEFINE_PROP_UINT32("enabled-cpus", BCM283XState, enabled_cpus,
BCM283X_NCPUS),
DEFINE_PROP_STRING("cpu-type", BCM2836State, cpu_type),
DEFINE_PROP_UINT32("enabled-cpus", BCM2836State, enabled_cpus, BCM2836_NCPUS),
DEFINE_PROP_END_OF_LIST()
};
static void bcm283x_class_init(ObjectClass *oc, void *data)
static void bcm2836_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
BCM283XClass *bc = BCM283X_CLASS(oc);
bc->info = data;
dc->realize = bcm2836_realize;
dc->props = bcm2836_props;
dc->realize = bcm2836_realize;
}
static const TypeInfo bcm283x_type_info = {
.name = TYPE_BCM283X,
.parent = TYPE_DEVICE,
.instance_size = sizeof(BCM283XState),
static const TypeInfo bcm2836_type_info = {
.name = TYPE_BCM2836,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(BCM2836State),
.instance_init = bcm2836_init,
.class_size = sizeof(BCM283XClass),
.abstract = true,
.class_init = bcm2836_class_init,
};
static void bcm2836_register_types(void)
{
int i;
type_register_static(&bcm283x_type_info);
for (i = 0; i < ARRAY_SIZE(bcm283x_socs); i++) {
TypeInfo ti = {
.name = bcm283x_socs[i].name,
.parent = TYPE_BCM283X,
.class_init = bcm283x_class_init,
.class_data = (void *) &bcm283x_socs[i],
};
type_register(&ti);
}
type_register_static(&bcm2836_type_info);
}
type_init(bcm2836_register_types)

View File

@@ -720,18 +720,6 @@ static void do_cpu_reset(void *opaque)
} else {
env->pstate = PSTATE_MODE_EL1h;
}
/* AArch64 kernels never boot in secure mode */
assert(!info->secure_boot);
/* This hook is only supported for AArch32 currently:
* bootloader_aarch64[] will not call the hook, and
* the code above has already dropped us into EL2 or EL1.
*/
assert(!info->secure_board_setup);
}
if (arm_feature(env, ARM_FEATURE_EL2)) {
/* If we have EL2 then Linux expects the HVC insn to work */
env->cp15.scr_el3 |= SCR_HCE;
}
/* Set to non-secure if not a secure boot */

View File

@@ -27,6 +27,7 @@
#include "sysemu/kvm.h"
#include "sysemu/sysemu.h"
#include "hw/boards.h"
#include "sysemu/block-backend.h"
#include "exec/address-spaces.h"
#include "qemu/error-report.h"
#include "hw/char/pl011.h"

View File

@@ -29,6 +29,7 @@
#include "exec/address-spaces.h"
#include "hw/char/serial.h"
#include "hw/boards.h"
#include "sysemu/block-backend.h"
#include "qemu/cutils.h"
#include "hw/arm/msf2-soc.h"
#include "hw/misc/unimp.h"

View File

@@ -27,13 +27,12 @@
#define BOARDSETUP_ADDR (MVBAR_ADDR + 0x20) /* board setup code */
#define FIRMWARE_ADDR_2 0x8000 /* Pi 2 loads kernel.img here by default */
#define FIRMWARE_ADDR_3 0x80000 /* Pi 3 loads kernel.img here by default */
#define SPINTABLE_ADDR 0xd8 /* Pi 3 bootloader spintable */
/* Table of Linux board IDs for different Pi versions */
static const int raspi_boardid[] = {[1] = 0xc42, [2] = 0xc43, [3] = 0xc44};
typedef struct RasPiState {
BCM283XState soc;
BCM2836State soc;
MemoryRegion ram;
} RasPiState;
@@ -64,40 +63,6 @@ static void write_smpboot(ARMCPU *cpu, const struct arm_boot_info *info)
info->smp_loader_start);
}
static void write_smpboot64(ARMCPU *cpu, const struct arm_boot_info *info)
{
/* Unlike the AArch32 version we don't need to call the board setup hook.
* The mechanism for doing the spin-table is also entirely different.
* We must have four 64-bit fields at absolute addresses
* 0xd8, 0xe0, 0xe8, 0xf0 in RAM, which are the flag variables for
* our CPUs, and which we must ensure are zero initialized before
* the primary CPU goes into the kernel. We put these variables inside
* a rom blob, so that the reset for ROM contents zeroes them for us.
*/
static const uint32_t smpboot[] = {
0xd2801b05, /* mov x5, 0xd8 */
0xd53800a6, /* mrs x6, mpidr_el1 */
0x924004c6, /* and x6, x6, #0x3 */
0xd503205f, /* spin: wfe */
0xf86678a4, /* ldr x4, [x5,x6,lsl #3] */
0xb4ffffc4, /* cbz x4, spin */
0xd2800000, /* mov x0, #0x0 */
0xd2800001, /* mov x1, #0x0 */
0xd2800002, /* mov x2, #0x0 */
0xd2800003, /* mov x3, #0x0 */
0xd61f0080, /* br x4 */
};
static const uint64_t spintables[] = {
0, 0, 0, 0
};
rom_add_blob_fixed("raspi_smpboot", smpboot, sizeof(smpboot),
info->smp_loader_start);
rom_add_blob_fixed("raspi_spintables", spintables, sizeof(spintables),
SPINTABLE_ADDR);
}
static void write_board_setup(ARMCPU *cpu, const struct arm_boot_info *info)
{
arm_write_secure_board_setup_dummy_smc(cpu, info, MVBAR_ADDR);
@@ -117,28 +82,15 @@ static void setup_boot(MachineState *machine, int version, size_t ram_size)
binfo.board_id = raspi_boardid[version];
binfo.ram_size = ram_size;
binfo.nb_cpus = smp_cpus;
if (version <= 2) {
/* The rpi1 and 2 require some custom setup code to run in Secure
* mode before booting a kernel (to set up the SMC vectors so
* that we get a no-op SMC; this is used by Linux to call the
* firmware for some cache maintenance operations.
* The rpi3 doesn't need this.
*/
binfo.board_setup_addr = BOARDSETUP_ADDR;
binfo.write_board_setup = write_board_setup;
binfo.secure_board_setup = true;
binfo.secure_boot = true;
}
binfo.board_setup_addr = BOARDSETUP_ADDR;
binfo.write_board_setup = write_board_setup;
binfo.secure_board_setup = true;
binfo.secure_boot = true;
/* Pi2 and Pi3 requires SMP setup */
if (version >= 2) {
binfo.smp_loader_start = SMPBOOT_ADDR;
if (version == 2) {
binfo.write_secondary_boot = write_smpboot;
} else {
binfo.write_secondary_boot = write_smpboot64;
}
binfo.write_secondary_boot = write_smpboot;
binfo.secondary_cpu_reset_hook = reset_secondary;
}
@@ -175,8 +127,7 @@ static void raspi_init(MachineState *machine, int version)
BusState *bus;
DeviceState *carddev;
object_initialize(&s->soc, sizeof(s->soc),
version == 3 ? TYPE_BCM2837 : TYPE_BCM2836);
object_initialize(&s->soc, sizeof(s->soc), TYPE_BCM2836);
object_property_add_child(OBJECT(machine), "soc", OBJECT(&s->soc),
&error_abort);
@@ -189,6 +140,8 @@ static void raspi_init(MachineState *machine, int version)
/* Setup the SOC */
object_property_add_const_link(OBJECT(&s->soc), "ram", OBJECT(&s->ram),
&error_abort);
object_property_set_str(OBJECT(&s->soc), machine->cpu_type, "cpu-type",
&error_abort);
object_property_set_int(OBJECT(&s->soc), smp_cpus, "enabled-cpus",
&error_abort);
int board_rev = version == 3 ? 0xa02082 : 0xa21041;
@@ -227,9 +180,9 @@ static void raspi2_machine_init(MachineClass *mc)
mc->no_floppy = 1;
mc->no_cdrom = 1;
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a15");
mc->max_cpus = BCM283X_NCPUS;
mc->min_cpus = BCM283X_NCPUS;
mc->default_cpus = BCM283X_NCPUS;
mc->max_cpus = BCM2836_NCPUS;
mc->min_cpus = BCM2836_NCPUS;
mc->default_cpus = BCM2836_NCPUS;
mc->default_ram_size = 1024 * 1024 * 1024;
mc->ignore_memory_transaction_failures = true;
};
@@ -250,9 +203,9 @@ static void raspi3_machine_init(MachineClass *mc)
mc->no_floppy = 1;
mc->no_cdrom = 1;
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a53");
mc->max_cpus = BCM283X_NCPUS;
mc->min_cpus = BCM283X_NCPUS;
mc->default_cpus = BCM283X_NCPUS;
mc->max_cpus = BCM2836_NCPUS;
mc->min_cpus = BCM2836_NCPUS;
mc->default_cpus = BCM2836_NCPUS;
mc->default_ram_size = 1024 * 1024 * 1024;
}
DEFINE_MACHINE("raspi3", raspi3_machine_init)

View File

@@ -20,6 +20,7 @@
#include "sysemu/sysemu.h"
#include "hw/boards.h"
#include "hw/i2c/i2c.h"
#include "sysemu/block-backend.h"
#include "exec/address-spaces.h"
#include "qemu/error-report.h"
#include "hw/char/pl011.h"

View File

@@ -22,6 +22,7 @@
#include "hw/boards.h"
#include "hw/i2c/i2c.h"
#include "hw/ssi/ssi.h"
#include "sysemu/block-backend.h"
#include "hw/sysbus.h"
#include "exec/address-spaces.h"
#include "sysemu/sysemu.h"

View File

@@ -651,33 +651,42 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
}
/* FADT */
static void build_fadt_rev5(GArray *table_data, BIOSLinker *linker,
VirtMachineState *vms, unsigned dsdt_tbl_offset)
static void build_fadt(GArray *table_data, BIOSLinker *linker,
VirtMachineState *vms, unsigned dsdt_tbl_offset)
{
/* ACPI v5.1 */
AcpiFadtData fadt = {
.rev = 5,
.minor_ver = 1,
.flags = 1 << ACPI_FADT_F_HW_REDUCED_ACPI,
.xdsdt_tbl_offset = &dsdt_tbl_offset,
};
int fadt_start = table_data->len;
AcpiFadtDescriptorRev5_1 *fadt = acpi_data_push(table_data, sizeof(*fadt));
unsigned xdsdt_entry_offset = (char *)&fadt->x_dsdt - table_data->data;
uint16_t bootflags;
switch (vms->psci_conduit) {
case QEMU_PSCI_CONDUIT_DISABLED:
fadt.arm_boot_arch = 0;
bootflags = 0;
break;
case QEMU_PSCI_CONDUIT_HVC:
fadt.arm_boot_arch = ACPI_FADT_ARM_PSCI_COMPLIANT |
ACPI_FADT_ARM_PSCI_USE_HVC;
bootflags = ACPI_FADT_ARM_PSCI_COMPLIANT | ACPI_FADT_ARM_PSCI_USE_HVC;
break;
case QEMU_PSCI_CONDUIT_SMC:
fadt.arm_boot_arch = ACPI_FADT_ARM_PSCI_COMPLIANT;
bootflags = ACPI_FADT_ARM_PSCI_COMPLIANT;
break;
default:
g_assert_not_reached();
}
build_fadt(table_data, linker, &fadt, NULL, NULL);
/* Hardware Reduced = 1 and use PSCI 0.2+ */
fadt->flags = cpu_to_le32(1 << ACPI_FADT_F_HW_REDUCED_ACPI);
fadt->arm_boot_flags = cpu_to_le16(bootflags);
/* ACPI v5.1 (fadt->revision.fadt->minor_revision) */
fadt->minor_revision = 0x1;
/* DSDT address to be filled by Guest linker */
bios_linker_loader_add_pointer(linker,
ACPI_BUILD_TABLE_FILE, xdsdt_entry_offset, sizeof(fadt->x_dsdt),
ACPI_BUILD_TABLE_FILE, dsdt_tbl_offset);
build_header(linker, table_data, (void *)(table_data->data + fadt_start),
"FACP", table_data->len - fadt_start, 5, NULL, NULL);
}
/* DSDT */
@@ -752,7 +761,7 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
/* FADT MADT GTDT MCFG SPCR pointed to by RSDT */
acpi_add_table(table_offsets, tables_blob);
build_fadt_rev5(tables_blob, tables->linker, vms, dsdt);
build_fadt(tables_blob, tables->linker, vms, dsdt);
acpi_add_table(table_offsets, tables_blob);
build_madt(tables_blob, tables->linker, vms);

View File

@@ -1,7 +1,6 @@
common-obj-$(CONFIG_IPACK) += ipoctal232.o
common-obj-$(CONFIG_ESCC) += escc.o
common-obj-$(CONFIG_PARALLEL) += parallel.o
common-obj-$(CONFIG_PARALLEL) += parallel-isa.o
common-obj-$(CONFIG_PL011) += pl011.o
common-obj-$(CONFIG_SERIAL) += serial.o
common-obj-$(CONFIG_SERIAL_ISA) += serial-isa.o

View File

@@ -37,8 +37,8 @@
static const VMStateDescription vmstate_imx_serial = {
.name = TYPE_IMX_SERIAL,
.version_id = 2,
.minimum_version_id = 2,
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_INT32(readbuff, IMXSerialState),
VMSTATE_UINT32(usr1, IMXSerialState),
@@ -50,36 +50,22 @@ static const VMStateDescription vmstate_imx_serial = {
VMSTATE_UINT32(ubmr, IMXSerialState),
VMSTATE_UINT32(ubrc, IMXSerialState),
VMSTATE_UINT32(ucr3, IMXSerialState),
VMSTATE_UINT32(ucr4, IMXSerialState),
VMSTATE_END_OF_LIST()
},
};
static void imx_update(IMXSerialState *s)
{
uint32_t usr1;
uint32_t usr2;
uint32_t mask;
uint32_t flags;
/*
* Lucky for us TRDY and RRDY has the same offset in both USR1 and
* UCR1, so we can get away with something as simple as the
* following:
*/
usr1 = s->usr1 & s->ucr1 & (USR1_TRDY | USR1_RRDY);
/*
* Bits that we want in USR2 are not as conveniently laid out,
* unfortunately.
*/
mask = (s->ucr1 & UCR1_TXMPTYEN) ? USR2_TXFE : 0;
/*
* TCEN and TXDC are both bit 3
*/
mask |= s->ucr4 & UCR4_TCEN;
flags = (s->usr1 & s->ucr1) & (USR1_TRDY|USR1_RRDY);
if (s->ucr1 & UCR1_TXMPTYEN) {
flags |= (s->uts1 & UTS1_TXEMPTY);
} else {
flags &= ~USR1_TRDY;
}
usr2 = s->usr2 & mask;
qemu_set_irq(s->irq, usr1 || usr2);
qemu_set_irq(s->irq, !!flags);
}
static void imx_serial_reset(IMXSerialState *s)
@@ -169,8 +155,6 @@ static uint64_t imx_serial_read(void *opaque, hwaddr offset,
return s->ucr3;
case 0x23: /* UCR4 */
return s->ucr4;
case 0x29: /* BRM Incremental */
return 0x0; /* TODO */
@@ -199,10 +183,8 @@ static void imx_serial_write(void *opaque, hwaddr offset,
* qemu_chr_fe_write and background I/O callbacks */
qemu_chr_fe_write_all(&s->chr, &ch, 1);
s->usr1 &= ~USR1_TRDY;
s->usr2 &= ~USR2_TXDC;
imx_update(s);
s->usr1 |= USR1_TRDY;
s->usr2 |= USR2_TXDC;
imx_update(s);
}
break;
@@ -275,12 +257,8 @@ static void imx_serial_write(void *opaque, hwaddr offset,
s->ucr3 = value & 0xffff;
break;
case 0x23: /* UCR4 */
s->ucr4 = value & 0xffff;
imx_update(s);
break;
case 0x2d: /* UTS1 */
case 0x23: /* UCR4 */
qemu_log_mask(LOG_UNIMP, "[%s]%s: Unimplemented reg 0x%"
HWADDR_PRIx "\n", TYPE_IMX_SERIAL, __func__, offset);
/* TODO */

View File

@@ -1,36 +0,0 @@
/*
* QEMU Parallel PORT (ISA bus helpers)
*
* Copyright (c) 2003 Fabrice Bellard
*
* SPDX-License-Identifier: MIT
*/
#include "qemu/osdep.h"
#include "sysemu/sysemu.h"
#include "hw/isa/isa.h"
#include "hw/char/parallel.h"
static void parallel_init(ISABus *bus, int index, Chardev *chr)
{
DeviceState *dev;
ISADevice *isadev;
isadev = isa_create(bus, "isa-parallel");
dev = DEVICE(isadev);
qdev_prop_set_uint32(dev, "index", index);
qdev_prop_set_chr(dev, "chardev", chr);
qdev_init_nofail(dev);
}
void parallel_hds_isa_init(ISABus *bus, int n)
{
int i;
assert(n <= MAX_PARALLEL_PORTS);
for (i = 0; i < n; i++) {
if (parallel_hds[i]) {
parallel_init(bus, i, parallel_hds[i]);
}
}
}

View File

@@ -28,7 +28,7 @@
#include "chardev/char-parallel.h"
#include "chardev/char-fe.h"
#include "hw/isa/isa.h"
#include "hw/char/parallel.h"
#include "hw/i386/pc.h"
#include "sysemu/sysemu.h"
//#define DEBUG_PARALLEL

View File

@@ -334,22 +334,6 @@ static bool machine_get_enforce_config_section(Object *obj, Error **errp)
return ms->enforce_config_section;
}
static char *machine_get_memory_encryption(Object *obj, Error **errp)
{
MachineState *ms = MACHINE(obj);
return g_strdup(ms->memory_encryption);
}
static void machine_set_memory_encryption(Object *obj, const char *value,
Error **errp)
{
MachineState *ms = MACHINE(obj);
g_free(ms->memory_encryption);
ms->memory_encryption = g_strdup(value);
}
void machine_class_allow_dynamic_sysbus_dev(MachineClass *mc, const char *type)
{
strList *item = g_new0(strList, 1);
@@ -628,12 +612,6 @@ static void machine_class_init(ObjectClass *oc, void *data)
&error_abort);
object_class_property_set_description(oc, "enforce-config-section",
"Set on to enforce configuration section migration", &error_abort);
object_class_property_add_str(oc, "memory-encryption",
machine_get_memory_encryption, machine_set_memory_encryption,
&error_abort);
object_class_property_set_description(oc, "memory-encryption",
"Set memory encyption object to use", &error_abort);
}
static void machine_class_base_init(ObjectClass *oc, void *data)

View File

@@ -24,9 +24,9 @@ static void machine_none_init(MachineState *mch)
{
CPUState *cpu = NULL;
/* Initialize CPU (if user asked for it) */
if (mch->cpu_type) {
cpu = cpu_create(mch->cpu_type);
/* Initialize CPU (if a model has been specified) */
if (mch->cpu_model) {
cpu = cpu_init(mch->cpu_model);
if (!cpu) {
error_report("Unable to initialize CPU");
exit(1);

View File

@@ -292,14 +292,6 @@ static void pci_secondary_vga_realize(PCIDevice *dev, Error **errp)
pci_register_bar(&d->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio);
}
static void pci_secondary_vga_exit(PCIDevice *dev)
{
PCIVGAState *d = PCI_VGA(dev);
VGACommonState *s = &d->vga;
graphic_console_close(s->con);
}
static void pci_secondary_vga_init(Object *obj)
{
/* Expose framebuffer byteorder via QOM */
@@ -369,7 +361,6 @@ static void secondary_class_init(ObjectClass *klass, void *data)
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->realize = pci_secondary_vga_realize;
k->exit = pci_secondary_vga_exit;
k->class_id = PCI_CLASS_DISPLAY_OTHER;
dc->props = secondary_pci_properties;
dc->reset = pci_secondary_vga_reset;

View File

@@ -24,7 +24,6 @@
#include "qemu/osdep.h"
#include "hw/isa/isa.h"
#include "hw/dma/i8257.h"
#define TYPE_I82374 "i82374"
#define I82374(obj) OBJECT_CHECK(I82374State, (obj), TYPE_I82374)
@@ -124,7 +123,7 @@ static void i82374_realize(DeviceState *dev, Error **errp)
portio_list_add(&s->port_list, isa_address_space_io(&s->parent_obj),
s->iobase);
i8257_dma_init(isa_bus_from_device(ISA_DEVICE(dev)), true);
DMA_init(isa_bus_from_device(ISA_DEVICE(dev)), 1);
memset(s->commands, 0, sizeof(s->commands));
}

View File

@@ -24,7 +24,7 @@
#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/isa/isa.h"
#include "hw/dma/i8257.h"
#include "hw/isa/i8257.h"
#include "qemu/main-loop.h"
#include "trace.h"
@@ -622,7 +622,7 @@ static void i8257_register_types(void)
type_init(i8257_register_types)
void i8257_dma_init(ISABus *bus, bool high_page_enable)
void DMA_init(ISABus *bus, int high_page_enable)
{
ISADevice *isa1, *isa2;
DeviceState *d;

View File

@@ -2,8 +2,8 @@ obj-$(CONFIG_KVM) += kvm/
obj-y += multiboot.o
obj-y += pc.o pc_piix.o pc_q35.o
obj-y += pc_sysfw.o
obj-$(CONFIG_VTD) += x86-iommu.o intel_iommu.o
obj-$(CONFIG_AMD_IOMMU) += x86-iommu.o amd_iommu.o
obj-y += x86-iommu.o intel_iommu.o
obj-y += amd_iommu.o
obj-$(CONFIG_XEN) += ../xenpv/ xen/
obj-$(CONFIG_VMPORT) += vmport.o
obj-$(CONFIG_VMMOUSE) += vmmouse.o

View File

@@ -91,11 +91,17 @@ typedef struct AcpiMcfgInfo {
} AcpiMcfgInfo;
typedef struct AcpiPmInfo {
bool force_rev1_fadt;
bool s3_disabled;
bool s4_disabled;
bool pcihp_bridge_en;
uint8_t s4_val;
AcpiFadtData fadt;
uint16_t sci_int;
uint8_t acpi_enable_cmd;
uint8_t acpi_disable_cmd;
uint32_t gpe0_blk;
uint32_t gpe0_blk_len;
uint32_t io_base;
uint16_t cpu_hp_io_base;
uint16_t pcihp_io_base;
uint16_t pcihp_io_len;
@@ -118,59 +124,21 @@ typedef struct AcpiBuildPciBusHotplugState {
bool pcihp_bridge_en;
} AcpiBuildPciBusHotplugState;
static void init_common_fadt_data(Object *o, AcpiFadtData *data)
{
uint32_t io = object_property_get_uint(o, ACPI_PM_PROP_PM_IO_BASE, NULL);
AmlAddressSpace as = AML_AS_SYSTEM_IO;
AcpiFadtData fadt = {
.rev = 3,
.flags =
(1 << ACPI_FADT_F_WBINVD) |
(1 << ACPI_FADT_F_PROC_C1) |
(1 << ACPI_FADT_F_SLP_BUTTON) |
(1 << ACPI_FADT_F_RTC_S4) |
(1 << ACPI_FADT_F_USE_PLATFORM_CLOCK) |
/* APIC destination mode ("Flat Logical") has an upper limit of 8
* CPUs for more than 8 CPUs, "Clustered Logical" mode has to be
* used
*/
((max_cpus > 8) ? (1 << ACPI_FADT_F_FORCE_APIC_CLUSTER_MODEL) : 0),
.int_model = 1 /* Multiple APIC */,
.rtc_century = RTC_CENTURY,
.plvl2_lat = 0xfff /* C2 state not supported */,
.plvl3_lat = 0xfff /* C3 state not supported */,
.smi_cmd = ACPI_PORT_SMI_CMD,
.sci_int = object_property_get_uint(o, ACPI_PM_PROP_SCI_INT, NULL),
.acpi_enable_cmd =
object_property_get_uint(o, ACPI_PM_PROP_ACPI_ENABLE_CMD, NULL),
.acpi_disable_cmd =
object_property_get_uint(o, ACPI_PM_PROP_ACPI_DISABLE_CMD, NULL),
.pm1a_evt = { .space_id = as, .bit_width = 4 * 8, .address = io },
.pm1a_cnt = { .space_id = as, .bit_width = 2 * 8,
.address = io + 0x04 },
.pm_tmr = { .space_id = as, .bit_width = 4 * 8, .address = io + 0x08 },
.gpe0_blk = { .space_id = as, .bit_width =
object_property_get_uint(o, ACPI_PM_PROP_GPE0_BLK_LEN, NULL) * 8,
.address = object_property_get_uint(o, ACPI_PM_PROP_GPE0_BLK, NULL)
},
};
*data = fadt;
}
static void acpi_get_pm_info(AcpiPmInfo *pm)
{
Object *piix = piix4_pm_find();
Object *lpc = ich9_lpc_find();
Object *obj = piix ? piix : lpc;
Object *obj = NULL;
QObject *o;
pm->force_rev1_fadt = false;
pm->cpu_hp_io_base = 0;
pm->pcihp_io_base = 0;
pm->pcihp_io_len = 0;
init_common_fadt_data(obj, &pm->fadt);
if (piix) {
/* w2k requires FADT(rev1) or it won't boot, keep PC compatible */
pm->fadt.rev = 1;
pm->force_rev1_fadt = true;
obj = piix;
pm->cpu_hp_io_base = PIIX4_CPU_HOTPLUG_IO_BASE;
pm->pcihp_io_base =
object_property_get_uint(obj, ACPI_PCIHP_IO_BASE_PROP, NULL);
@@ -178,42 +146,50 @@ static void acpi_get_pm_info(AcpiPmInfo *pm)
object_property_get_uint(obj, ACPI_PCIHP_IO_LEN_PROP, NULL);
}
if (lpc) {
struct AcpiGenericAddress r = { .space_id = AML_AS_SYSTEM_IO,
.bit_width = 8, .address = ICH9_RST_CNT_IOPORT };
pm->fadt.reset_reg = r;
pm->fadt.reset_val = 0xf;
pm->fadt.flags |= 1 << ACPI_FADT_F_RESET_REG_SUP;
obj = lpc;
pm->cpu_hp_io_base = ICH9_CPU_HOTPLUG_IO_BASE;
}
assert(obj);
/* The above need not be conditional on machine type because the reset port
* happens to be the same on PIIX (pc) and ICH9 (q35). */
QEMU_BUILD_BUG_ON(ICH9_RST_CNT_IOPORT != RCR_IOPORT);
/* Fill in optional s3/s4 related properties */
o = object_property_get_qobject(obj, ACPI_PM_PROP_S3_DISABLED, NULL);
if (o) {
pm->s3_disabled = qnum_get_uint(qobject_to(QNum, o));
pm->s3_disabled = qnum_get_uint(qobject_to_qnum(o));
} else {
pm->s3_disabled = false;
}
qobject_decref(o);
o = object_property_get_qobject(obj, ACPI_PM_PROP_S4_DISABLED, NULL);
if (o) {
pm->s4_disabled = qnum_get_uint(qobject_to(QNum, o));
pm->s4_disabled = qnum_get_uint(qobject_to_qnum(o));
} else {
pm->s4_disabled = false;
}
qobject_decref(o);
o = object_property_get_qobject(obj, ACPI_PM_PROP_S4_VAL, NULL);
if (o) {
pm->s4_val = qnum_get_uint(qobject_to(QNum, o));
pm->s4_val = qnum_get_uint(qobject_to_qnum(o));
} else {
pm->s4_val = false;
}
qobject_decref(o);
/* Fill in mandatory properties */
pm->sci_int = object_property_get_uint(obj, ACPI_PM_PROP_SCI_INT, NULL);
pm->acpi_enable_cmd = object_property_get_uint(obj,
ACPI_PM_PROP_ACPI_ENABLE_CMD,
NULL);
pm->acpi_disable_cmd =
object_property_get_uint(obj,
ACPI_PM_PROP_ACPI_DISABLE_CMD,
NULL);
pm->io_base = object_property_get_uint(obj, ACPI_PM_PROP_PM_IO_BASE,
NULL);
pm->gpe0_blk = object_property_get_uint(obj, ACPI_PM_PROP_GPE0_BLK,
NULL);
pm->gpe0_blk_len = object_property_get_uint(obj, ACPI_PM_PROP_GPE0_BLK_LEN,
NULL);
pm->pcihp_bridge_en =
object_property_get_bool(obj, "acpi-pci-hotplug-with-bridge-support",
NULL);
@@ -281,6 +257,8 @@ static void acpi_get_pci_holes(Range *hole, Range *hole64)
NULL));
}
#define ACPI_PORT_SMI_CMD 0x00b2 /* TODO: this is APM_CNT_IOPORT */
static void acpi_align_size(GArray *blob, unsigned align)
{
/* Align size to multiple of given size. This reduces the chance
@@ -298,6 +276,106 @@ build_facs(GArray *table_data, BIOSLinker *linker)
facs->length = cpu_to_le32(sizeof(*facs));
}
/* Load chipset information in FADT */
static void fadt_setup(AcpiFadtDescriptorRev3 *fadt, AcpiPmInfo *pm)
{
fadt->model = 1;
fadt->reserved1 = 0;
fadt->sci_int = cpu_to_le16(pm->sci_int);
fadt->smi_cmd = cpu_to_le32(ACPI_PORT_SMI_CMD);
fadt->acpi_enable = pm->acpi_enable_cmd;
fadt->acpi_disable = pm->acpi_disable_cmd;
/* EVT, CNT, TMR offset matches hw/acpi/core.c */
fadt->pm1a_evt_blk = cpu_to_le32(pm->io_base);
fadt->pm1a_cnt_blk = cpu_to_le32(pm->io_base + 0x04);
fadt->pm_tmr_blk = cpu_to_le32(pm->io_base + 0x08);
fadt->gpe0_blk = cpu_to_le32(pm->gpe0_blk);
/* EVT, CNT, TMR length matches hw/acpi/core.c */
fadt->pm1_evt_len = 4;
fadt->pm1_cnt_len = 2;
fadt->pm_tmr_len = 4;
fadt->gpe0_blk_len = pm->gpe0_blk_len;
fadt->plvl2_lat = cpu_to_le16(0xfff); /* C2 state not supported */
fadt->plvl3_lat = cpu_to_le16(0xfff); /* C3 state not supported */
fadt->flags = cpu_to_le32((1 << ACPI_FADT_F_WBINVD) |
(1 << ACPI_FADT_F_PROC_C1) |
(1 << ACPI_FADT_F_SLP_BUTTON) |
(1 << ACPI_FADT_F_RTC_S4));
fadt->flags |= cpu_to_le32(1 << ACPI_FADT_F_USE_PLATFORM_CLOCK);
/* APIC destination mode ("Flat Logical") has an upper limit of 8 CPUs
* For more than 8 CPUs, "Clustered Logical" mode has to be used
*/
if (max_cpus > 8) {
fadt->flags |= cpu_to_le32(1 << ACPI_FADT_F_FORCE_APIC_CLUSTER_MODEL);
}
fadt->century = RTC_CENTURY;
if (pm->force_rev1_fadt) {
return;
}
fadt->flags |= cpu_to_le32(1 << ACPI_FADT_F_RESET_REG_SUP);
fadt->reset_value = 0xf;
fadt->reset_register.space_id = AML_SYSTEM_IO;
fadt->reset_register.bit_width = 8;
fadt->reset_register.address = cpu_to_le64(ICH9_RST_CNT_IOPORT);
/* The above need not be conditional on machine type because the reset port
* happens to be the same on PIIX (pc) and ICH9 (q35). */
QEMU_BUILD_BUG_ON(ICH9_RST_CNT_IOPORT != RCR_IOPORT);
fadt->xpm1a_event_block.space_id = AML_SYSTEM_IO;
fadt->xpm1a_event_block.bit_width = fadt->pm1_evt_len * 8;
fadt->xpm1a_event_block.address = cpu_to_le64(pm->io_base);
fadt->xpm1a_control_block.space_id = AML_SYSTEM_IO;
fadt->xpm1a_control_block.bit_width = fadt->pm1_cnt_len * 8;
fadt->xpm1a_control_block.address = cpu_to_le64(pm->io_base + 0x4);
fadt->xpm_timer_block.space_id = AML_SYSTEM_IO;
fadt->xpm_timer_block.bit_width = fadt->pm_tmr_len * 8;
fadt->xpm_timer_block.address = cpu_to_le64(pm->io_base + 0x8);
fadt->xgpe0_block.space_id = AML_SYSTEM_IO;
fadt->xgpe0_block.bit_width = pm->gpe0_blk_len * 8;
fadt->xgpe0_block.address = cpu_to_le64(pm->gpe0_blk);
}
/* FADT */
static void
build_fadt(GArray *table_data, BIOSLinker *linker, AcpiPmInfo *pm,
unsigned facs_tbl_offset, unsigned dsdt_tbl_offset,
const char *oem_id, const char *oem_table_id)
{
AcpiFadtDescriptorRev3 *fadt = acpi_data_push(table_data, sizeof(*fadt));
unsigned fw_ctrl_offset = (char *)&fadt->firmware_ctrl - table_data->data;
unsigned dsdt_entry_offset = (char *)&fadt->dsdt - table_data->data;
unsigned xdsdt_entry_offset = (char *)&fadt->x_dsdt - table_data->data;
int fadt_size = sizeof(*fadt);
int rev = 3;
/* FACS address to be filled by Guest linker */
bios_linker_loader_add_pointer(linker,
ACPI_BUILD_TABLE_FILE, fw_ctrl_offset, sizeof(fadt->firmware_ctrl),
ACPI_BUILD_TABLE_FILE, facs_tbl_offset);
/* DSDT address to be filled by Guest linker */
fadt_setup(fadt, pm);
bios_linker_loader_add_pointer(linker,
ACPI_BUILD_TABLE_FILE, dsdt_entry_offset, sizeof(fadt->dsdt),
ACPI_BUILD_TABLE_FILE, dsdt_tbl_offset);
if (pm->force_rev1_fadt) {
rev = 1;
fadt_size = offsetof(typeof(*fadt), reset_register);
} else {
bios_linker_loader_add_pointer(linker,
ACPI_BUILD_TABLE_FILE, xdsdt_entry_offset, sizeof(fadt->x_dsdt),
ACPI_BUILD_TABLE_FILE, dsdt_tbl_offset);
}
build_header(linker, table_data,
(void *)fadt, "FACP", fadt_size, rev, oem_id, oem_table_id);
}
void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid,
const CPUArchIdList *apic_ids, GArray *entry)
{
@@ -429,14 +507,14 @@ static void build_append_pcihp_notify_entry(Aml *method, int slot)
static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus,
bool pcihp_bridge_en)
{
Aml *dev, *notify_method = NULL, *method;
Aml *dev, *notify_method, *method;
QObject *bsel;
PCIBus *sec;
int i;
bsel = object_property_get_qobject(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, NULL);
if (bsel) {
uint64_t bsel_val = qnum_get_uint(qobject_to(QNum, bsel));
uint64_t bsel_val = qnum_get_uint(qobject_to_qnum(bsel));
aml_append(parent_scope, aml_name_decl("BSEL", aml_int(bsel_val)));
notify_method = aml_method("DVNT", 2, AML_NOTSERIALIZED);
@@ -546,7 +624,7 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus,
/* If bus supports hotplug select it and notify about local events */
if (bsel) {
uint64_t bsel_val = qnum_get_uint(qobject_to(QNum, bsel));
uint64_t bsel_val = qnum_get_uint(qobject_to_qnum(bsel));
aml_append(method, aml_store(aml_int(bsel_val), aml_name("BNUM")));
aml_append(method,
@@ -1975,12 +2053,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
aml_append(dev, aml_name_decl("_STA", aml_int(0xB)));
crs = aml_resource_template();
aml_append(crs,
aml_io(
AML_DECODE16,
pm->fadt.gpe0_blk.address,
pm->fadt.gpe0_blk.address,
1,
pm->fadt.gpe0_blk.bit_width / 8)
aml_io(AML_DECODE16, pm->gpe0_blk, pm->gpe0_blk, 1, pm->gpe0_blk_len)
);
aml_append(dev, aml_name_decl("_CRS", crs));
aml_append(scope, dev);
@@ -2250,55 +2323,6 @@ build_tpm2(GArray *table_data, BIOSLinker *linker, GArray *tcpalog)
#define HOLE_640K_START (640 * 1024)
#define HOLE_640K_END (1024 * 1024)
static void build_srat_hotpluggable_memory(GArray *table_data, uint64_t base,
uint64_t len, int default_node)
{
MemoryDeviceInfoList *info_list = qmp_pc_dimm_device_list();
MemoryDeviceInfoList *info;
MemoryDeviceInfo *mi;
PCDIMMDeviceInfo *di;
uint64_t end = base + len, cur, size;
bool is_nvdimm;
AcpiSratMemoryAffinity *numamem;
MemoryAffinityFlags flags;
for (cur = base, info = info_list;
cur < end;
cur += size, info = info->next) {
numamem = acpi_data_push(table_data, sizeof *numamem);
if (!info) {
build_srat_memory(numamem, cur, end - cur, default_node,
MEM_AFFINITY_HOTPLUGGABLE | MEM_AFFINITY_ENABLED);
break;
}
mi = info->value;
is_nvdimm = (mi->type == MEMORY_DEVICE_INFO_KIND_NVDIMM);
di = !is_nvdimm ? mi->u.dimm.data : mi->u.nvdimm.data;
if (cur < di->addr) {
build_srat_memory(numamem, cur, di->addr - cur, default_node,
MEM_AFFINITY_HOTPLUGGABLE | MEM_AFFINITY_ENABLED);
numamem = acpi_data_push(table_data, sizeof *numamem);
}
size = di->size;
flags = MEM_AFFINITY_ENABLED;
if (di->hotpluggable) {
flags |= MEM_AFFINITY_HOTPLUGGABLE;
}
if (is_nvdimm) {
flags |= MEM_AFFINITY_NON_VOLATILE;
}
build_srat_memory(numamem, di->addr, size, di->node, flags);
}
qapi_free_MemoryDeviceInfoList(info_list);
}
static void
build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
{
@@ -2410,9 +2434,10 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
* providing _PXM method if necessary.
*/
if (hotplugabble_address_space_size) {
build_srat_hotpluggable_memory(table_data, pcms->hotplug_memory.base,
hotplugabble_address_space_size,
pcms->numa_nodes - 1);
numamem = acpi_data_push(table_data, sizeof *numamem);
build_srat_memory(numamem, pcms->hotplug_memory.base,
hotplugabble_address_space_size, pcms->numa_nodes - 1,
MEM_AFFINITY_HOTPLUGGABLE | MEM_AFFINITY_ENABLED);
}
build_header(linker, table_data,
@@ -2613,12 +2638,12 @@ static bool acpi_get_mcfg(AcpiMcfgInfo *mcfg)
if (!o) {
return false;
}
mcfg->mcfg_base = qnum_get_uint(qobject_to(QNum, o));
mcfg->mcfg_base = qnum_get_uint(qobject_to_qnum(o));
qobject_decref(o);
o = object_property_get_qobject(pci_host, PCIE_HOST_MCFG_SIZE, NULL);
assert(o);
mcfg->mcfg_size = qnum_get_uint(qobject_to(QNum, o));
mcfg->mcfg_size = qnum_get_uint(qobject_to_qnum(o));
qobject_decref(o);
return true;
}
@@ -2675,10 +2700,7 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
/* ACPI tables pointed to by RSDT */
fadt = tables_blob->len;
acpi_add_table(table_offsets, tables_blob);
pm.fadt.facs_tbl_offset = &facs;
pm.fadt.dsdt_tbl_offset = &dsdt;
pm.fadt.xdsdt_tbl_offset = &dsdt;
build_fadt(tables_blob, tables->linker, &pm.fadt,
build_fadt(tables_blob, tables->linker, &pm, facs, dsdt,
slic_oem.id, slic_oem.table_id);
aml_len += tables_blob->len - fadt;

View File

@@ -26,7 +26,6 @@
#include "hw/hw.h"
#include "hw/i386/pc.h"
#include "hw/char/serial.h"
#include "hw/char/parallel.h"
#include "hw/i386/apic.h"
#include "hw/i386/topology.h"
#include "sysemu/cpus.h"
@@ -41,9 +40,7 @@
#include "elf.h"
#include "multiboot.h"
#include "hw/timer/mc146818rtc.h"
#include "hw/dma/i8257.h"
#include "hw/timer/i8254.h"
#include "hw/input/i8042.h"
#include "hw/audio/pcspk.h"
#include "hw/pci/msi.h"
#include "hw/sysbus.h"
@@ -53,6 +50,8 @@
#include "sysemu/qtest.h"
#include "kvm_i386.h"
#include "hw/xen/xen.h"
#include "sysemu/block-backend.h"
#include "hw/block/block.h"
#include "ui/qemu-spice.h"
#include "exec/memory.h"
#include "exec/address-spaces.h"
@@ -1517,44 +1516,6 @@ static const MemoryRegionOps ioportF0_io_ops = {
},
};
static void pc_superio_init(ISABus *isa_bus, bool create_fdctrl, bool no_vmport)
{
int i;
DriveInfo *fd[MAX_FD];
qemu_irq *a20_line;
ISADevice *i8042, *port92, *vmmouse;
serial_hds_isa_init(isa_bus, 0, MAX_SERIAL_PORTS);
parallel_hds_isa_init(isa_bus, MAX_PARALLEL_PORTS);
for (i = 0; i < MAX_FD; i++) {
fd[i] = drive_get(IF_FLOPPY, 0, i);
create_fdctrl |= !!fd[i];
}
if (create_fdctrl) {
fdctrl_init_isa(isa_bus, fd);
}
i8042 = isa_create_simple(isa_bus, "i8042");
if (!no_vmport) {
vmport_init(isa_bus);
vmmouse = isa_try_create(isa_bus, "vmmouse");
} else {
vmmouse = NULL;
}
if (vmmouse) {
DeviceState *dev = DEVICE(vmmouse);
qdev_prop_set_ptr(dev, "ps2_mouse", i8042);
qdev_init_nofail(dev);
}
port92 = isa_create_simple(isa_bus, "port92");
a20_line = qemu_allocate_irqs(handle_a20_line_change, first_cpu, 2);
i8042_setup_a20_line(i8042, a20_line[0]);
port92_init(port92, a20_line[1]);
g_free(a20_line);
}
void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
ISADevice **rtc_state,
bool create_fdctrl,
@@ -1563,11 +1524,13 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
uint32_t hpet_irqs)
{
int i;
DriveInfo *fd[MAX_FD];
DeviceState *hpet = NULL;
int pit_isa_irq = 0;
qemu_irq pit_alt_irq = NULL;
qemu_irq rtc_irq = NULL;
ISADevice *pit = NULL;
qemu_irq *a20_line;
ISADevice *i8042, *port92, *vmmouse, *pit = NULL;
MemoryRegion *ioport80_io = g_new(MemoryRegion, 1);
MemoryRegion *ioportF0_io = g_new(MemoryRegion, 1);
@@ -1624,25 +1587,50 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
pcspk_init(isa_bus, pit);
}
i8257_dma_init(isa_bus, 0);
serial_hds_isa_init(isa_bus, 0, MAX_SERIAL_PORTS);
parallel_hds_isa_init(isa_bus, MAX_PARALLEL_PORTS);
/* Super I/O */
pc_superio_init(isa_bus, create_fdctrl, no_vmport);
a20_line = qemu_allocate_irqs(handle_a20_line_change, first_cpu, 2);
i8042 = isa_create_simple(isa_bus, "i8042");
i8042_setup_a20_line(i8042, a20_line[0]);
if (!no_vmport) {
vmport_init(isa_bus);
vmmouse = isa_try_create(isa_bus, "vmmouse");
} else {
vmmouse = NULL;
}
if (vmmouse) {
DeviceState *dev = DEVICE(vmmouse);
qdev_prop_set_ptr(dev, "ps2_mouse", i8042);
qdev_init_nofail(dev);
}
port92 = isa_create_simple(isa_bus, "port92");
port92_init(port92, a20_line[1]);
g_free(a20_line);
DMA_init(isa_bus, 0);
for(i = 0; i < MAX_FD; i++) {
fd[i] = drive_get(IF_FLOPPY, 0, i);
create_fdctrl |= !!fd[i];
}
if (create_fdctrl) {
fdctrl_init_isa(isa_bus, fd);
}
}
void pc_nic_init(PCMachineClass *pcmc, ISABus *isa_bus, PCIBus *pci_bus)
void pc_nic_init(ISABus *isa_bus, PCIBus *pci_bus)
{
int i;
rom_set_order_override(FW_CFG_ORDER_OVERRIDE_NIC);
for (i = 0; i < nb_nics; i++) {
NICInfo *nd = &nd_table[i];
const char *model = nd->model ? nd->model : pcmc->default_nic_model;
if (g_str_equal(model, "ne2k_isa")) {
if (!pci_bus || (nd->model && strcmp(nd->model, "ne2k_isa") == 0)) {
pc_init_ne2k_isa(isa_bus, nd);
} else {
pci_nic_init_nofail(nd, pci_bus, model, NULL);
pci_nic_init_nofail(nd, pci_bus, "e1000", NULL);
}
}
rom_reset_order_override();

View File

@@ -40,6 +40,7 @@
#include "sysemu/sysemu.h"
#include "hw/sysbus.h"
#include "sysemu/arch_init.h"
#include "sysemu/block-backend.h"
#include "hw/i2c/smbus.h"
#include "hw/xen/xen.h"
#include "exec/memory.h"
@@ -239,7 +240,7 @@ static void pc_init1(MachineState *machine,
pc_basic_device_init(isa_bus, pcms->gsi, &rtc_state, true,
(pcms->vmport != ON_OFF_AUTO_ON), pcms->pit, 0x4);
pc_nic_init(pcmc, isa_bus, pci_bus);
pc_nic_init(isa_bus, pci_bus);
ide_drive_get(hd, ARRAY_SIZE(hd));
if (pcmc->pci_enabled) {
@@ -416,9 +417,6 @@ static void pc_xen_hvm_init(MachineState *machine)
static void pc_i440fx_machine_options(MachineClass *m)
{
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
pcmc->default_nic_model = "e1000";
m->family = "pc_piix";
m->desc = "Standard PC (i440FX + PIIX, 1996)";
m->default_machine_opts = "firmware=bios-256k.bin";
@@ -1116,7 +1114,6 @@ static void isapc_machine_options(MachineClass *m)
pcmc->gigabyte_align = false;
pcmc->smbios_legacy_mode = true;
pcmc->has_reserved_memory = false;
pcmc->default_nic_model = "ne2k_isa";
m->default_cpu_type = X86_CPU_TYPE_NAME("486");
}

View File

@@ -272,7 +272,7 @@ static void pc_q35_init(MachineState *machine)
/* the rest devices to which pci devfn is automatically assigned */
pc_vga_init(isa_bus, host_bus);
pc_nic_init(pcmc, isa_bus, host_bus);
pc_nic_init(isa_bus, host_bus);
if (pcms->acpi_nvdimm_state.is_enabled) {
nvdimm_init_acpi_state(&pcms->acpi_nvdimm_state, system_io,
@@ -294,9 +294,6 @@ static void pc_q35_init(MachineState *machine)
static void pc_q35_machine_options(MachineClass *m)
{
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
pcmc->default_nic_model = "e1000e";
m->family = "pc_q35";
m->desc = "Standard PC (Q35 + ICH9, 2009)";
m->units_per_default_bus = 1;
@@ -319,10 +316,7 @@ DEFINE_Q35_MACHINE(v2_12, "pc-q35-2.12", NULL,
static void pc_q35_2_11_machine_options(MachineClass *m)
{
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
pc_q35_2_12_machine_options(m);
pcmc->default_nic_model = "e1000";
m->alias = NULL;
SET_MACHINE_COMPAT(m, PC_COMPAT_2_11);
}

View File

@@ -113,8 +113,6 @@ static void pc_system_flash_init(MemoryRegion *rom_memory)
pflash_t *system_flash;
MemoryRegion *flash_mem;
char name[64];
void *flash_ptr;
int ret, flash_size;
sector_bits = 12;
sector_size = 1 << sector_bits;
@@ -171,17 +169,6 @@ static void pc_system_flash_init(MemoryRegion *rom_memory)
if (unit == 0) {
flash_mem = pflash_cfi01_get_memory(system_flash);
pc_isa_bios_init(rom_memory, flash_mem, size);
/* Encrypt the pflash boot ROM */
if (kvm_memcrypt_enabled()) {
flash_ptr = memory_region_get_ram_ptr(flash_mem);
flash_size = memory_region_size(flash_mem);
ret = kvm_memcrypt_encrypt_data(flash_ptr, flash_size);
if (ret) {
error_report("failed to encrypt pflash rom");
exit(1);
}
}
}
}
}

View File

@@ -25,7 +25,6 @@
#include "hw/hw.h"
#include "ui/console.h"
#include "hw/i386/pc.h"
#include "hw/input/i8042.h"
#include "hw/qdev.h"
/* debug only vmmouse */

View File

@@ -25,7 +25,6 @@
#include "hw/hw.h"
#include "hw/isa/isa.h"
#include "hw/i386/pc.h"
#include "hw/input/i8042.h"
#include "sysemu/hw_accel.h"
#include "hw/qdev.h"
#include "qemu/log.h"

View File

@@ -18,6 +18,7 @@
#include "qemu/osdep.h"
#include "hw/hw.h"
#include "qemu/error-report.h"
#include "sysemu/block-backend.h"
#include "sysemu/dma.h"
#include "hw/ide/internal.h"
#include "hw/ide/ahci_internal.h"

View File

@@ -26,6 +26,7 @@
#include "hw/hw.h"
#include "hw/pci/pci.h"
#include "hw/isa/isa.h"
#include "sysemu/block-backend.h"
#include "sysemu/sysemu.h"
#include "sysemu/dma.h"

View File

@@ -65,6 +65,7 @@
#include "hw/pci/msi.h"
#include "hw/pci/pci.h"
#include "hw/isa/isa.h"
#include "sysemu/block-backend.h"
#include "sysemu/dma.h"
#include "hw/ide/pci.h"
#include "hw/ide/ahci_internal.h"

View File

@@ -25,6 +25,7 @@
#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/isa/isa.h"
#include "sysemu/block-backend.h"
#include "sysemu/dma.h"
#include "hw/ide/internal.h"

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