Compare commits
236 Commits
qemu-2.3.0
...
pull-gtk-2
Author | SHA1 | Date | |
---|---|---|---|
|
1271f7f7c6 | ||
|
dc7ff34418 | ||
|
1301e515ef | ||
|
b7fb49f0c7 | ||
|
cf1ecc82ab | ||
|
874e9aeeeb | ||
|
b4c5df7a15 | ||
|
e444ea34f8 | ||
|
0b71a5d5ca | ||
|
19dadfccd0 | ||
|
cd2bc889e5 | ||
|
985e1c9b00 | ||
|
2e1c92daff | ||
|
d98bc0b654 | ||
|
5bccbb04a4 | ||
|
f90f5b9a9a | ||
|
4a4d614ff5 | ||
|
498147529d | ||
|
c95e4c0e53 | ||
|
17f1e8f5ac | ||
|
abfe4e9408 | ||
|
d55053b16e | ||
|
e7c6e631b1 | ||
|
b457a5f54c | ||
|
553029351b | ||
|
4d850406a8 | ||
|
fee068e4f1 | ||
|
2ed0c3dad7 | ||
|
ab7c5aaf31 | ||
|
3ad9fd5a25 | ||
|
5403432f39 | ||
|
52a53afebd | ||
|
b1201addc7 | ||
|
63d229c32b | ||
|
dfbf272b77 | ||
|
c28e399cad | ||
|
93100f67c7 | ||
|
2161be35ce | ||
|
059ec9aa34 | ||
|
004f979fbb | ||
|
b133b09a9d | ||
|
19191a6bc5 | ||
|
a0970d91c9 | ||
|
f66759d3ae | ||
|
28507a415a | ||
|
d3e4abdddf | ||
|
5ecaa4ed88 | ||
|
ef1d27f4b1 | ||
|
3bf2af7b40 | ||
|
ec29ea1b2b | ||
|
26b93109c0 | ||
|
04768b985e | ||
|
9dcfda1298 | ||
|
825976153e | ||
|
c2cb2b041b | ||
|
29b558d877 | ||
|
1897b212b7 | ||
|
f2fbb40ea3 | ||
|
631b22ea20 | ||
|
c9f88ce330 | ||
|
9425c004fe | ||
|
4769a881cb | ||
|
494cb81741 | ||
|
4188e39055 | ||
|
4d1ba9c4f8 | ||
|
070c7607f6 | ||
|
2c80e996e4 | ||
|
6cb1e49de5 | ||
|
a9bcd1b871 | ||
|
f07177a559 | ||
|
7a52ce8a16 | ||
|
217a4acb21 | ||
|
b4ab4572b3 | ||
|
183f6b8d7e | ||
|
4d1866de94 | ||
|
cd20d61634 | ||
|
06feaacfb4 | ||
|
a1fe58f6ad | ||
|
d064d9f381 | ||
|
510a647fa2 | ||
|
b8eb5512fd | ||
|
7398dfc779 | ||
|
738e4171de | ||
|
2847b46958 | ||
|
c836867498 | ||
|
cf5aa89e9d | ||
|
72c85e949f | ||
|
ba4ed39346 | ||
|
8fe941f749 | ||
|
debaaa114a | ||
|
4e217074ca | ||
|
727be1a755 | ||
|
122fdf2d88 | ||
|
24a5c62cfe | ||
|
52b7aba62f | ||
|
5655f931ab | ||
|
c6d231e2fd | ||
|
07ceaf9880 | ||
|
a9392bc93c | ||
|
61007b316c | ||
|
0eb7217e49 | ||
|
e0c47b6cb1 | ||
|
4f5472cb2d | ||
|
7237aecd7e | ||
|
5505e8b76f | ||
|
001c95b740 | ||
|
59fc5d844f | ||
|
24618f5381 | ||
|
a3d715958c | ||
|
7898f74e78 | ||
|
9f7264f57c | ||
|
a94e87c08c | ||
|
ce1ffea8cd | ||
|
20dca81075 | ||
|
aa0c7ca506 | ||
|
a113534ffb | ||
|
e74e6b78e6 | ||
|
d58d845397 | ||
|
9bd2b08f27 | ||
|
b8e6fb752e | ||
|
be58721dbf | ||
|
8515efbef1 | ||
|
592fdd02ae | ||
|
341ebc2f81 | ||
|
5fba6c0e50 | ||
|
0db6e54a8a | ||
|
efcfa278dc | ||
|
9eac3622a2 | ||
|
03e40fef46 | ||
|
e380aff831 | ||
|
59dd0a22ca | ||
|
73b5394e2e | ||
|
752ce45150 | ||
|
7191f2080c | ||
|
0a386e4852 | ||
|
20474e9aa0 | ||
|
d5a8ee60a0 | ||
|
9419874f70 | ||
|
dc881b441d | ||
|
81e5f78a9f | ||
|
9b2aa84f87 | ||
|
ec683d6040 | ||
|
c485cf9c92 | ||
|
d07063e460 | ||
|
4eb867e98c | ||
|
0b5a24454f | ||
|
a7282330c0 | ||
|
e62303a437 | ||
|
69da3b0b47 | ||
|
751ebd76e6 | ||
|
199667a8c8 | ||
|
1c2b49a172 | ||
|
e5e51dd3af | ||
|
9eddd6a4b3 | ||
|
1faa5bb732 | ||
|
d1a126c53d | ||
|
8eedfbd4a5 | ||
|
e4f5874923 | ||
|
690c730160 | ||
|
0df89e8e6f | ||
|
a0710f7995 | ||
|
49110174f8 | ||
|
e98ab09709 | ||
|
de50a20a4c | ||
|
8b6ee9aeb3 | ||
|
f450a85899 | ||
|
41074f3d3f | ||
|
c9d9331851 | ||
|
bd2a88840e | ||
|
786a4ea82e | ||
|
5863d374a3 | ||
|
ad5f5fdca8 | ||
|
588ef9d411 | ||
|
ecdda9e03d | ||
|
407bc15033 | ||
|
84cbd63f87 | ||
|
54965ee61d | ||
|
da378d014d | ||
|
3d27b09cf6 | ||
|
726a8ff686 | ||
|
01431f3ce0 | ||
|
b9472b76d2 | ||
|
d9f7e29ee5 | ||
|
b203a4ba93 | ||
|
e1a0433956 | ||
|
3f9d69ba12 | ||
|
2f54eb98c3 | ||
|
0d81cdddaa | ||
|
23820dbfc7 | ||
|
4080a13c11 | ||
|
147ed37983 | ||
|
30476b2282 | ||
|
e477317cce | ||
|
54da54e543 | ||
|
3337d0b279 | ||
|
0e1cd6576c | ||
|
339240b5cd | ||
|
37d7c08413 | ||
|
e95205e1f9 | ||
|
33b6c2edf6 | ||
|
38e047b50d | ||
|
02f4035c47 | ||
|
c2cba0ffe4 | ||
|
e3a0abfda7 | ||
|
700cd855de | ||
|
dc8dceee64 | ||
|
d0df04a156 | ||
|
c1d37cd353 | ||
|
3b5704b2f8 | ||
|
1a01716a30 | ||
|
9d677e1c2f | ||
|
4eb2764083 | ||
|
3d5c84ff21 | ||
|
7ebd5f2e03 | ||
|
ef7bab8d73 | ||
|
9e1fc5bdfd | ||
|
0995bf8cd9 | ||
|
ebca90e4c3 | ||
|
8bf5b6a9c1 | ||
|
42874d3a8c | ||
|
66b9b43c42 | ||
|
500131154d | ||
|
5c9eb0286c | ||
|
f25a49e005 | ||
|
fadc1cbe85 | ||
|
e469b22ffd | ||
|
3b64349539 | ||
|
cc05c43ad9 | ||
|
e1a5476354 | ||
|
2d5a8346a4 | ||
|
43d0a2c1af | ||
|
6540e9f35b | ||
|
46abb81240 | ||
|
779ce88fbd | ||
|
f8c223f69a | ||
|
f98f43eab0 |
134
MAINTAINERS
134
MAINTAINERS
@@ -172,7 +172,8 @@ F: hw/unicore32/
|
||||
X86
|
||||
M: Paolo Bonzini <pbonzini@redhat.com>
|
||||
M: Richard Henderson <rth@twiddle.net>
|
||||
S: Odd Fixes
|
||||
M: Eduardo Habkost <ehabkost@redhat.com>
|
||||
S: Maintained
|
||||
F: target-i386/
|
||||
F: hw/i386/
|
||||
|
||||
@@ -703,10 +704,13 @@ F: tests/virtio-9p-test.c
|
||||
T: git git://github.com/kvaneesh/QEMU.git
|
||||
|
||||
virtio-blk
|
||||
M: Kevin Wolf <kwolf@redhat.com>
|
||||
M: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: hw/block/virtio-blk.c
|
||||
F: hw/block/dataplane/*
|
||||
F: hw/virtio/dataplane/*
|
||||
T: git git://github.com/stefanha/qemu.git block
|
||||
|
||||
virtio-ccw
|
||||
M: Cornelia Huck <cornelia.huck@de.ibm.com>
|
||||
@@ -731,12 +735,14 @@ F: backends/rng*.c
|
||||
|
||||
nvme
|
||||
M: Keith Busch <keith.busch@intel.com>
|
||||
L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: hw/block/nvme*
|
||||
F: tests/nvme-test.c
|
||||
|
||||
megasas
|
||||
M: Hannes Reinecke <hare@suse.de>
|
||||
L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: hw/scsi/megasas.c
|
||||
F: hw/scsi/mfi.h
|
||||
@@ -766,21 +772,26 @@ F: tests/ac97-test.c
|
||||
F: tests/es1370-test.c
|
||||
F: tests/intel-hda-test.c
|
||||
|
||||
Block
|
||||
Block layer core
|
||||
M: Kevin Wolf <kwolf@redhat.com>
|
||||
M: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: async.c
|
||||
F: aio-*.c
|
||||
F: block*
|
||||
F: block/
|
||||
F: hw/block/
|
||||
F: migration/block*
|
||||
F: qemu-img*
|
||||
F: qemu-io*
|
||||
F: tests/image-fuzzer/
|
||||
F: tests/qemu-iotests/
|
||||
T: git git://repo.or.cz/qemu/kevin.git block
|
||||
|
||||
Block I/O path
|
||||
M: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: async.c
|
||||
F: aio-*.c
|
||||
F: block/io.c
|
||||
F: migration/block*
|
||||
T: git git://github.com/stefanha/qemu.git block
|
||||
|
||||
Block Jobs
|
||||
@@ -905,6 +916,15 @@ F: nbd.*
|
||||
F: qemu-nbd.c
|
||||
T: git git://github.com/bonzini/qemu.git nbd-next
|
||||
|
||||
NUMA
|
||||
M: Eduardo Habkost <ehabkost@redhat.com>
|
||||
S: Maintained
|
||||
F: numa.c
|
||||
F: include/sysemu/numa.h
|
||||
K: numa|NUMA
|
||||
K: srat|SRAT
|
||||
T: git git://github.com/ehabkost/qemu.git numa
|
||||
|
||||
QAPI
|
||||
M: Luiz Capitulino <lcapitulino@redhat.com>
|
||||
M: Michael Roth <mdroth@linux.vnet.ibm.com>
|
||||
@@ -1094,6 +1114,7 @@ Block drivers
|
||||
-------------
|
||||
VMDK
|
||||
M: Fam Zheng <famz@redhat.com>
|
||||
L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: block/vmdk.c
|
||||
|
||||
@@ -1124,6 +1145,7 @@ T: git git://github.com/codyprime/qemu-kvm-jtc.git block
|
||||
|
||||
VDI
|
||||
M: Stefan Weil <sw@weilnetz.de>
|
||||
L: qemu-block@nongnu.org
|
||||
S: Maintained
|
||||
F: block/vdi.c
|
||||
|
||||
@@ -1131,6 +1153,7 @@ iSCSI
|
||||
M: Ronnie Sahlberg <ronniesahlberg@gmail.com>
|
||||
M: Paolo Bonzini <pbonzini@redhat.com>
|
||||
M: Peter Lieven <pl@kamp.de>
|
||||
L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: block/iscsi.c
|
||||
|
||||
@@ -1172,7 +1195,102 @@ S: Supported
|
||||
F: block/gluster.c
|
||||
T: git git://github.com/codyprime/qemu-kvm-jtc.git block
|
||||
|
||||
Null Block Driver
|
||||
M: Fam Zheng <famz@redhat.com>
|
||||
L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: block/null.c
|
||||
|
||||
Bootdevice
|
||||
M: Gonglei <arei.gonglei@huawei.com>
|
||||
S: Maintained
|
||||
F: bootdevice.c
|
||||
|
||||
Quorum
|
||||
M: Alberto Garcia <berto@igalia.com>
|
||||
S: Supported
|
||||
F: block/quorum.c
|
||||
L: qemu-block@nongnu.org
|
||||
|
||||
blkverify
|
||||
M: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: block/blkverify.c
|
||||
|
||||
bochs
|
||||
M: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: block/bochs.c
|
||||
|
||||
cloop
|
||||
M: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: block/cloop.c
|
||||
|
||||
dmg
|
||||
M: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: block/dmg.c
|
||||
|
||||
parallels
|
||||
M: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: block/parallels.c
|
||||
|
||||
qed
|
||||
M: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: block/qed.c
|
||||
|
||||
raw
|
||||
M: Kevin Wolf <kwolf@redhat.com>
|
||||
L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: block/linux-aio.c
|
||||
F: block/raw-aio.h
|
||||
F: block/raw-posix.c
|
||||
F: block/raw-win32.c
|
||||
F: block/raw_bsd.c
|
||||
F: block/win32-aio.c
|
||||
|
||||
qcow2
|
||||
M: Kevin Wolf <kwolf@redhat.com>
|
||||
L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: block/qcow2*
|
||||
|
||||
qcow
|
||||
M: Kevin Wolf <kwolf@redhat.com>
|
||||
L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: block/qcow.c
|
||||
|
||||
blkdebug
|
||||
M: Kevin Wolf <kwolf@redhat.com>
|
||||
L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: block/blkdebug.c
|
||||
|
||||
vpc
|
||||
M: Kevin Wolf <kwolf@redhat.com>
|
||||
L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: block/vpc.c
|
||||
|
||||
vvfat
|
||||
M: Kevin Wolf <kwolf@redhat.com>
|
||||
L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: block/vvfat.c
|
||||
|
||||
Image format fuzzer
|
||||
M: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: tests/image-fuzzer/
|
||||
|
17
Makefile
17
Makefile
@@ -296,6 +296,7 @@ clean:
|
||||
rm -f fsdev/*.pod
|
||||
rm -rf .libs */.libs
|
||||
rm -f qemu-img-cmds.h
|
||||
rm -f ui/shader/*-vert.h ui/shader/*-frag.h
|
||||
@# May not be present in GENERATED_HEADERS
|
||||
rm -f trace/generated-tracers-dtrace.dtrace*
|
||||
rm -f trace/generated-tracers-dtrace.h*
|
||||
@@ -441,6 +442,22 @@ cscope:
|
||||
find "$(SRC_PATH)" -name "*.[chsS]" -print | sed 's,^\./,,' > ./cscope.files
|
||||
cscope -b
|
||||
|
||||
# opengl shader programs
|
||||
ui/shader/%-vert.h: $(SRC_PATH)/ui/shader/%.vert $(SRC_PATH)/scripts/shaderinclude.pl
|
||||
@mkdir -p $(dir $@)
|
||||
$(call quiet-command,\
|
||||
perl $(SRC_PATH)/scripts/shaderinclude.pl $< > $@,\
|
||||
" VERT $@")
|
||||
|
||||
ui/shader/%-frag.h: $(SRC_PATH)/ui/shader/%.frag $(SRC_PATH)/scripts/shaderinclude.pl
|
||||
@mkdir -p $(dir $@)
|
||||
$(call quiet-command,\
|
||||
perl $(SRC_PATH)/scripts/shaderinclude.pl $< > $@,\
|
||||
" FRAG $@")
|
||||
|
||||
ui/console-gl.o: $(SRC_PATH)/ui/console-gl.c \
|
||||
ui/shader/texture-blit-vert.h ui/shader/texture-blit-frag.h
|
||||
|
||||
# documentation
|
||||
MAKEINFO=makeinfo
|
||||
MAKEINFOFLAGS=--no-headers --no-split --number-sections
|
||||
|
@@ -134,7 +134,7 @@ obj-$(CONFIG_KVM) += kvm-all.o
|
||||
obj-y += memory.o savevm.o cputlb.o
|
||||
obj-y += memory_mapping.o
|
||||
obj-y += dump.o
|
||||
LIBS+=$(libs_softmmu)
|
||||
LIBS := $(libs_softmmu) $(LIBS)
|
||||
|
||||
# xen support
|
||||
obj-$(CONFIG_XEN) += xen-common.o
|
||||
|
87
aio-posix.c
87
aio-posix.c
@@ -24,7 +24,6 @@ struct AioHandler
|
||||
IOHandler *io_read;
|
||||
IOHandler *io_write;
|
||||
int deleted;
|
||||
int pollfds_idx;
|
||||
void *opaque;
|
||||
QLIST_ENTRY(AioHandler) node;
|
||||
};
|
||||
@@ -83,7 +82,6 @@ void aio_set_fd_handler(AioContext *ctx,
|
||||
node->io_read = io_read;
|
||||
node->io_write = io_write;
|
||||
node->opaque = opaque;
|
||||
node->pollfds_idx = -1;
|
||||
|
||||
node->pfd.events = (io_read ? G_IO_IN | G_IO_HUP | G_IO_ERR : 0);
|
||||
node->pfd.events |= (io_write ? G_IO_OUT | G_IO_ERR : 0);
|
||||
@@ -186,13 +184,61 @@ bool aio_dispatch(AioContext *ctx)
|
||||
return progress;
|
||||
}
|
||||
|
||||
/* These thread-local variables are used only in a small part of aio_poll
|
||||
* around the call to the poll() system call. In particular they are not
|
||||
* used while aio_poll is performing callbacks, which makes it much easier
|
||||
* to think about reentrancy!
|
||||
*
|
||||
* Stack-allocated arrays would be perfect but they have size limitations;
|
||||
* heap allocation is expensive enough that we want to reuse arrays across
|
||||
* calls to aio_poll(). And because poll() has to be called without holding
|
||||
* any lock, the arrays cannot be stored in AioContext. Thread-local data
|
||||
* has none of the disadvantages of these three options.
|
||||
*/
|
||||
static __thread GPollFD *pollfds;
|
||||
static __thread AioHandler **nodes;
|
||||
static __thread unsigned npfd, nalloc;
|
||||
static __thread Notifier pollfds_cleanup_notifier;
|
||||
|
||||
static void pollfds_cleanup(Notifier *n, void *unused)
|
||||
{
|
||||
g_assert(npfd == 0);
|
||||
g_free(pollfds);
|
||||
g_free(nodes);
|
||||
nalloc = 0;
|
||||
}
|
||||
|
||||
static void add_pollfd(AioHandler *node)
|
||||
{
|
||||
if (npfd == nalloc) {
|
||||
if (nalloc == 0) {
|
||||
pollfds_cleanup_notifier.notify = pollfds_cleanup;
|
||||
qemu_thread_atexit_add(&pollfds_cleanup_notifier);
|
||||
nalloc = 8;
|
||||
} else {
|
||||
g_assert(nalloc <= INT_MAX);
|
||||
nalloc *= 2;
|
||||
}
|
||||
pollfds = g_renew(GPollFD, pollfds, nalloc);
|
||||
nodes = g_renew(AioHandler *, nodes, nalloc);
|
||||
}
|
||||
nodes[npfd] = node;
|
||||
pollfds[npfd] = (GPollFD) {
|
||||
.fd = node->pfd.fd,
|
||||
.events = node->pfd.events,
|
||||
};
|
||||
npfd++;
|
||||
}
|
||||
|
||||
bool aio_poll(AioContext *ctx, bool blocking)
|
||||
{
|
||||
AioHandler *node;
|
||||
bool was_dispatching;
|
||||
int ret;
|
||||
int i, ret;
|
||||
bool progress;
|
||||
int64_t timeout;
|
||||
|
||||
aio_context_acquire(ctx);
|
||||
was_dispatching = ctx->dispatching;
|
||||
progress = false;
|
||||
|
||||
@@ -210,39 +256,36 @@ bool aio_poll(AioContext *ctx, bool blocking)
|
||||
|
||||
ctx->walking_handlers++;
|
||||
|
||||
g_array_set_size(ctx->pollfds, 0);
|
||||
assert(npfd == 0);
|
||||
|
||||
/* fill pollfds */
|
||||
QLIST_FOREACH(node, &ctx->aio_handlers, node) {
|
||||
node->pollfds_idx = -1;
|
||||
if (!node->deleted && node->pfd.events) {
|
||||
GPollFD pfd = {
|
||||
.fd = node->pfd.fd,
|
||||
.events = node->pfd.events,
|
||||
};
|
||||
node->pollfds_idx = ctx->pollfds->len;
|
||||
g_array_append_val(ctx->pollfds, pfd);
|
||||
add_pollfd(node);
|
||||
}
|
||||
}
|
||||
|
||||
ctx->walking_handlers--;
|
||||
timeout = blocking ? aio_compute_timeout(ctx) : 0;
|
||||
|
||||
/* wait until next event */
|
||||
ret = qemu_poll_ns((GPollFD *)ctx->pollfds->data,
|
||||
ctx->pollfds->len,
|
||||
blocking ? aio_compute_timeout(ctx) : 0);
|
||||
if (timeout) {
|
||||
aio_context_release(ctx);
|
||||
}
|
||||
ret = qemu_poll_ns((GPollFD *)pollfds, npfd, timeout);
|
||||
if (timeout) {
|
||||
aio_context_acquire(ctx);
|
||||
}
|
||||
|
||||
/* if we have any readable fds, dispatch event */
|
||||
if (ret > 0) {
|
||||
QLIST_FOREACH(node, &ctx->aio_handlers, node) {
|
||||
if (node->pollfds_idx != -1) {
|
||||
GPollFD *pfd = &g_array_index(ctx->pollfds, GPollFD,
|
||||
node->pollfds_idx);
|
||||
node->pfd.revents = pfd->revents;
|
||||
}
|
||||
for (i = 0; i < npfd; i++) {
|
||||
nodes[i]->pfd.revents = pollfds[i].revents;
|
||||
}
|
||||
}
|
||||
|
||||
npfd = 0;
|
||||
ctx->walking_handlers--;
|
||||
|
||||
/* Run dispatch even if there were no readable fds to run timers */
|
||||
aio_set_dispatching(ctx, true);
|
||||
if (aio_dispatch(ctx)) {
|
||||
@@ -250,5 +293,7 @@ bool aio_poll(AioContext *ctx, bool blocking)
|
||||
}
|
||||
|
||||
aio_set_dispatching(ctx, was_dispatching);
|
||||
aio_context_release(ctx);
|
||||
|
||||
return progress;
|
||||
}
|
||||
|
@@ -283,6 +283,7 @@ bool aio_poll(AioContext *ctx, bool blocking)
|
||||
int count;
|
||||
int timeout;
|
||||
|
||||
aio_context_acquire(ctx);
|
||||
have_select_revents = aio_prepare(ctx);
|
||||
if (have_select_revents) {
|
||||
blocking = false;
|
||||
@@ -323,7 +324,13 @@ bool aio_poll(AioContext *ctx, bool blocking)
|
||||
|
||||
timeout = blocking
|
||||
? qemu_timeout_ns_to_ms(aio_compute_timeout(ctx)) : 0;
|
||||
if (timeout) {
|
||||
aio_context_release(ctx);
|
||||
}
|
||||
ret = WaitForMultipleObjects(count, events, FALSE, timeout);
|
||||
if (timeout) {
|
||||
aio_context_acquire(ctx);
|
||||
}
|
||||
aio_set_dispatching(ctx, true);
|
||||
|
||||
if (first && aio_bh_poll(ctx)) {
|
||||
@@ -349,5 +356,6 @@ bool aio_poll(AioContext *ctx, bool blocking)
|
||||
progress |= timerlistgroup_run_timers(&ctx->tlg);
|
||||
|
||||
aio_set_dispatching(ctx, was_dispatching);
|
||||
aio_context_release(ctx);
|
||||
return progress;
|
||||
}
|
||||
|
10
async.c
10
async.c
@@ -230,7 +230,6 @@ aio_ctx_finalize(GSource *source)
|
||||
event_notifier_cleanup(&ctx->notifier);
|
||||
rfifolock_destroy(&ctx->lock);
|
||||
qemu_mutex_destroy(&ctx->bh_lock);
|
||||
g_array_free(ctx->pollfds, TRUE);
|
||||
timerlistgroup_deinit(&ctx->tlg);
|
||||
}
|
||||
|
||||
@@ -281,12 +280,6 @@ static void aio_timerlist_notify(void *opaque)
|
||||
aio_notify(opaque);
|
||||
}
|
||||
|
||||
static void aio_rfifolock_cb(void *opaque)
|
||||
{
|
||||
/* Kick owner thread in case they are blocked in aio_poll() */
|
||||
aio_notify(opaque);
|
||||
}
|
||||
|
||||
AioContext *aio_context_new(Error **errp)
|
||||
{
|
||||
int ret;
|
||||
@@ -302,10 +295,9 @@ AioContext *aio_context_new(Error **errp)
|
||||
aio_set_event_notifier(ctx, &ctx->notifier,
|
||||
(EventNotifierHandler *)
|
||||
event_notifier_test_and_clear);
|
||||
ctx->pollfds = g_array_new(FALSE, FALSE, sizeof(GPollFD));
|
||||
ctx->thread_pool = NULL;
|
||||
qemu_mutex_init(&ctx->bh_lock);
|
||||
rfifolock_init(&ctx->lock, aio_rfifolock_cb, ctx);
|
||||
rfifolock_init(&ctx->lock, NULL, NULL);
|
||||
timerlistgroup_init(&ctx->tlg, aio_timerlist_notify, ctx);
|
||||
|
||||
return ctx;
|
||||
|
@@ -43,7 +43,7 @@ file_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
|
||||
return;
|
||||
}
|
||||
if (!fb->mem_path) {
|
||||
error_setg(errp, "mem_path property not set");
|
||||
error_setg(errp, "mem-path property not set");
|
||||
return;
|
||||
}
|
||||
#ifndef CONFIG_LINUX
|
||||
|
@@ -58,7 +58,6 @@ int qemu_add_balloon_handler(QEMUBalloonEvent *event_func,
|
||||
/* We're already registered one balloon handler. How many can
|
||||
* a guest really have?
|
||||
*/
|
||||
error_report("Another balloon device already registered");
|
||||
return -1;
|
||||
}
|
||||
balloon_event_fn = event_func;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
block-obj-y += raw_bsd.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o
|
||||
block-obj-y += raw_bsd.o qcow.o vdi.o vmdk.o cloop.o bochs.o vpc.o vvfat.o
|
||||
block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o
|
||||
block-obj-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o
|
||||
block-obj-y += qed-check.o
|
||||
@@ -9,7 +9,7 @@ block-obj-y += block-backend.o snapshot.o qapi.o
|
||||
block-obj-$(CONFIG_WIN32) += raw-win32.o win32-aio.o
|
||||
block-obj-$(CONFIG_POSIX) += raw-posix.o
|
||||
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
|
||||
block-obj-y += null.o mirror.o
|
||||
block-obj-y += null.o mirror.o io.o
|
||||
|
||||
block-obj-y += nbd.o nbd-client.o sheepdog.o
|
||||
block-obj-$(CONFIG_LIBISCSI) += iscsi.o
|
||||
@@ -37,6 +37,7 @@ gluster.o-libs := $(GLUSTERFS_LIBS)
|
||||
ssh.o-cflags := $(LIBSSH2_CFLAGS)
|
||||
ssh.o-libs := $(LIBSSH2_LIBS)
|
||||
archipelago.o-libs := $(ARCHIPELAGO_LIBS)
|
||||
block-obj-m += dmg.o
|
||||
dmg.o-libs := $(BZIP2_LIBS)
|
||||
qcow.o-libs := -lz
|
||||
linux-aio.o-libs := -laio
|
||||
|
155
block/backup.c
155
block/backup.c
@@ -37,6 +37,8 @@ typedef struct CowRequest {
|
||||
typedef struct BackupBlockJob {
|
||||
BlockJob common;
|
||||
BlockDriverState *target;
|
||||
/* bitmap for sync=dirty-bitmap */
|
||||
BdrvDirtyBitmap *sync_bitmap;
|
||||
MirrorSyncMode sync_mode;
|
||||
RateLimit limit;
|
||||
BlockdevOnError on_source_error;
|
||||
@@ -242,6 +244,91 @@ static void backup_complete(BlockJob *job, void *opaque)
|
||||
g_free(data);
|
||||
}
|
||||
|
||||
static bool coroutine_fn yield_and_check(BackupBlockJob *job)
|
||||
{
|
||||
if (block_job_is_cancelled(&job->common)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* we need to yield so that bdrv_drain_all() returns.
|
||||
* (without, VM does not reboot)
|
||||
*/
|
||||
if (job->common.speed) {
|
||||
uint64_t delay_ns = ratelimit_calculate_delay(&job->limit,
|
||||
job->sectors_read);
|
||||
job->sectors_read = 0;
|
||||
block_job_sleep_ns(&job->common, QEMU_CLOCK_REALTIME, delay_ns);
|
||||
} else {
|
||||
block_job_sleep_ns(&job->common, QEMU_CLOCK_REALTIME, 0);
|
||||
}
|
||||
|
||||
if (block_job_is_cancelled(&job->common)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int coroutine_fn backup_run_incremental(BackupBlockJob *job)
|
||||
{
|
||||
bool error_is_read;
|
||||
int ret = 0;
|
||||
int clusters_per_iter;
|
||||
uint32_t granularity;
|
||||
int64_t sector;
|
||||
int64_t cluster;
|
||||
int64_t end;
|
||||
int64_t last_cluster = -1;
|
||||
BlockDriverState *bs = job->common.bs;
|
||||
HBitmapIter hbi;
|
||||
|
||||
granularity = bdrv_dirty_bitmap_granularity(job->sync_bitmap);
|
||||
clusters_per_iter = MAX((granularity / BACKUP_CLUSTER_SIZE), 1);
|
||||
bdrv_dirty_iter_init(job->sync_bitmap, &hbi);
|
||||
|
||||
/* Find the next dirty sector(s) */
|
||||
while ((sector = hbitmap_iter_next(&hbi)) != -1) {
|
||||
cluster = sector / BACKUP_SECTORS_PER_CLUSTER;
|
||||
|
||||
/* Fake progress updates for any clusters we skipped */
|
||||
if (cluster != last_cluster + 1) {
|
||||
job->common.offset += ((cluster - last_cluster - 1) *
|
||||
BACKUP_CLUSTER_SIZE);
|
||||
}
|
||||
|
||||
for (end = cluster + clusters_per_iter; cluster < end; cluster++) {
|
||||
do {
|
||||
if (yield_and_check(job)) {
|
||||
return ret;
|
||||
}
|
||||
ret = backup_do_cow(bs, cluster * BACKUP_SECTORS_PER_CLUSTER,
|
||||
BACKUP_SECTORS_PER_CLUSTER, &error_is_read);
|
||||
if ((ret < 0) &&
|
||||
backup_error_action(job, error_is_read, -ret) ==
|
||||
BLOCK_ERROR_ACTION_REPORT) {
|
||||
return ret;
|
||||
}
|
||||
} while (ret < 0);
|
||||
}
|
||||
|
||||
/* If the bitmap granularity is smaller than the backup granularity,
|
||||
* we need to advance the iterator pointer to the next cluster. */
|
||||
if (granularity < BACKUP_CLUSTER_SIZE) {
|
||||
bdrv_set_dirty_iter(&hbi, cluster * BACKUP_SECTORS_PER_CLUSTER);
|
||||
}
|
||||
|
||||
last_cluster = cluster - 1;
|
||||
}
|
||||
|
||||
/* Play some final catchup with the progress meter */
|
||||
end = DIV_ROUND_UP(job->common.len, BACKUP_CLUSTER_SIZE);
|
||||
if (last_cluster + 1 < end) {
|
||||
job->common.offset += ((end - last_cluster - 1) * BACKUP_CLUSTER_SIZE);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void coroutine_fn backup_run(void *opaque)
|
||||
{
|
||||
BackupBlockJob *job = opaque;
|
||||
@@ -259,8 +346,7 @@ static void coroutine_fn backup_run(void *opaque)
|
||||
qemu_co_rwlock_init(&job->flush_rwlock);
|
||||
|
||||
start = 0;
|
||||
end = DIV_ROUND_UP(job->common.len / BDRV_SECTOR_SIZE,
|
||||
BACKUP_SECTORS_PER_CLUSTER);
|
||||
end = DIV_ROUND_UP(job->common.len, BACKUP_CLUSTER_SIZE);
|
||||
|
||||
job->bitmap = hbitmap_alloc(end, 0);
|
||||
|
||||
@@ -278,28 +364,13 @@ static void coroutine_fn backup_run(void *opaque)
|
||||
qemu_coroutine_yield();
|
||||
job->common.busy = true;
|
||||
}
|
||||
} else if (job->sync_mode == MIRROR_SYNC_MODE_DIRTY_BITMAP) {
|
||||
ret = backup_run_incremental(job);
|
||||
} else {
|
||||
/* Both FULL and TOP SYNC_MODE's require copying.. */
|
||||
for (; start < end; start++) {
|
||||
bool error_is_read;
|
||||
|
||||
if (block_job_is_cancelled(&job->common)) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* we need to yield so that qemu_aio_flush() returns.
|
||||
* (without, VM does not reboot)
|
||||
*/
|
||||
if (job->common.speed) {
|
||||
uint64_t delay_ns = ratelimit_calculate_delay(
|
||||
&job->limit, job->sectors_read);
|
||||
job->sectors_read = 0;
|
||||
block_job_sleep_ns(&job->common, QEMU_CLOCK_REALTIME, delay_ns);
|
||||
} else {
|
||||
block_job_sleep_ns(&job->common, QEMU_CLOCK_REALTIME, 0);
|
||||
}
|
||||
|
||||
if (block_job_is_cancelled(&job->common)) {
|
||||
if (yield_and_check(job)) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -357,6 +428,18 @@ static void coroutine_fn backup_run(void *opaque)
|
||||
qemu_co_rwlock_wrlock(&job->flush_rwlock);
|
||||
qemu_co_rwlock_unlock(&job->flush_rwlock);
|
||||
|
||||
if (job->sync_bitmap) {
|
||||
BdrvDirtyBitmap *bm;
|
||||
if (ret < 0) {
|
||||
/* Merge the successor back into the parent, delete nothing. */
|
||||
bm = bdrv_reclaim_dirty_bitmap(bs, job->sync_bitmap, NULL);
|
||||
assert(bm);
|
||||
} else {
|
||||
/* Everything is fine, delete this bitmap and install the backup. */
|
||||
bm = bdrv_dirty_bitmap_abdicate(bs, job->sync_bitmap, NULL);
|
||||
assert(bm);
|
||||
}
|
||||
}
|
||||
hbitmap_free(job->bitmap);
|
||||
|
||||
bdrv_iostatus_disable(target);
|
||||
@@ -369,6 +452,7 @@ static void coroutine_fn backup_run(void *opaque)
|
||||
|
||||
void backup_start(BlockDriverState *bs, BlockDriverState *target,
|
||||
int64_t speed, MirrorSyncMode sync_mode,
|
||||
BdrvDirtyBitmap *sync_bitmap,
|
||||
BlockdevOnError on_source_error,
|
||||
BlockdevOnError on_target_error,
|
||||
BlockCompletionFunc *cb, void *opaque,
|
||||
@@ -412,17 +496,36 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
|
||||
return;
|
||||
}
|
||||
|
||||
if (sync_mode == MIRROR_SYNC_MODE_DIRTY_BITMAP) {
|
||||
if (!sync_bitmap) {
|
||||
error_setg(errp, "must provide a valid bitmap name for "
|
||||
"\"dirty-bitmap\" sync mode");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Create a new bitmap, and freeze/disable this one. */
|
||||
if (bdrv_dirty_bitmap_create_successor(bs, sync_bitmap, errp) < 0) {
|
||||
return;
|
||||
}
|
||||
} else if (sync_bitmap) {
|
||||
error_setg(errp,
|
||||
"a sync_bitmap was provided to backup_run, "
|
||||
"but received an incompatible sync_mode (%s)",
|
||||
MirrorSyncMode_lookup[sync_mode]);
|
||||
return;
|
||||
}
|
||||
|
||||
len = bdrv_getlength(bs);
|
||||
if (len < 0) {
|
||||
error_setg_errno(errp, -len, "unable to get length for '%s'",
|
||||
bdrv_get_device_name(bs));
|
||||
return;
|
||||
goto error;
|
||||
}
|
||||
|
||||
BackupBlockJob *job = block_job_create(&backup_job_driver, bs, speed,
|
||||
cb, opaque, errp);
|
||||
if (!job) {
|
||||
return;
|
||||
goto error;
|
||||
}
|
||||
|
||||
bdrv_op_block_all(target, job->common.blocker);
|
||||
@@ -431,7 +534,15 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
|
||||
job->on_target_error = on_target_error;
|
||||
job->target = target;
|
||||
job->sync_mode = sync_mode;
|
||||
job->sync_bitmap = sync_mode == MIRROR_SYNC_MODE_DIRTY_BITMAP ?
|
||||
sync_bitmap : NULL;
|
||||
job->common.len = len;
|
||||
job->common.co = qemu_coroutine_create(backup_run);
|
||||
qemu_coroutine_enter(job->common.co, job);
|
||||
return;
|
||||
|
||||
error:
|
||||
if (sync_bitmap) {
|
||||
bdrv_reclaim_dirty_bitmap(bs, sync_bitmap, NULL);
|
||||
}
|
||||
}
|
||||
|
@@ -721,6 +721,11 @@ static int64_t blkdebug_getlength(BlockDriverState *bs)
|
||||
return bdrv_getlength(bs->file);
|
||||
}
|
||||
|
||||
static int blkdebug_truncate(BlockDriverState *bs, int64_t offset)
|
||||
{
|
||||
return bdrv_truncate(bs->file, offset);
|
||||
}
|
||||
|
||||
static void blkdebug_refresh_filename(BlockDriverState *bs)
|
||||
{
|
||||
QDict *opts;
|
||||
@@ -779,6 +784,7 @@ static BlockDriver bdrv_blkdebug = {
|
||||
.bdrv_file_open = blkdebug_open,
|
||||
.bdrv_close = blkdebug_close,
|
||||
.bdrv_getlength = blkdebug_getlength,
|
||||
.bdrv_truncate = blkdebug_truncate,
|
||||
.bdrv_refresh_filename = blkdebug_refresh_filename,
|
||||
|
||||
.bdrv_aio_readv = blkdebug_aio_readv,
|
||||
|
@@ -515,6 +515,17 @@ int blk_write(BlockBackend *blk, int64_t sector_num, const uint8_t *buf,
|
||||
return bdrv_write(blk->bs, sector_num, buf, nb_sectors);
|
||||
}
|
||||
|
||||
int blk_write_zeroes(BlockBackend *blk, int64_t sector_num,
|
||||
int nb_sectors, BdrvRequestFlags flags)
|
||||
{
|
||||
int ret = blk_check_request(blk, sector_num, nb_sectors);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return bdrv_write_zeroes(blk->bs, sector_num, nb_sectors, flags);
|
||||
}
|
||||
|
||||
static void error_callback_bh(void *opaque)
|
||||
{
|
||||
struct BlockBackendAIOCB *acb = opaque;
|
||||
|
2540
block/io.c
Normal file
2540
block/io.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
||||
* QEMU Block driver for iSCSI images
|
||||
*
|
||||
* Copyright (c) 2010-2011 Ronnie Sahlberg <ronniesahlberg@gmail.com>
|
||||
* Copyright (c) 2012-2014 Peter Lieven <pl@kamp.de>
|
||||
* Copyright (c) 2012-2015 Peter Lieven <pl@kamp.de>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -57,9 +57,6 @@ typedef struct IscsiLun {
|
||||
int events;
|
||||
QEMUTimer *nop_timer;
|
||||
QEMUTimer *event_timer;
|
||||
uint8_t lbpme;
|
||||
uint8_t lbprz;
|
||||
uint8_t has_write_same;
|
||||
struct scsi_inquiry_logical_block_provisioning lbp;
|
||||
struct scsi_inquiry_block_limits bl;
|
||||
unsigned char *zeroblock;
|
||||
@@ -67,6 +64,11 @@ typedef struct IscsiLun {
|
||||
int cluster_sectors;
|
||||
bool use_16_for_rw;
|
||||
bool write_protected;
|
||||
bool lbpme;
|
||||
bool lbprz;
|
||||
bool dpofua;
|
||||
bool has_write_same;
|
||||
bool force_next_flush;
|
||||
} IscsiLun;
|
||||
|
||||
typedef struct IscsiTask {
|
||||
@@ -79,6 +81,7 @@ typedef struct IscsiTask {
|
||||
QEMUBH *bh;
|
||||
IscsiLun *iscsilun;
|
||||
QEMUTimer retry_timer;
|
||||
bool force_next_flush;
|
||||
} IscsiTask;
|
||||
|
||||
typedef struct IscsiAIOCB {
|
||||
@@ -100,7 +103,7 @@ typedef struct IscsiAIOCB {
|
||||
#define NOP_INTERVAL 5000
|
||||
#define MAX_NOP_FAILURES 3
|
||||
#define ISCSI_CMD_RETRIES ARRAY_SIZE(iscsi_retry_times)
|
||||
static const unsigned iscsi_retry_times[] = {8, 32, 128, 512, 2048};
|
||||
static const unsigned iscsi_retry_times[] = {8, 32, 128, 512, 2048, 8192, 32768};
|
||||
|
||||
/* this threshold is a trade-off knob to choose between
|
||||
* the potential additional overhead of an extra GET_LBA_STATUS request
|
||||
@@ -183,10 +186,13 @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status,
|
||||
iTask->do_retry = 1;
|
||||
goto out;
|
||||
}
|
||||
if (status == SCSI_STATUS_BUSY) {
|
||||
/* status 0x28 is SCSI_TASK_SET_FULL. It was first introduced
|
||||
* in libiscsi 1.10.0. Hardcode this value here to avoid
|
||||
* the need to bump the libiscsi requirement to 1.10.0 */
|
||||
if (status == SCSI_STATUS_BUSY || status == 0x28) {
|
||||
unsigned retry_time =
|
||||
exp_random(iscsi_retry_times[iTask->retries - 1]);
|
||||
error_report("iSCSI Busy (retry #%u in %u ms): %s",
|
||||
error_report("iSCSI Busy/TaskSetFull (retry #%u in %u ms): %s",
|
||||
iTask->retries, retry_time,
|
||||
iscsi_get_error(iscsi));
|
||||
aio_timer_init(iTask->iscsilun->aio_context,
|
||||
@@ -199,6 +205,8 @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status,
|
||||
}
|
||||
}
|
||||
error_report("iSCSI Failure: %s", iscsi_get_error(iscsi));
|
||||
} else {
|
||||
iTask->iscsilun->force_next_flush |= iTask->force_next_flush;
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -369,6 +377,7 @@ static int coroutine_fn iscsi_co_writev(BlockDriverState *bs,
|
||||
struct IscsiTask iTask;
|
||||
uint64_t lba;
|
||||
uint32_t num_sectors;
|
||||
int fua;
|
||||
|
||||
if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
|
||||
return -EINVAL;
|
||||
@@ -384,15 +393,17 @@ static int coroutine_fn iscsi_co_writev(BlockDriverState *bs,
|
||||
num_sectors = sector_qemu2lun(nb_sectors, iscsilun);
|
||||
iscsi_co_init_iscsitask(iscsilun, &iTask);
|
||||
retry:
|
||||
fua = iscsilun->dpofua && !bs->enable_write_cache;
|
||||
iTask.force_next_flush = !fua;
|
||||
if (iscsilun->use_16_for_rw) {
|
||||
iTask.task = iscsi_write16_task(iscsilun->iscsi, iscsilun->lun, lba,
|
||||
NULL, num_sectors * iscsilun->block_size,
|
||||
iscsilun->block_size, 0, 0, 0, 0, 0,
|
||||
iscsilun->block_size, 0, 0, fua, 0, 0,
|
||||
iscsi_co_generic_cb, &iTask);
|
||||
} else {
|
||||
iTask.task = iscsi_write10_task(iscsilun->iscsi, iscsilun->lun, lba,
|
||||
NULL, num_sectors * iscsilun->block_size,
|
||||
iscsilun->block_size, 0, 0, 0, 0, 0,
|
||||
iscsilun->block_size, 0, 0, fua, 0, 0,
|
||||
iscsi_co_generic_cb, &iTask);
|
||||
}
|
||||
if (iTask.task == NULL) {
|
||||
@@ -460,7 +471,7 @@ static int64_t coroutine_fn iscsi_co_get_block_status(BlockDriverState *bs,
|
||||
*pnum = nb_sectors;
|
||||
|
||||
/* LUN does not support logical block provisioning */
|
||||
if (iscsilun->lbpme == 0) {
|
||||
if (!iscsilun->lbpme) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -620,8 +631,12 @@ static int coroutine_fn iscsi_co_flush(BlockDriverState *bs)
|
||||
return 0;
|
||||
}
|
||||
|
||||
iscsi_co_init_iscsitask(iscsilun, &iTask);
|
||||
if (!iscsilun->force_next_flush) {
|
||||
return 0;
|
||||
}
|
||||
iscsilun->force_next_flush = false;
|
||||
|
||||
iscsi_co_init_iscsitask(iscsilun, &iTask);
|
||||
retry:
|
||||
if (iscsi_synchronizecache10_task(iscsilun->iscsi, iscsilun->lun, 0, 0, 0,
|
||||
0, iscsi_co_generic_cb, &iTask) == NULL) {
|
||||
@@ -917,6 +932,7 @@ coroutine_fn iscsi_co_write_zeroes(BlockDriverState *bs, int64_t sector_num,
|
||||
}
|
||||
|
||||
iscsi_co_init_iscsitask(iscsilun, &iTask);
|
||||
iTask.force_next_flush = true;
|
||||
retry:
|
||||
if (use_16_for_ws) {
|
||||
iTask.task = iscsi_writesame16_task(iscsilun->iscsi, iscsilun->lun, lba,
|
||||
@@ -1121,8 +1137,8 @@ static void iscsi_readcapacity_sync(IscsiLun *iscsilun, Error **errp)
|
||||
} else {
|
||||
iscsilun->block_size = rc16->block_length;
|
||||
iscsilun->num_blocks = rc16->returned_lba + 1;
|
||||
iscsilun->lbpme = rc16->lbpme;
|
||||
iscsilun->lbprz = rc16->lbprz;
|
||||
iscsilun->lbpme = !!rc16->lbpme;
|
||||
iscsilun->lbprz = !!rc16->lbprz;
|
||||
iscsilun->use_16_for_rw = (rc16->returned_lba > 0xffffffff);
|
||||
}
|
||||
}
|
||||
@@ -1253,11 +1269,12 @@ static void iscsi_attach_aio_context(BlockDriverState *bs,
|
||||
iscsi_timed_set_events, iscsilun);
|
||||
}
|
||||
|
||||
static bool iscsi_is_write_protected(IscsiLun *iscsilun)
|
||||
static void iscsi_modesense_sync(IscsiLun *iscsilun)
|
||||
{
|
||||
struct scsi_task *task;
|
||||
struct scsi_mode_sense *ms = NULL;
|
||||
bool wrprotected = false;
|
||||
iscsilun->write_protected = false;
|
||||
iscsilun->dpofua = false;
|
||||
|
||||
task = iscsi_modesense6_sync(iscsilun->iscsi, iscsilun->lun,
|
||||
1, SCSI_MODESENSE_PC_CURRENT,
|
||||
@@ -1278,13 +1295,13 @@ static bool iscsi_is_write_protected(IscsiLun *iscsilun)
|
||||
iscsi_get_error(iscsilun->iscsi));
|
||||
goto out;
|
||||
}
|
||||
wrprotected = ms->device_specific_parameter & 0x80;
|
||||
iscsilun->write_protected = ms->device_specific_parameter & 0x80;
|
||||
iscsilun->dpofua = ms->device_specific_parameter & 0x10;
|
||||
|
||||
out:
|
||||
if (task) {
|
||||
scsi_free_scsi_task(task);
|
||||
}
|
||||
return wrprotected;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1403,7 +1420,8 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
scsi_free_scsi_task(task);
|
||||
task = NULL;
|
||||
|
||||
iscsilun->write_protected = iscsi_is_write_protected(iscsilun);
|
||||
iscsi_modesense_sync(iscsilun);
|
||||
|
||||
/* Check the write protect flag of the LUN if we want to write */
|
||||
if (iscsilun->type == TYPE_DISK && (flags & BDRV_O_RDWR) &&
|
||||
iscsilun->write_protected) {
|
||||
@@ -1481,7 +1499,7 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
iscsilun->bl.opt_unmap_gran * iscsilun->block_size <= 16 * 1024 * 1024) {
|
||||
iscsilun->cluster_sectors = (iscsilun->bl.opt_unmap_gran *
|
||||
iscsilun->block_size) >> BDRV_SECTOR_BITS;
|
||||
if (iscsilun->lbprz && !(bs->open_flags & BDRV_O_NOCACHE)) {
|
||||
if (iscsilun->lbprz) {
|
||||
iscsilun->allocationmap = iscsi_allocationmap_init(iscsilun);
|
||||
if (iscsilun->allocationmap == NULL) {
|
||||
ret = -ENOMEM;
|
||||
@@ -1501,6 +1519,9 @@ out:
|
||||
|
||||
if (ret) {
|
||||
if (iscsi != NULL) {
|
||||
if (iscsi_is_logged_in(iscsi)) {
|
||||
iscsi_logout_sync(iscsi);
|
||||
}
|
||||
iscsi_destroy_context(iscsi);
|
||||
}
|
||||
memset(iscsilun, 0, sizeof(IscsiLun));
|
||||
@@ -1514,6 +1535,9 @@ static void iscsi_close(BlockDriverState *bs)
|
||||
struct iscsi_context *iscsi = iscsilun->iscsi;
|
||||
|
||||
iscsi_detach_aio_context(bs);
|
||||
if (iscsi_is_logged_in(iscsi)) {
|
||||
iscsi_logout_sync(iscsi);
|
||||
}
|
||||
iscsi_destroy_context(iscsi);
|
||||
g_free(iscsilun->zeroblock);
|
||||
g_free(iscsilun->allocationmap);
|
||||
@@ -1649,7 +1673,7 @@ out:
|
||||
static int iscsi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||
{
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
bdi->unallocated_blocks_are_zero = !!iscsilun->lbprz;
|
||||
bdi->unallocated_blocks_are_zero = iscsilun->lbprz;
|
||||
bdi->can_write_zeroes_with_unmap = iscsilun->lbprz && iscsilun->lbp.lbpws;
|
||||
bdi->cluster_size = iscsilun->cluster_sectors * BDRV_SECTOR_SIZE;
|
||||
return 0;
|
||||
|
@@ -125,11 +125,9 @@ static void mirror_write_complete(void *opaque, int ret)
|
||||
MirrorOp *op = opaque;
|
||||
MirrorBlockJob *s = op->s;
|
||||
if (ret < 0) {
|
||||
BlockDriverState *source = s->common.bs;
|
||||
BlockErrorAction action;
|
||||
|
||||
bdrv_set_dirty_bitmap(source, s->dirty_bitmap, op->sector_num,
|
||||
op->nb_sectors);
|
||||
bdrv_set_dirty_bitmap(s->dirty_bitmap, op->sector_num, op->nb_sectors);
|
||||
action = mirror_error_action(s, false, -ret);
|
||||
if (action == BLOCK_ERROR_ACTION_REPORT && s->ret >= 0) {
|
||||
s->ret = ret;
|
||||
@@ -143,11 +141,9 @@ static void mirror_read_complete(void *opaque, int ret)
|
||||
MirrorOp *op = opaque;
|
||||
MirrorBlockJob *s = op->s;
|
||||
if (ret < 0) {
|
||||
BlockDriverState *source = s->common.bs;
|
||||
BlockErrorAction action;
|
||||
|
||||
bdrv_set_dirty_bitmap(source, s->dirty_bitmap, op->sector_num,
|
||||
op->nb_sectors);
|
||||
bdrv_set_dirty_bitmap(s->dirty_bitmap, op->sector_num, op->nb_sectors);
|
||||
action = mirror_error_action(s, true, -ret);
|
||||
if (action == BLOCK_ERROR_ACTION_REPORT && s->ret >= 0) {
|
||||
s->ret = ret;
|
||||
@@ -170,10 +166,9 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
|
||||
|
||||
s->sector_num = hbitmap_iter_next(&s->hbi);
|
||||
if (s->sector_num < 0) {
|
||||
bdrv_dirty_iter_init(source, s->dirty_bitmap, &s->hbi);
|
||||
bdrv_dirty_iter_init(s->dirty_bitmap, &s->hbi);
|
||||
s->sector_num = hbitmap_iter_next(&s->hbi);
|
||||
trace_mirror_restart_iter(s,
|
||||
bdrv_get_dirty_count(source, s->dirty_bitmap));
|
||||
trace_mirror_restart_iter(s, bdrv_get_dirty_count(s->dirty_bitmap));
|
||||
assert(s->sector_num >= 0);
|
||||
}
|
||||
|
||||
@@ -288,8 +283,7 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
|
||||
next_sector += sectors_per_chunk;
|
||||
}
|
||||
|
||||
bdrv_reset_dirty_bitmap(source, s->dirty_bitmap, sector_num,
|
||||
nb_sectors);
|
||||
bdrv_reset_dirty_bitmap(s->dirty_bitmap, sector_num, nb_sectors);
|
||||
|
||||
/* Copy the dirty cluster. */
|
||||
s->in_flight++;
|
||||
@@ -446,7 +440,7 @@ static void coroutine_fn mirror_run(void *opaque)
|
||||
|
||||
assert(n > 0);
|
||||
if (ret == 1) {
|
||||
bdrv_set_dirty_bitmap(bs, s->dirty_bitmap, sector_num, n);
|
||||
bdrv_set_dirty_bitmap(s->dirty_bitmap, sector_num, n);
|
||||
sector_num = next;
|
||||
} else {
|
||||
sector_num += n;
|
||||
@@ -454,7 +448,7 @@ static void coroutine_fn mirror_run(void *opaque)
|
||||
}
|
||||
}
|
||||
|
||||
bdrv_dirty_iter_init(bs, s->dirty_bitmap, &s->hbi);
|
||||
bdrv_dirty_iter_init(s->dirty_bitmap, &s->hbi);
|
||||
last_pause_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
|
||||
for (;;) {
|
||||
uint64_t delay_ns = 0;
|
||||
@@ -466,7 +460,7 @@ static void coroutine_fn mirror_run(void *opaque)
|
||||
goto immediate_exit;
|
||||
}
|
||||
|
||||
cnt = bdrv_get_dirty_count(bs, s->dirty_bitmap);
|
||||
cnt = bdrv_get_dirty_count(s->dirty_bitmap);
|
||||
/* s->common.offset contains the number of bytes already processed so
|
||||
* far, cnt is the number of dirty sectors remaining and
|
||||
* s->sectors_in_flight is the number of sectors currently being
|
||||
@@ -475,7 +469,7 @@ static void coroutine_fn mirror_run(void *opaque)
|
||||
(cnt + s->sectors_in_flight) * BDRV_SECTOR_SIZE;
|
||||
|
||||
/* Note that even when no rate limit is applied we need to yield
|
||||
* periodically with no pending I/O so that qemu_aio_flush() returns.
|
||||
* periodically with no pending I/O so that bdrv_drain_all() returns.
|
||||
* We do so every SLICE_TIME nanoseconds, or when there is an error,
|
||||
* or when the source is clean, whichever comes first.
|
||||
*/
|
||||
@@ -488,9 +482,6 @@ static void coroutine_fn mirror_run(void *opaque)
|
||||
continue;
|
||||
} else if (cnt != 0) {
|
||||
delay_ns = mirror_iteration(s);
|
||||
if (delay_ns == 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -516,7 +507,7 @@ static void coroutine_fn mirror_run(void *opaque)
|
||||
|
||||
should_complete = s->should_complete ||
|
||||
block_job_is_cancelled(&s->common);
|
||||
cnt = bdrv_get_dirty_count(bs, s->dirty_bitmap);
|
||||
cnt = bdrv_get_dirty_count(s->dirty_bitmap);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -531,7 +522,7 @@ static void coroutine_fn mirror_run(void *opaque)
|
||||
*/
|
||||
trace_mirror_before_drain(s, cnt);
|
||||
bdrv_drain(bs);
|
||||
cnt = bdrv_get_dirty_count(bs, s->dirty_bitmap);
|
||||
cnt = bdrv_get_dirty_count(s->dirty_bitmap);
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
@@ -634,7 +625,7 @@ static void mirror_complete(BlockJob *job, Error **errp)
|
||||
}
|
||||
|
||||
s->should_complete = true;
|
||||
block_job_resume(job);
|
||||
block_job_enter(&s->common);
|
||||
}
|
||||
|
||||
static const BlockJobDriver mirror_job_driver = {
|
||||
@@ -656,7 +647,7 @@ static const BlockJobDriver commit_active_job_driver = {
|
||||
|
||||
static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target,
|
||||
const char *replaces,
|
||||
int64_t speed, int64_t granularity,
|
||||
int64_t speed, uint32_t granularity,
|
||||
int64_t buf_size,
|
||||
BlockdevOnError on_source_error,
|
||||
BlockdevOnError on_target_error,
|
||||
@@ -668,15 +659,7 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target,
|
||||
MirrorBlockJob *s;
|
||||
|
||||
if (granularity == 0) {
|
||||
/* Choose the default granularity based on the target file's cluster
|
||||
* size, clamped between 4k and 64k. */
|
||||
BlockDriverInfo bdi;
|
||||
if (bdrv_get_info(target, &bdi) >= 0 && bdi.cluster_size != 0) {
|
||||
granularity = MAX(4096, bdi.cluster_size);
|
||||
granularity = MIN(65536, granularity);
|
||||
} else {
|
||||
granularity = 65536;
|
||||
}
|
||||
granularity = bdrv_get_default_bitmap_granularity(target);
|
||||
}
|
||||
|
||||
assert ((granularity & (granularity - 1)) == 0);
|
||||
@@ -703,7 +686,7 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target,
|
||||
s->granularity = granularity;
|
||||
s->buf_size = MAX(buf_size, granularity);
|
||||
|
||||
s->dirty_bitmap = bdrv_create_dirty_bitmap(bs, granularity, errp);
|
||||
s->dirty_bitmap = bdrv_create_dirty_bitmap(bs, granularity, NULL, errp);
|
||||
if (!s->dirty_bitmap) {
|
||||
return;
|
||||
}
|
||||
@@ -717,7 +700,7 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target,
|
||||
|
||||
void mirror_start(BlockDriverState *bs, BlockDriverState *target,
|
||||
const char *replaces,
|
||||
int64_t speed, int64_t granularity, int64_t buf_size,
|
||||
int64_t speed, uint32_t granularity, int64_t buf_size,
|
||||
MirrorSyncMode mode, BlockdevOnError on_source_error,
|
||||
BlockdevOnError on_target_error,
|
||||
BlockCompletionFunc *cb,
|
||||
@@ -726,6 +709,10 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target,
|
||||
bool is_none_mode;
|
||||
BlockDriverState *base;
|
||||
|
||||
if (mode == MIRROR_SYNC_MODE_DIRTY_BITMAP) {
|
||||
error_setg(errp, "Sync mode 'dirty-bitmap' not supported");
|
||||
return;
|
||||
}
|
||||
is_none_mode = mode == MIRROR_SYNC_MODE_NONE;
|
||||
base = mode == MIRROR_SYNC_MODE_TOP ? bs->backing_hd : NULL;
|
||||
mirror_start_job(bs, target, replaces,
|
||||
|
66
block/null.c
66
block/null.c
@@ -12,8 +12,11 @@
|
||||
|
||||
#include "block/block_int.h"
|
||||
|
||||
#define NULL_OPT_LATENCY "latency-ns"
|
||||
|
||||
typedef struct {
|
||||
int64_t length;
|
||||
int64_t latency_ns;
|
||||
} BDRVNullState;
|
||||
|
||||
static QemuOptsList runtime_opts = {
|
||||
@@ -30,6 +33,12 @@ static QemuOptsList runtime_opts = {
|
||||
.type = QEMU_OPT_SIZE,
|
||||
.help = "size of the null block",
|
||||
},
|
||||
{
|
||||
.name = NULL_OPT_LATENCY,
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
.help = "nanoseconds (approximated) to wait "
|
||||
"before completing request",
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
@@ -39,13 +48,20 @@ static int null_file_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
{
|
||||
QemuOpts *opts;
|
||||
BDRVNullState *s = bs->opaque;
|
||||
int ret = 0;
|
||||
|
||||
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
||||
qemu_opts_absorb_qdict(opts, options, &error_abort);
|
||||
s->length =
|
||||
qemu_opt_get_size(opts, BLOCK_OPT_SIZE, 1 << 30);
|
||||
s->latency_ns =
|
||||
qemu_opt_get_number(opts, NULL_OPT_LATENCY, 0);
|
||||
if (s->latency_ns < 0) {
|
||||
error_setg(errp, "latency-ns is invalid");
|
||||
ret = -EINVAL;
|
||||
}
|
||||
qemu_opts_del(opts);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void null_close(BlockDriverState *bs)
|
||||
@@ -58,28 +74,40 @@ static int64_t null_getlength(BlockDriverState *bs)
|
||||
return s->length;
|
||||
}
|
||||
|
||||
static coroutine_fn int null_co_common(BlockDriverState *bs)
|
||||
{
|
||||
BDRVNullState *s = bs->opaque;
|
||||
|
||||
if (s->latency_ns) {
|
||||
co_aio_sleep_ns(bdrv_get_aio_context(bs), QEMU_CLOCK_REALTIME,
|
||||
s->latency_ns);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static coroutine_fn int null_co_readv(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors,
|
||||
QEMUIOVector *qiov)
|
||||
{
|
||||
return 0;
|
||||
return null_co_common(bs);
|
||||
}
|
||||
|
||||
static coroutine_fn int null_co_writev(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors,
|
||||
QEMUIOVector *qiov)
|
||||
{
|
||||
return 0;
|
||||
return null_co_common(bs);
|
||||
}
|
||||
|
||||
static coroutine_fn int null_co_flush(BlockDriverState *bs)
|
||||
{
|
||||
return 0;
|
||||
return null_co_common(bs);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
BlockAIOCB common;
|
||||
QEMUBH *bh;
|
||||
QEMUTimer timer;
|
||||
} NullAIOCB;
|
||||
|
||||
static const AIOCBInfo null_aiocb_info = {
|
||||
@@ -94,15 +122,33 @@ static void null_bh_cb(void *opaque)
|
||||
qemu_aio_unref(acb);
|
||||
}
|
||||
|
||||
static void null_timer_cb(void *opaque)
|
||||
{
|
||||
NullAIOCB *acb = opaque;
|
||||
acb->common.cb(acb->common.opaque, 0);
|
||||
timer_deinit(&acb->timer);
|
||||
qemu_aio_unref(acb);
|
||||
}
|
||||
|
||||
static inline BlockAIOCB *null_aio_common(BlockDriverState *bs,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque)
|
||||
{
|
||||
NullAIOCB *acb;
|
||||
BDRVNullState *s = bs->opaque;
|
||||
|
||||
acb = qemu_aio_get(&null_aiocb_info, bs, cb, opaque);
|
||||
acb->bh = aio_bh_new(bdrv_get_aio_context(bs), null_bh_cb, acb);
|
||||
qemu_bh_schedule(acb->bh);
|
||||
/* Only emulate latency after vcpu is running. */
|
||||
if (s->latency_ns) {
|
||||
aio_timer_init(bdrv_get_aio_context(bs), &acb->timer,
|
||||
QEMU_CLOCK_REALTIME, SCALE_NS,
|
||||
null_timer_cb, acb);
|
||||
timer_mod_ns(&acb->timer,
|
||||
qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + s->latency_ns);
|
||||
} else {
|
||||
acb->bh = aio_bh_new(bdrv_get_aio_context(bs), null_bh_cb, acb);
|
||||
qemu_bh_schedule(acb->bh);
|
||||
}
|
||||
return &acb->common;
|
||||
}
|
||||
|
||||
@@ -131,6 +177,12 @@ static BlockAIOCB *null_aio_flush(BlockDriverState *bs,
|
||||
return null_aio_common(bs, cb, opaque);
|
||||
}
|
||||
|
||||
static int null_reopen_prepare(BDRVReopenState *reopen_state,
|
||||
BlockReopenQueue *queue, Error **errp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static BlockDriver bdrv_null_co = {
|
||||
.format_name = "null-co",
|
||||
.protocol_name = "null-co",
|
||||
@@ -143,6 +195,7 @@ static BlockDriver bdrv_null_co = {
|
||||
.bdrv_co_readv = null_co_readv,
|
||||
.bdrv_co_writev = null_co_writev,
|
||||
.bdrv_co_flush_to_disk = null_co_flush,
|
||||
.bdrv_reopen_prepare = null_reopen_prepare,
|
||||
};
|
||||
|
||||
static BlockDriver bdrv_null_aio = {
|
||||
@@ -157,6 +210,7 @@ static BlockDriver bdrv_null_aio = {
|
||||
.bdrv_aio_readv = null_aio_readv,
|
||||
.bdrv_aio_writev = null_aio_writev,
|
||||
.bdrv_aio_flush = null_aio_flush,
|
||||
.bdrv_reopen_prepare = null_reopen_prepare,
|
||||
};
|
||||
|
||||
static void bdrv_null_init(void)
|
||||
|
46
block/qapi.c
46
block/qapi.c
@@ -31,8 +31,10 @@
|
||||
#include "qapi/qmp/types.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
|
||||
BlockDeviceInfo *bdrv_block_device_info(BlockDriverState *bs)
|
||||
BlockDeviceInfo *bdrv_block_device_info(BlockDriverState *bs, Error **errp)
|
||||
{
|
||||
ImageInfo **p_image_info;
|
||||
BlockDriverState *bs0;
|
||||
BlockDeviceInfo *info = g_malloc0(sizeof(*info));
|
||||
|
||||
info->file = g_strdup(bs->filename);
|
||||
@@ -92,6 +94,25 @@ BlockDeviceInfo *bdrv_block_device_info(BlockDriverState *bs)
|
||||
|
||||
info->write_threshold = bdrv_write_threshold_get(bs);
|
||||
|
||||
bs0 = bs;
|
||||
p_image_info = &info->image;
|
||||
while (1) {
|
||||
Error *local_err = NULL;
|
||||
bdrv_query_image_info(bs0, p_image_info, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
qapi_free_BlockDeviceInfo(info);
|
||||
return NULL;
|
||||
}
|
||||
if (bs0->drv && bs0->backing_hd) {
|
||||
bs0 = bs0->backing_hd;
|
||||
(*p_image_info)->has_backing_image = true;
|
||||
p_image_info = &((*p_image_info)->backing_image);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
@@ -264,9 +285,6 @@ static void bdrv_query_info(BlockBackend *blk, BlockInfo **p_info,
|
||||
{
|
||||
BlockInfo *info = g_malloc0(sizeof(*info));
|
||||
BlockDriverState *bs = blk_bs(blk);
|
||||
BlockDriverState *bs0;
|
||||
ImageInfo **p_image_info;
|
||||
Error *local_err = NULL;
|
||||
info->device = g_strdup(blk_name(blk));
|
||||
info->type = g_strdup("unknown");
|
||||
info->locked = blk_dev_is_medium_locked(blk);
|
||||
@@ -289,23 +307,9 @@ static void bdrv_query_info(BlockBackend *blk, BlockInfo **p_info,
|
||||
|
||||
if (bs->drv) {
|
||||
info->has_inserted = true;
|
||||
info->inserted = bdrv_block_device_info(bs);
|
||||
|
||||
bs0 = bs;
|
||||
p_image_info = &info->inserted->image;
|
||||
while (1) {
|
||||
bdrv_query_image_info(bs0, p_image_info, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
goto err;
|
||||
}
|
||||
if (bs0->drv && bs0->backing_hd) {
|
||||
bs0 = bs0->backing_hd;
|
||||
(*p_image_info)->has_backing_image = true;
|
||||
p_image_info = &((*p_image_info)->backing_image);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
info->inserted = bdrv_block_device_info(bs, errp);
|
||||
if (info->inserted == NULL) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -124,7 +124,7 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
snprintf(version, sizeof(version), "QCOW version %" PRIu32,
|
||||
header.version);
|
||||
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||
bdrv_get_device_name(bs), "qcow", version);
|
||||
bdrv_get_device_or_node_name(bs), "qcow", version);
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
}
|
||||
@@ -229,9 +229,9 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
|
||||
/* Disable migration when qcow images are used */
|
||||
error_set(&s->migration_blocker,
|
||||
QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
|
||||
"qcow", bdrv_get_device_name(bs), "live migration");
|
||||
error_setg(&s->migration_blocker, "The qcow format used by node '%s' "
|
||||
"does not support live migration",
|
||||
bdrv_get_device_or_node_name(bs));
|
||||
migrate_add_blocker(s->migration_blocker);
|
||||
|
||||
qemu_co_mutex_init(&s->lock);
|
||||
|
@@ -2450,7 +2450,7 @@ int qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t offset,
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
} else if (ret > 0) {
|
||||
int metadata_ol_bitnr = ffs(ret) - 1;
|
||||
int metadata_ol_bitnr = ctz32(ret);
|
||||
assert(metadata_ol_bitnr < QCOW2_OL_MAX_BITNR);
|
||||
|
||||
qcow2_signal_corruption(bs, true, offset, size, "Preventing invalid "
|
||||
|
@@ -351,10 +351,8 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
|
||||
|
||||
memset(sn, 0, sizeof(*sn));
|
||||
|
||||
/* Generate an ID if it wasn't passed */
|
||||
if (sn_info->id_str[0] == '\0') {
|
||||
find_new_snapshot_id(bs, sn_info->id_str, sizeof(sn_info->id_str));
|
||||
}
|
||||
/* Generate an ID */
|
||||
find_new_snapshot_id(bs, sn_info->id_str, sizeof(sn_info->id_str));
|
||||
|
||||
/* Check that the ID is unique */
|
||||
if (find_snapshot_by_id_and_name(bs, sn_info->id_str, NULL) >= 0) {
|
||||
|
@@ -208,7 +208,7 @@ static void GCC_FMT_ATTR(3, 4) report_unsupported(BlockDriverState *bs,
|
||||
va_end(ap);
|
||||
|
||||
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||
bdrv_get_device_name(bs), "qcow2", msg);
|
||||
bdrv_get_device_or_node_name(bs), "qcow2", msg);
|
||||
}
|
||||
|
||||
static void report_unsupported_feature(BlockDriverState *bs,
|
||||
@@ -1802,7 +1802,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
||||
{
|
||||
/* Calculate cluster_bits */
|
||||
int cluster_bits;
|
||||
cluster_bits = ffs(cluster_size) - 1;
|
||||
cluster_bits = ctz32(cluster_size);
|
||||
if (cluster_bits < MIN_CLUSTER_BITS || cluster_bits > MAX_CLUSTER_BITS ||
|
||||
(1 << cluster_bits) != cluster_size)
|
||||
{
|
||||
@@ -2110,7 +2110,7 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
refcount_order = ffs(refcount_bits) - 1;
|
||||
refcount_order = ctz32(refcount_bits);
|
||||
|
||||
ret = qcow2_create2(filename, size, backing_file, backing_fmt, flags,
|
||||
cluster_size, prealloc, opts, version, refcount_order,
|
||||
@@ -2824,6 +2824,7 @@ void qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset,
|
||||
int64_t size, const char *message_format, ...)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
const char *node_name;
|
||||
char *message;
|
||||
va_list ap;
|
||||
|
||||
@@ -2847,8 +2848,11 @@ void qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset,
|
||||
"corruption events will be suppressed\n", message);
|
||||
}
|
||||
|
||||
qapi_event_send_block_image_corrupted(bdrv_get_device_name(bs), message,
|
||||
offset >= 0, offset, size >= 0, size,
|
||||
node_name = bdrv_get_node_name(bs);
|
||||
qapi_event_send_block_image_corrupted(bdrv_get_device_name(bs),
|
||||
*node_name != '\0', node_name,
|
||||
message, offset >= 0, offset,
|
||||
size >= 0, size,
|
||||
fatal, &error_abort);
|
||||
g_free(message);
|
||||
|
||||
|
@@ -408,7 +408,7 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
snprintf(buf, sizeof(buf), "%" PRIx64,
|
||||
s->header.features & ~QED_FEATURE_MASK);
|
||||
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||
bdrv_get_device_name(bs), "QED", buf);
|
||||
bdrv_get_device_or_node_name(bs), "QED", buf);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
if (!qed_is_cluster_size_valid(s->header.cluster_size)) {
|
||||
@@ -436,9 +436,9 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
|
||||
s->table_nelems = (s->header.cluster_size * s->header.table_size) /
|
||||
sizeof(uint64_t);
|
||||
s->l2_shift = ffs(s->header.cluster_size) - 1;
|
||||
s->l2_shift = ctz32(s->header.cluster_size);
|
||||
s->l2_mask = s->table_nelems - 1;
|
||||
s->l1_shift = s->l2_shift + ffs(s->table_nelems) - 1;
|
||||
s->l1_shift = s->l2_shift + ctz32(s->table_nelems);
|
||||
|
||||
/* Header size calculation must not overflow uint32_t */
|
||||
if (s->header.header_size > UINT32_MAX / s->header.cluster_size) {
|
||||
|
@@ -226,10 +226,7 @@ static void quorum_report_bad(QuorumAIOCB *acb, char *node_name, int ret)
|
||||
|
||||
static void quorum_report_failure(QuorumAIOCB *acb)
|
||||
{
|
||||
const char *reference = bdrv_get_device_name(acb->common.bs)[0] ?
|
||||
bdrv_get_device_name(acb->common.bs) :
|
||||
acb->common.bs->node_name;
|
||||
|
||||
const char *reference = bdrv_get_device_or_node_name(acb->common.bs);
|
||||
qapi_event_send_quorum_failure(reference, acb->sector_num,
|
||||
acb->nb_sectors, &error_abort);
|
||||
}
|
||||
|
@@ -325,7 +325,7 @@ static int qemu_rbd_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
error_setg(errp, "obj size too small");
|
||||
return -EINVAL;
|
||||
}
|
||||
obj_order = ffs(objsize) - 1;
|
||||
obj_order = ctz32(objsize);
|
||||
}
|
||||
|
||||
clientname = qemu_rbd_parse_clientname(conf, clientname_buf);
|
||||
|
@@ -1716,7 +1716,7 @@ static int parse_block_size_shift(BDRVSheepdogState *s, QemuOpts *opt)
|
||||
if ((object_size - 1) & object_size) { /* not a power of 2? */
|
||||
return -EINVAL;
|
||||
}
|
||||
obj_order = ffs(object_size) - 1;
|
||||
obj_order = ctz32(object_size);
|
||||
if (obj_order < 20 || obj_order > 31) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@@ -246,9 +246,9 @@ int bdrv_snapshot_delete(BlockDriverState *bs,
|
||||
if (bs->file) {
|
||||
return bdrv_snapshot_delete(bs->file, snapshot_id, name, errp);
|
||||
}
|
||||
error_set(errp, QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
|
||||
drv->format_name, bdrv_get_device_name(bs),
|
||||
"internal snapshot deletion");
|
||||
error_setg(errp, "Block format '%s' used by device '%s' "
|
||||
"does not support internal snapshot deletion",
|
||||
drv->format_name, bdrv_get_device_name(bs));
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
@@ -329,9 +329,9 @@ int bdrv_snapshot_load_tmp(BlockDriverState *bs,
|
||||
if (drv->bdrv_snapshot_load_tmp) {
|
||||
return drv->bdrv_snapshot_load_tmp(bs, snapshot_id, name, errp);
|
||||
}
|
||||
error_set(errp, QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
|
||||
drv->format_name, bdrv_get_device_name(bs),
|
||||
"temporarily load internal snapshot");
|
||||
error_setg(errp, "Block format '%s' used by device '%s' "
|
||||
"does not support temporarily loading internal snapshots",
|
||||
drv->format_name, bdrv_get_device_name(bs));
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
|
@@ -502,9 +502,9 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
|
||||
/* Disable migration when vdi images are used */
|
||||
error_set(&s->migration_blocker,
|
||||
QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
|
||||
"vdi", bdrv_get_device_name(bs), "live migration");
|
||||
error_setg(&s->migration_blocker, "The vdi format used by node '%s' "
|
||||
"does not support live migration",
|
||||
bdrv_get_device_or_node_name(bs));
|
||||
migrate_add_blocker(s->migration_blocker);
|
||||
|
||||
qemu_co_mutex_init(&s->write_lock);
|
||||
|
10
block/vhdx.c
10
block/vhdx.c
@@ -1002,9 +1002,9 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
/* TODO: differencing files */
|
||||
|
||||
/* Disable migration when VHDX images are used */
|
||||
error_set(&s->migration_blocker,
|
||||
QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
|
||||
"vhdx", bdrv_get_device_name(bs), "live migration");
|
||||
error_setg(&s->migration_blocker, "The vhdx format used by node '%s' "
|
||||
"does not support live migration",
|
||||
bdrv_get_device_or_node_name(bs));
|
||||
migrate_add_blocker(s->migration_blocker);
|
||||
|
||||
return 0;
|
||||
@@ -1269,7 +1269,7 @@ static coroutine_fn int vhdx_co_writev(BlockDriverState *bs, int64_t sector_num,
|
||||
iov1.iov_base = qemu_blockalign(bs, iov1.iov_len);
|
||||
memset(iov1.iov_base, 0, iov1.iov_len);
|
||||
qemu_iovec_concat_iov(&hd_qiov, &iov1, 1, 0,
|
||||
sinfo.block_offset);
|
||||
iov1.iov_len);
|
||||
sectors_to_write += iov1.iov_len >> BDRV_SECTOR_BITS;
|
||||
}
|
||||
|
||||
@@ -1285,7 +1285,7 @@ static coroutine_fn int vhdx_co_writev(BlockDriverState *bs, int64_t sector_num,
|
||||
iov2.iov_base = qemu_blockalign(bs, iov2.iov_len);
|
||||
memset(iov2.iov_base, 0, iov2.iov_len);
|
||||
qemu_iovec_concat_iov(&hd_qiov, &iov2, 1, 0,
|
||||
sinfo.block_offset);
|
||||
iov2.iov_len);
|
||||
sectors_to_write += iov2.iov_len >> BDRV_SECTOR_BITS;
|
||||
}
|
||||
}
|
||||
|
10
block/vmdk.c
10
block/vmdk.c
@@ -523,7 +523,7 @@ static int vmdk_open_vmfs_sparse(BlockDriverState *bs,
|
||||
}
|
||||
ret = vmdk_add_extent(bs, file, false,
|
||||
le32_to_cpu(header.disk_sectors),
|
||||
le32_to_cpu(header.l1dir_offset) << 9,
|
||||
(int64_t)le32_to_cpu(header.l1dir_offset) << 9,
|
||||
0,
|
||||
le32_to_cpu(header.l1dir_size),
|
||||
4096,
|
||||
@@ -669,7 +669,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
|
||||
snprintf(buf, sizeof(buf), "VMDK version %" PRId32,
|
||||
le32_to_cpu(header.version));
|
||||
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||
bdrv_get_device_name(bs), "vmdk", buf);
|
||||
bdrv_get_device_or_node_name(bs), "vmdk", buf);
|
||||
return -ENOTSUP;
|
||||
} else if (le32_to_cpu(header.version) == 3 && (flags & BDRV_O_RDWR)) {
|
||||
/* VMware KB 2064959 explains that version 3 added support for
|
||||
@@ -962,9 +962,9 @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
qemu_co_mutex_init(&s->lock);
|
||||
|
||||
/* Disable migration when VMDK images are used */
|
||||
error_set(&s->migration_blocker,
|
||||
QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
|
||||
"vmdk", bdrv_get_device_name(bs), "live migration");
|
||||
error_setg(&s->migration_blocker, "The vmdk format used by node '%s' "
|
||||
"does not support live migration",
|
||||
bdrv_get_device_or_node_name(bs));
|
||||
migrate_add_blocker(s->migration_blocker);
|
||||
g_free(buf);
|
||||
return 0;
|
||||
|
@@ -318,9 +318,9 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
qemu_co_mutex_init(&s->lock);
|
||||
|
||||
/* Disable migration when VHD images are used */
|
||||
error_set(&s->migration_blocker,
|
||||
QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
|
||||
"vpc", bdrv_get_device_name(bs), "live migration");
|
||||
error_setg(&s->migration_blocker, "The vpc format used by node '%s' "
|
||||
"does not support live migration",
|
||||
bdrv_get_device_or_node_name(bs));
|
||||
migrate_add_blocker(s->migration_blocker);
|
||||
|
||||
return 0;
|
||||
|
@@ -1180,9 +1180,10 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
|
||||
/* Disable migration when vvfat is used rw */
|
||||
if (s->qcow) {
|
||||
error_set(&s->migration_blocker,
|
||||
QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
|
||||
"vvfat (rw)", bdrv_get_device_name(bs), "live migration");
|
||||
error_setg(&s->migration_blocker,
|
||||
"The vvfat (rw) format used by node '%s' "
|
||||
"does not support live migration",
|
||||
bdrv_get_device_or_node_name(bs));
|
||||
migrate_add_blocker(s->migration_blocker);
|
||||
}
|
||||
|
||||
|
195
blockdev.c
195
blockdev.c
@@ -1164,6 +1164,68 @@ out_aio_context:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* block_dirty_bitmap_lookup:
|
||||
* Return a dirty bitmap (if present), after validating
|
||||
* the node reference and bitmap names.
|
||||
*
|
||||
* @node: The name of the BDS node to search for bitmaps
|
||||
* @name: The name of the bitmap to search for
|
||||
* @pbs: Output pointer for BDS lookup, if desired. Can be NULL.
|
||||
* @paio: Output pointer for aio_context acquisition, if desired. Can be NULL.
|
||||
* @errp: Output pointer for error information. Can be NULL.
|
||||
*
|
||||
* @return: A bitmap object on success, or NULL on failure.
|
||||
*/
|
||||
static BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char *node,
|
||||
const char *name,
|
||||
BlockDriverState **pbs,
|
||||
AioContext **paio,
|
||||
Error **errp)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
BdrvDirtyBitmap *bitmap;
|
||||
AioContext *aio_context;
|
||||
|
||||
if (!node) {
|
||||
error_setg(errp, "Node cannot be NULL");
|
||||
return NULL;
|
||||
}
|
||||
if (!name) {
|
||||
error_setg(errp, "Bitmap name cannot be NULL");
|
||||
return NULL;
|
||||
}
|
||||
bs = bdrv_lookup_bs(node, node, NULL);
|
||||
if (!bs) {
|
||||
error_setg(errp, "Node '%s' not found", node);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
aio_context = bdrv_get_aio_context(bs);
|
||||
aio_context_acquire(aio_context);
|
||||
|
||||
bitmap = bdrv_find_dirty_bitmap(bs, name);
|
||||
if (!bitmap) {
|
||||
error_setg(errp, "Dirty bitmap '%s' not found", name);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (pbs) {
|
||||
*pbs = bs;
|
||||
}
|
||||
if (paio) {
|
||||
*paio = aio_context;
|
||||
} else {
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
return bitmap;
|
||||
|
||||
fail:
|
||||
aio_context_release(aio_context);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* New and old BlockDriverState structs for atomic group operations */
|
||||
|
||||
typedef struct BlkTransactionState BlkTransactionState;
|
||||
@@ -1248,13 +1310,14 @@ static void internal_snapshot_prepare(BlkTransactionState *common,
|
||||
}
|
||||
|
||||
if (bdrv_is_read_only(bs)) {
|
||||
error_set(errp, QERR_DEVICE_IS_READ_ONLY, device);
|
||||
error_setg(errp, "Device '%s' is read only", device);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bdrv_can_snapshot(bs)) {
|
||||
error_set(errp, QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
|
||||
bs->drv->format_name, device, "internal snapshot");
|
||||
error_setg(errp, "Block format '%s' used by device '%s' "
|
||||
"does not support internal snapshots",
|
||||
bs->drv->format_name, device);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1522,6 +1585,7 @@ static void drive_backup_prepare(BlkTransactionState *common, Error **errp)
|
||||
backup->sync,
|
||||
backup->has_mode, backup->mode,
|
||||
backup->has_speed, backup->speed,
|
||||
backup->has_bitmap, backup->bitmap,
|
||||
backup->has_on_source_error, backup->on_source_error,
|
||||
backup->has_on_target_error, backup->on_target_error,
|
||||
&local_err);
|
||||
@@ -1953,6 +2017,102 @@ void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
void qmp_block_dirty_bitmap_add(const char *node, const char *name,
|
||||
bool has_granularity, uint32_t granularity,
|
||||
Error **errp)
|
||||
{
|
||||
AioContext *aio_context;
|
||||
BlockDriverState *bs;
|
||||
|
||||
if (!name || name[0] == '\0') {
|
||||
error_setg(errp, "Bitmap name cannot be empty");
|
||||
return;
|
||||
}
|
||||
|
||||
bs = bdrv_lookup_bs(node, node, errp);
|
||||
if (!bs) {
|
||||
return;
|
||||
}
|
||||
|
||||
aio_context = bdrv_get_aio_context(bs);
|
||||
aio_context_acquire(aio_context);
|
||||
|
||||
if (has_granularity) {
|
||||
if (granularity < 512 || !is_power_of_2(granularity)) {
|
||||
error_setg(errp, "Granularity must be power of 2 "
|
||||
"and at least 512");
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
/* Default to cluster size, if available: */
|
||||
granularity = bdrv_get_default_bitmap_granularity(bs);
|
||||
}
|
||||
|
||||
bdrv_create_dirty_bitmap(bs, granularity, name, errp);
|
||||
|
||||
out:
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
void qmp_block_dirty_bitmap_remove(const char *node, const char *name,
|
||||
Error **errp)
|
||||
{
|
||||
AioContext *aio_context;
|
||||
BlockDriverState *bs;
|
||||
BdrvDirtyBitmap *bitmap;
|
||||
|
||||
bitmap = block_dirty_bitmap_lookup(node, name, &bs, &aio_context, errp);
|
||||
if (!bitmap || !bs) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (bdrv_dirty_bitmap_frozen(bitmap)) {
|
||||
error_setg(errp,
|
||||
"Bitmap '%s' is currently frozen and cannot be removed",
|
||||
name);
|
||||
goto out;
|
||||
}
|
||||
bdrv_dirty_bitmap_make_anon(bitmap);
|
||||
bdrv_release_dirty_bitmap(bs, bitmap);
|
||||
|
||||
out:
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Completely clear a bitmap, for the purposes of synchronizing a bitmap
|
||||
* immediately after a full backup operation.
|
||||
*/
|
||||
void qmp_block_dirty_bitmap_clear(const char *node, const char *name,
|
||||
Error **errp)
|
||||
{
|
||||
AioContext *aio_context;
|
||||
BdrvDirtyBitmap *bitmap;
|
||||
BlockDriverState *bs;
|
||||
|
||||
bitmap = block_dirty_bitmap_lookup(node, name, &bs, &aio_context, errp);
|
||||
if (!bitmap || !bs) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (bdrv_dirty_bitmap_frozen(bitmap)) {
|
||||
error_setg(errp,
|
||||
"Bitmap '%s' is currently frozen and cannot be modified",
|
||||
name);
|
||||
goto out;
|
||||
} else if (!bdrv_dirty_bitmap_enabled(bitmap)) {
|
||||
error_setg(errp,
|
||||
"Bitmap '%s' is currently disabled and cannot be cleared",
|
||||
name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
bdrv_clear_dirty_bitmap(bitmap);
|
||||
|
||||
out:
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
int hmp_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
||||
{
|
||||
const char *id = qdict_get_str(qdict, "id");
|
||||
@@ -2055,7 +2215,7 @@ void qmp_block_resize(bool has_device, const char *device,
|
||||
error_set(errp, QERR_UNSUPPORTED);
|
||||
break;
|
||||
case -EACCES:
|
||||
error_set(errp, QERR_DEVICE_IS_READ_ONLY, device);
|
||||
error_setg(errp, "Device '%s' is read only", device);
|
||||
break;
|
||||
case -EBUSY:
|
||||
error_set(errp, QERR_DEVICE_IN_USE, device);
|
||||
@@ -2270,6 +2430,7 @@ void qmp_drive_backup(const char *device, const char *target,
|
||||
enum MirrorSyncMode sync,
|
||||
bool has_mode, enum NewImageMode mode,
|
||||
bool has_speed, int64_t speed,
|
||||
bool has_bitmap, const char *bitmap,
|
||||
bool has_on_source_error, BlockdevOnError on_source_error,
|
||||
bool has_on_target_error, BlockdevOnError on_target_error,
|
||||
Error **errp)
|
||||
@@ -2278,6 +2439,7 @@ void qmp_drive_backup(const char *device, const char *target,
|
||||
BlockDriverState *bs;
|
||||
BlockDriverState *target_bs;
|
||||
BlockDriverState *source = NULL;
|
||||
BdrvDirtyBitmap *bmap = NULL;
|
||||
AioContext *aio_context;
|
||||
BlockDriver *drv = NULL;
|
||||
Error *local_err = NULL;
|
||||
@@ -2377,7 +2539,16 @@ void qmp_drive_backup(const char *device, const char *target,
|
||||
|
||||
bdrv_set_aio_context(target_bs, aio_context);
|
||||
|
||||
backup_start(bs, target_bs, speed, sync, on_source_error, on_target_error,
|
||||
if (has_bitmap) {
|
||||
bmap = bdrv_find_dirty_bitmap(bs, bitmap);
|
||||
if (!bmap) {
|
||||
error_setg(errp, "Bitmap '%s' could not be found", bitmap);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
backup_start(bs, target_bs, speed, sync, bmap,
|
||||
on_source_error, on_target_error,
|
||||
block_job_cb, bs, &local_err);
|
||||
if (local_err != NULL) {
|
||||
bdrv_unref(target_bs);
|
||||
@@ -2391,7 +2562,7 @@ out:
|
||||
|
||||
BlockDeviceInfoList *qmp_query_named_block_nodes(Error **errp)
|
||||
{
|
||||
return bdrv_named_nodes_list();
|
||||
return bdrv_named_nodes_list(errp);
|
||||
}
|
||||
|
||||
void qmp_blockdev_backup(const char *device, const char *target,
|
||||
@@ -2438,8 +2609,8 @@ void qmp_blockdev_backup(const char *device, const char *target,
|
||||
|
||||
bdrv_ref(target_bs);
|
||||
bdrv_set_aio_context(target_bs, aio_context);
|
||||
backup_start(bs, target_bs, speed, sync, on_source_error, on_target_error,
|
||||
block_job_cb, bs, &local_err);
|
||||
backup_start(bs, target_bs, speed, sync, NULL, on_source_error,
|
||||
on_target_error, block_job_cb, bs, &local_err);
|
||||
if (local_err != NULL) {
|
||||
bdrv_unref(target_bs);
|
||||
error_propagate(errp, local_err);
|
||||
@@ -2699,7 +2870,7 @@ void qmp_block_job_cancel(const char *device,
|
||||
force = false;
|
||||
}
|
||||
|
||||
if (job->paused && !force) {
|
||||
if (job->user_paused && !force) {
|
||||
error_setg(errp, "The block job for device '%s' is currently paused",
|
||||
device);
|
||||
goto out;
|
||||
@@ -2716,10 +2887,11 @@ 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 || job->user_paused) {
|
||||
return;
|
||||
}
|
||||
|
||||
job->user_paused = true;
|
||||
trace_qmp_block_job_pause(job);
|
||||
block_job_pause(job);
|
||||
aio_context_release(aio_context);
|
||||
@@ -2730,10 +2902,11 @@ 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 || !job->user_paused) {
|
||||
return;
|
||||
}
|
||||
|
||||
job->user_paused = false;
|
||||
trace_qmp_block_job_resume(job);
|
||||
block_job_resume(job);
|
||||
aio_context_release(aio_context);
|
||||
|
23
blockjob.c
23
blockjob.c
@@ -107,7 +107,7 @@ void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
|
||||
|
||||
void block_job_complete(BlockJob *job, Error **errp)
|
||||
{
|
||||
if (job->paused || job->cancelled || !job->driver->complete) {
|
||||
if (job->pause_count || job->cancelled || !job->driver->complete) {
|
||||
error_set(errp, QERR_BLOCK_JOB_NOT_READY,
|
||||
bdrv_get_device_name(job->bs));
|
||||
return;
|
||||
@@ -118,17 +118,26 @@ void block_job_complete(BlockJob *job, Error **errp)
|
||||
|
||||
void block_job_pause(BlockJob *job)
|
||||
{
|
||||
job->paused = true;
|
||||
job->pause_count++;
|
||||
}
|
||||
|
||||
bool block_job_is_paused(BlockJob *job)
|
||||
{
|
||||
return job->paused;
|
||||
return job->pause_count > 0;
|
||||
}
|
||||
|
||||
void block_job_resume(BlockJob *job)
|
||||
{
|
||||
job->paused = false;
|
||||
assert(job->pause_count > 0);
|
||||
job->pause_count--;
|
||||
if (job->pause_count) {
|
||||
return;
|
||||
}
|
||||
block_job_enter(job);
|
||||
}
|
||||
|
||||
void block_job_enter(BlockJob *job)
|
||||
{
|
||||
block_job_iostatus_reset(job);
|
||||
if (job->co && !job->busy) {
|
||||
qemu_coroutine_enter(job->co, NULL);
|
||||
@@ -138,7 +147,7 @@ void block_job_resume(BlockJob *job)
|
||||
void block_job_cancel(BlockJob *job)
|
||||
{
|
||||
job->cancelled = true;
|
||||
block_job_resume(job);
|
||||
block_job_enter(job);
|
||||
}
|
||||
|
||||
bool block_job_is_cancelled(BlockJob *job)
|
||||
@@ -258,7 +267,7 @@ BlockJobInfo *block_job_query(BlockJob *job)
|
||||
info->device = g_strdup(bdrv_get_device_name(job->bs));
|
||||
info->len = job->len;
|
||||
info->busy = job->busy;
|
||||
info->paused = job->paused;
|
||||
info->paused = job->pause_count > 0;
|
||||
info->offset = job->offset;
|
||||
info->speed = job->speed;
|
||||
info->io_status = job->iostatus;
|
||||
@@ -335,6 +344,8 @@ BlockErrorAction block_job_error_action(BlockJob *job, BlockDriverState *bs,
|
||||
IO_OPERATION_TYPE_WRITE,
|
||||
action, &error_abort);
|
||||
if (action == BLOCK_ERROR_ACTION_STOP) {
|
||||
/* make the pause user visible, which will be resumed from QMP. */
|
||||
job->user_paused = true;
|
||||
block_job_pause(job);
|
||||
block_job_iostatus_set_err(job, error);
|
||||
if (bs != job->bs) {
|
||||
|
@@ -905,7 +905,6 @@ int main(int argc, char **argv)
|
||||
#endif
|
||||
}
|
||||
tcg_exec_init(0);
|
||||
cpu_exec_init_all();
|
||||
/* NOTE: we need to init the CPU at this stage to get
|
||||
qemu_host_page_size */
|
||||
cpu = cpu_init(cpu_model);
|
||||
|
30
configure
vendored
30
configure
vendored
@@ -336,6 +336,7 @@ libssh2=""
|
||||
vhdx=""
|
||||
quorum=""
|
||||
numa=""
|
||||
tcmalloc="no"
|
||||
|
||||
# parse CC options first
|
||||
for opt do
|
||||
@@ -1134,6 +1135,10 @@ for opt do
|
||||
;;
|
||||
--enable-numa) numa="yes"
|
||||
;;
|
||||
--disable-tcmalloc) tcmalloc="no"
|
||||
;;
|
||||
--enable-tcmalloc) tcmalloc="yes"
|
||||
;;
|
||||
*)
|
||||
echo "ERROR: unknown option $opt"
|
||||
echo "Try '$0 --help' for more information"
|
||||
@@ -1407,6 +1412,8 @@ Advanced options (experts only):
|
||||
--enable-quorum enable quorum block filter support
|
||||
--disable-numa disable libnuma support
|
||||
--enable-numa enable libnuma support
|
||||
--disable-tcmalloc disable tcmalloc support
|
||||
--enable-tcmalloc enable tcmalloc support
|
||||
|
||||
NOTE: The object files are built at the place where configure is launched
|
||||
EOF
|
||||
@@ -3135,7 +3142,7 @@ else
|
||||
fi
|
||||
|
||||
if test "$opengl" != "no" ; then
|
||||
opengl_pkgs="gl"
|
||||
opengl_pkgs="gl glesv2"
|
||||
if $pkg_config $opengl_pkgs x11 && test "$have_glx" = "yes"; then
|
||||
opengl_cflags="$($pkg_config --cflags $opengl_pkgs) $x11_cflags"
|
||||
opengl_libs="$($pkg_config --libs $opengl_pkgs) $x11_libs"
|
||||
@@ -3330,6 +3337,22 @@ EOF
|
||||
fi
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# tcmalloc probe
|
||||
|
||||
if test "$tcmalloc" = "yes" ; then
|
||||
cat > $TMPC << EOF
|
||||
#include <stdlib.h>
|
||||
int main(void) { malloc(1); return 0; }
|
||||
EOF
|
||||
|
||||
if compile_prog "" "-ltcmalloc" ; then
|
||||
LIBS="-ltcmalloc $LIBS"
|
||||
else
|
||||
feature_not_found "tcmalloc" "install gperftools devel"
|
||||
fi
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# signalfd probe
|
||||
signalfd="no"
|
||||
@@ -4441,6 +4464,7 @@ echo "lzo support $lzo"
|
||||
echo "snappy support $snappy"
|
||||
echo "bzip2 support $bzip2"
|
||||
echo "NUMA host support $numa"
|
||||
echo "tcmalloc support $tcmalloc"
|
||||
|
||||
if test "$sdl_too_old" = "yes"; then
|
||||
echo "-> Your SDL version is too old - please upgrade to have SDL support"
|
||||
@@ -5169,8 +5193,6 @@ case "$target_name" in
|
||||
TARGET_BASE_ARCH=mips
|
||||
echo "TARGET_ABI_MIPSN64=y" >> $config_target_mak
|
||||
;;
|
||||
tricore)
|
||||
;;
|
||||
moxie)
|
||||
;;
|
||||
or32)
|
||||
@@ -5221,6 +5243,8 @@ case "$target_name" in
|
||||
s390x)
|
||||
gdb_xml_files="s390x-core64.xml s390-acr.xml s390-fpr.xml"
|
||||
;;
|
||||
tricore)
|
||||
;;
|
||||
unicore32)
|
||||
;;
|
||||
xtensa|xtensaeb)
|
||||
|
2
cpus.c
2
cpus.c
@@ -1016,7 +1016,7 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
|
||||
qemu_cond_signal(&qemu_cpu_cond);
|
||||
|
||||
/* wait for initial kick-off after machine start */
|
||||
while (QTAILQ_FIRST(&cpus)->stopped) {
|
||||
while (first_cpu->stopped) {
|
||||
qemu_cond_wait(tcg_halt_cond, &qemu_global_mutex);
|
||||
|
||||
/* process any pending work */
|
||||
|
22
cputlb.c
22
cputlb.c
@@ -249,9 +249,9 @@ static void tlb_add_large_page(CPUArchState *env, target_ulong vaddr,
|
||||
* Called from TCG-generated code, which is under an RCU read-side
|
||||
* critical section.
|
||||
*/
|
||||
void tlb_set_page(CPUState *cpu, target_ulong vaddr,
|
||||
hwaddr paddr, int prot,
|
||||
int mmu_idx, target_ulong size)
|
||||
void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr,
|
||||
hwaddr paddr, MemTxAttrs attrs, int prot,
|
||||
int mmu_idx, target_ulong size)
|
||||
{
|
||||
CPUArchState *env = cpu->env_ptr;
|
||||
MemoryRegionSection *section;
|
||||
@@ -301,7 +301,8 @@ void tlb_set_page(CPUState *cpu, target_ulong vaddr,
|
||||
env->iotlb_v[mmu_idx][vidx] = env->iotlb[mmu_idx][index];
|
||||
|
||||
/* refill the tlb */
|
||||
env->iotlb[mmu_idx][index] = iotlb - vaddr;
|
||||
env->iotlb[mmu_idx][index].addr = iotlb - vaddr;
|
||||
env->iotlb[mmu_idx][index].attrs = attrs;
|
||||
te->addend = addend - vaddr;
|
||||
if (prot & PAGE_READ) {
|
||||
te->addr_read = address;
|
||||
@@ -331,6 +332,17 @@ void tlb_set_page(CPUState *cpu, target_ulong vaddr,
|
||||
}
|
||||
}
|
||||
|
||||
/* Add a new TLB entry, but without specifying the memory
|
||||
* transaction attributes to be used.
|
||||
*/
|
||||
void tlb_set_page(CPUState *cpu, target_ulong vaddr,
|
||||
hwaddr paddr, int prot,
|
||||
int mmu_idx, target_ulong size)
|
||||
{
|
||||
tlb_set_page_with_attrs(cpu, vaddr, paddr, MEMTXATTRS_UNSPECIFIED,
|
||||
prot, mmu_idx, size);
|
||||
}
|
||||
|
||||
/* NOTE: this function can trigger an exception */
|
||||
/* NOTE2: the returned address is not exactly the physical address: it
|
||||
* is actually a ram_addr_t (in system mode; the user mode emulation
|
||||
@@ -349,7 +361,7 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr)
|
||||
(addr & TARGET_PAGE_MASK))) {
|
||||
cpu_ldub_code(env1, addr);
|
||||
}
|
||||
pd = env1->iotlb[mmu_idx][page_index] & ~TARGET_PAGE_MASK;
|
||||
pd = env1->iotlb[mmu_idx][page_index].addr & ~TARGET_PAGE_MASK;
|
||||
mr = iotlb_to_region(cpu, pd);
|
||||
if (memory_region_is_unassigned(mr)) {
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
|
@@ -1,11 +1,3 @@
|
||||
# Default configuration for microblazeel-softmmu
|
||||
|
||||
CONFIG_PTIMER=y
|
||||
CONFIG_PFLASH_CFI01=y
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_XILINX=y
|
||||
CONFIG_XILINX_AXI=y
|
||||
CONFIG_XILINX_SPI=y
|
||||
CONFIG_XILINX_ETHLITE=y
|
||||
CONFIG_SSI=y
|
||||
CONFIG_SSI_M25P80=y
|
||||
include microblaze-softmmu.mak
|
||||
|
@@ -10,7 +10,6 @@
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/dma.h"
|
||||
#include "trace.h"
|
||||
#include "qemu/range.h"
|
||||
#include "qemu/thread.h"
|
||||
#include "qemu/main-loop.h"
|
||||
|
||||
@@ -28,7 +27,8 @@ int dma_memory_set(AddressSpace *as, dma_addr_t addr, uint8_t c, dma_addr_t len)
|
||||
memset(fillbuf, c, FILLBUF_SIZE);
|
||||
while (len > 0) {
|
||||
l = len < FILLBUF_SIZE ? len : FILLBUF_SIZE;
|
||||
error |= address_space_rw(as, addr, fillbuf, l, true);
|
||||
error |= address_space_rw(as, addr, MEMTXATTRS_UNSPECIFIED,
|
||||
fillbuf, l, true);
|
||||
len -= l;
|
||||
addr += l;
|
||||
}
|
||||
@@ -92,14 +92,6 @@ static void reschedule_dma(void *opaque)
|
||||
dma_blk_cb(dbs, 0);
|
||||
}
|
||||
|
||||
static void continue_after_map_failure(void *opaque)
|
||||
{
|
||||
DMAAIOCB *dbs = (DMAAIOCB *)opaque;
|
||||
|
||||
dbs->bh = qemu_bh_new(reschedule_dma, dbs);
|
||||
qemu_bh_schedule(dbs->bh);
|
||||
}
|
||||
|
||||
static void dma_blk_unmap(DMAAIOCB *dbs)
|
||||
{
|
||||
int i;
|
||||
@@ -161,7 +153,9 @@ static void dma_blk_cb(void *opaque, int ret)
|
||||
|
||||
if (dbs->iov.size == 0) {
|
||||
trace_dma_map_wait(dbs);
|
||||
cpu_register_map_client(dbs, continue_after_map_failure);
|
||||
dbs->bh = aio_bh_new(blk_get_aio_context(dbs->blk),
|
||||
reschedule_dma, dbs);
|
||||
cpu_register_map_client(dbs->bh);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -183,6 +177,11 @@ static void dma_aio_cancel(BlockAIOCB *acb)
|
||||
if (dbs->acb) {
|
||||
blk_aio_cancel_async(dbs->acb);
|
||||
}
|
||||
if (dbs->bh) {
|
||||
cpu_unregister_map_client(dbs->bh);
|
||||
qemu_bh_delete(dbs->bh);
|
||||
dbs->bh = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -281,7 +281,7 @@ note that the other barrier may actually be in a driver that runs in
|
||||
the guest!
|
||||
|
||||
For the purposes of pairing, smp_read_barrier_depends() and smp_rmb()
|
||||
both count as read barriers. A read barriers shall pair with a write
|
||||
both count as read barriers. A read barrier shall pair with a write
|
||||
barrier or a full barrier; a write barrier shall pair with a read
|
||||
barrier or a full barrier. A full barrier can pair with anything.
|
||||
For example:
|
||||
@@ -294,7 +294,7 @@ For example:
|
||||
smp_rmb();
|
||||
y = a;
|
||||
|
||||
Note that the "writing" thread are accessing the variables in the
|
||||
Note that the "writing" thread is accessing the variables in the
|
||||
opposite order as the "reading" thread. This is expected: stores
|
||||
before the write barrier will normally match the loads after the
|
||||
read barrier, and vice versa. The same is true for more than 2
|
||||
|
352
docs/bitmaps.md
Normal file
352
docs/bitmaps.md
Normal file
@@ -0,0 +1,352 @@
|
||||
<!--
|
||||
Copyright 2015 John Snow <jsnow@redhat.com> and Red Hat, Inc.
|
||||
All rights reserved.
|
||||
|
||||
This file is licensed via The FreeBSD Documentation License, the full text of
|
||||
which is included at the end of this document.
|
||||
-->
|
||||
|
||||
# Dirty Bitmaps and Incremental Backup
|
||||
|
||||
* Dirty Bitmaps are objects that track which data needs to be backed up for the
|
||||
next incremental backup.
|
||||
|
||||
* Dirty bitmaps can be created at any time and attached to any node
|
||||
(not just complete drives.)
|
||||
|
||||
## Dirty Bitmap Names
|
||||
|
||||
* A dirty bitmap's name is unique to the node, but bitmaps attached to different
|
||||
nodes can share the same name.
|
||||
|
||||
## Bitmap Modes
|
||||
|
||||
* A Bitmap can be "frozen," which means that it is currently in-use by a backup
|
||||
operation and cannot be deleted, renamed, written to, reset,
|
||||
etc.
|
||||
|
||||
## Basic QMP Usage
|
||||
|
||||
### Supported Commands ###
|
||||
|
||||
* block-dirty-bitmap-add
|
||||
* block-dirty-bitmap-remove
|
||||
* block-dirty-bitmap-clear
|
||||
|
||||
### Creation
|
||||
|
||||
* To create a new bitmap, enabled, on the drive with id=drive0:
|
||||
|
||||
```json
|
||||
{ "execute": "block-dirty-bitmap-add",
|
||||
"arguments": {
|
||||
"node": "drive0",
|
||||
"name": "bitmap0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
* This bitmap will have a default granularity that matches the cluster size of
|
||||
its associated drive, if available, clamped to between [4KiB, 64KiB].
|
||||
The current default for qcow2 is 64KiB.
|
||||
|
||||
* To create a new bitmap that tracks changes in 32KiB segments:
|
||||
|
||||
```json
|
||||
{ "execute": "block-dirty-bitmap-add",
|
||||
"arguments": {
|
||||
"node": "drive0",
|
||||
"name": "bitmap0",
|
||||
"granularity": 32768
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Deletion
|
||||
|
||||
* Bitmaps that are frozen cannot be deleted.
|
||||
|
||||
* Deleting the bitmap does not impact any other bitmaps attached to the same
|
||||
node, nor does it affect any backups already created from this node.
|
||||
|
||||
* Because bitmaps are only unique to the node to which they are attached,
|
||||
you must specify the node/drive name here, too.
|
||||
|
||||
```json
|
||||
{ "execute": "block-dirty-bitmap-remove",
|
||||
"arguments": {
|
||||
"node": "drive0",
|
||||
"name": "bitmap0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Resetting
|
||||
|
||||
* Resetting a bitmap will clear all information it holds.
|
||||
|
||||
* An incremental backup created from an empty bitmap will copy no data,
|
||||
as if nothing has changed.
|
||||
|
||||
```json
|
||||
{ "execute": "block-dirty-bitmap-clear",
|
||||
"arguments": {
|
||||
"node": "drive0",
|
||||
"name": "bitmap0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Transactions (Not yet implemented)
|
||||
|
||||
* Transactional commands are forthcoming in a future version,
|
||||
and are not yet available for use. This section serves as
|
||||
documentation of intent for their design and usage.
|
||||
|
||||
### Justification
|
||||
|
||||
Bitmaps can be safely modified when the VM is paused or halted by using
|
||||
the basic QMP commands. For instance, you might perform the following actions:
|
||||
|
||||
1. Boot the VM in a paused state.
|
||||
2. Create a full drive backup of drive0.
|
||||
3. Create a new bitmap attached to drive0.
|
||||
4. Resume execution of the VM.
|
||||
5. Incremental backups are ready to be created.
|
||||
|
||||
At this point, the bitmap and drive backup would be correctly in sync,
|
||||
and incremental backups made from this point forward would be correctly aligned
|
||||
to the full drive backup.
|
||||
|
||||
This is not particularly useful if we decide we want to start incremental
|
||||
backups after the VM has been running for a while, for which we will need to
|
||||
perform actions such as the following:
|
||||
|
||||
1. Boot the VM and begin execution.
|
||||
2. Using a single transaction, perform the following operations:
|
||||
* Create bitmap0.
|
||||
* Create a full drive backup of drive0.
|
||||
3. Incremental backups are now ready to be created.
|
||||
|
||||
### Supported Bitmap Transactions
|
||||
|
||||
* block-dirty-bitmap-add
|
||||
* block-dirty-bitmap-clear
|
||||
|
||||
The usages are identical to their respective QMP commands, but see below
|
||||
for examples.
|
||||
|
||||
### Example: New Incremental Backup
|
||||
|
||||
As outlined in the justification, perhaps we want to create a new incremental
|
||||
backup chain attached to a drive.
|
||||
|
||||
```json
|
||||
{ "execute": "transaction",
|
||||
"arguments": {
|
||||
"actions": [
|
||||
{"type": "block-dirty-bitmap-add",
|
||||
"data": {"node": "drive0", "name": "bitmap0"} },
|
||||
{"type": "drive-backup",
|
||||
"data": {"device": "drive0", "target": "/path/to/full_backup.img",
|
||||
"sync": "full", "format": "qcow2"} }
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Example: New Incremental Backup Anchor Point
|
||||
|
||||
Maybe we just want to create a new full backup with an existing bitmap and
|
||||
want to reset the bitmap to track the new chain.
|
||||
|
||||
```json
|
||||
{ "execute": "transaction",
|
||||
"arguments": {
|
||||
"actions": [
|
||||
{"type": "block-dirty-bitmap-clear",
|
||||
"data": {"node": "drive0", "name": "bitmap0"} },
|
||||
{"type": "drive-backup",
|
||||
"data": {"device": "drive0", "target": "/path/to/new_full_backup.img",
|
||||
"sync": "full", "format": "qcow2"} }
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Incremental Backups
|
||||
|
||||
The star of the show.
|
||||
|
||||
**Nota Bene!** Only incremental backups of entire drives are supported for now.
|
||||
So despite the fact that you can attach a bitmap to any arbitrary node, they are
|
||||
only currently useful when attached to the root node. This is because
|
||||
drive-backup only supports drives/devices instead of arbitrary nodes.
|
||||
|
||||
### Example: First Incremental Backup
|
||||
|
||||
1. Create a full backup and sync it to the dirty bitmap, as in the transactional
|
||||
examples above; or with the VM offline, manually create a full copy and then
|
||||
create a new bitmap before the VM begins execution.
|
||||
|
||||
* Let's assume the full backup is named 'full_backup.img'.
|
||||
* Let's assume the bitmap you created is 'bitmap0' attached to 'drive0'.
|
||||
|
||||
2. Create a destination image for the incremental backup that utilizes the
|
||||
full backup as a backing image.
|
||||
|
||||
* Let's assume it is named 'incremental.0.img'.
|
||||
|
||||
```sh
|
||||
# qemu-img create -f qcow2 incremental.0.img -b full_backup.img -F qcow2
|
||||
```
|
||||
|
||||
3. Issue the incremental backup command:
|
||||
|
||||
```json
|
||||
{ "execute": "drive-backup",
|
||||
"arguments": {
|
||||
"device": "drive0",
|
||||
"bitmap": "bitmap0",
|
||||
"target": "incremental.0.img",
|
||||
"format": "qcow2",
|
||||
"sync": "dirty-bitmap",
|
||||
"mode": "existing"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Example: Second Incremental Backup
|
||||
|
||||
1. Create a new destination image for the incremental backup that points to the
|
||||
previous one, e.g.: 'incremental.1.img'
|
||||
|
||||
```sh
|
||||
# qemu-img create -f qcow2 incremental.1.img -b incremental.0.img -F qcow2
|
||||
```
|
||||
|
||||
2. Issue a new incremental backup command. The only difference here is that we
|
||||
have changed the target image below.
|
||||
|
||||
```json
|
||||
{ "execute": "drive-backup",
|
||||
"arguments": {
|
||||
"device": "drive0",
|
||||
"bitmap": "bitmap0",
|
||||
"target": "incremental.1.img",
|
||||
"format": "qcow2",
|
||||
"sync": "dirty-bitmap",
|
||||
"mode": "existing"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
* In the event of an error that occurs after a backup job is successfully
|
||||
launched, either by a direct QMP command or a QMP transaction, the user
|
||||
will receive a BLOCK_JOB_COMPLETE event with a failure message, accompanied
|
||||
by a BLOCK_JOB_ERROR event.
|
||||
|
||||
* In the case of an event being cancelled, the user will receive a
|
||||
BLOCK_JOB_CANCELLED event instead of a pair of COMPLETE and ERROR events.
|
||||
|
||||
* In either case, the incremental backup data contained within the bitmap is
|
||||
safely rolled back, and the data within the bitmap is not lost. The image
|
||||
file created for the failed attempt can be safely deleted.
|
||||
|
||||
* Once the underlying problem is fixed (e.g. more storage space is freed up),
|
||||
you can simply retry the incremental backup command with the same bitmap.
|
||||
|
||||
### Example
|
||||
|
||||
1. Create a target image:
|
||||
|
||||
```sh
|
||||
# qemu-img create -f qcow2 incremental.0.img -b full_backup.img -F qcow2
|
||||
```
|
||||
|
||||
2. Attempt to create an incremental backup via QMP:
|
||||
|
||||
```json
|
||||
{ "execute": "drive-backup",
|
||||
"arguments": {
|
||||
"device": "drive0",
|
||||
"bitmap": "bitmap0",
|
||||
"target": "incremental.0.img",
|
||||
"format": "qcow2",
|
||||
"sync": "dirty-bitmap",
|
||||
"mode": "existing"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. Receive an event notifying us of failure:
|
||||
|
||||
```json
|
||||
{ "timestamp": { "seconds": 1424709442, "microseconds": 844524 },
|
||||
"data": { "speed": 0, "offset": 0, "len": 67108864,
|
||||
"error": "No space left on device",
|
||||
"device": "drive1", "type": "backup" },
|
||||
"event": "BLOCK_JOB_COMPLETED" }
|
||||
```
|
||||
|
||||
4. Delete the failed incremental, and re-create the image.
|
||||
|
||||
```sh
|
||||
# rm incremental.0.img
|
||||
# qemu-img create -f qcow2 incremental.0.img -b full_backup.img -F qcow2
|
||||
```
|
||||
|
||||
5. Retry the command after fixing the underlying problem,
|
||||
such as freeing up space on the backup volume:
|
||||
|
||||
```json
|
||||
{ "execute": "drive-backup",
|
||||
"arguments": {
|
||||
"device": "drive0",
|
||||
"bitmap": "bitmap0",
|
||||
"target": "incremental.0.img",
|
||||
"format": "qcow2",
|
||||
"sync": "dirty-bitmap",
|
||||
"mode": "existing"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
6. Receive confirmation that the job completed successfully:
|
||||
|
||||
```json
|
||||
{ "timestamp": { "seconds": 1424709668, "microseconds": 526525 },
|
||||
"data": { "device": "drive1", "type": "backup",
|
||||
"speed": 0, "len": 67108864, "offset": 67108864},
|
||||
"event": "BLOCK_JOB_COMPLETED" }
|
||||
```
|
||||
|
||||
<!--
|
||||
The FreeBSD Documentation License
|
||||
|
||||
Redistribution and use in source (Markdown) and 'compiled' forms (SGML, HTML,
|
||||
PDF, PostScript, RTF and so forth) with or without modification, are permitted
|
||||
provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code (Markdown) must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer of this file
|
||||
unmodified.
|
||||
|
||||
Redistributions in compiled form (transformed to other DTDs, converted to PDF,
|
||||
PostScript, RTF and other formats) must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
-->
|
@@ -31,21 +31,26 @@ Example:
|
||||
BLOCK_IMAGE_CORRUPTED
|
||||
---------------------
|
||||
|
||||
Emitted when a disk image is being marked corrupt.
|
||||
Emitted when a disk image is being marked corrupt. The image can be
|
||||
identified by its device or node name. The 'device' field is always
|
||||
present for compatibility reasons, but it can be empty ("") if the
|
||||
image does not have a device name associated.
|
||||
|
||||
Data:
|
||||
|
||||
- "device": Device name (json-string)
|
||||
- "msg": Informative message (e.g., reason for the corruption) (json-string)
|
||||
- "offset": If the corruption resulted from an image access, this is the access
|
||||
offset into the image (json-int)
|
||||
- "size": If the corruption resulted from an image access, this is the access
|
||||
size (json-int)
|
||||
- "device": Device name (json-string)
|
||||
- "node-name": Node name (json-string, optional)
|
||||
- "msg": Informative message (e.g., reason for the corruption)
|
||||
(json-string)
|
||||
- "offset": If the corruption resulted from an image access, this
|
||||
is the access offset into the image (json-int)
|
||||
- "size": If the corruption resulted from an image access, this
|
||||
is the access size (json-int)
|
||||
|
||||
Example:
|
||||
|
||||
{ "event": "BLOCK_IMAGE_CORRUPTED",
|
||||
"data": { "device": "ide0-hd0",
|
||||
"data": { "device": "ide0-hd0", "node-name": "node0",
|
||||
"msg": "Prevented active L1 table overwrite", "offset": 196608,
|
||||
"size": 65536 },
|
||||
"timestamp": { "seconds": 1378126126, "microseconds": 966463 } }
|
||||
|
521
exec.c
521
exec.c
@@ -380,7 +380,6 @@ MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr,
|
||||
IOMMUTLBEntry iotlb;
|
||||
MemoryRegionSection *section;
|
||||
MemoryRegion *mr;
|
||||
hwaddr len = *plen;
|
||||
|
||||
rcu_read_lock();
|
||||
for (;;) {
|
||||
@@ -395,7 +394,7 @@ MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr,
|
||||
iotlb = mr->iommu_ops->translate(mr, addr, is_write);
|
||||
addr = ((iotlb.translated_addr & ~iotlb.addr_mask)
|
||||
| (addr & iotlb.addr_mask));
|
||||
len = MIN(len, (addr | iotlb.addr_mask) - addr + 1);
|
||||
*plen = MIN(*plen, (addr | iotlb.addr_mask) - addr + 1);
|
||||
if (!(iotlb.perm & (1 << is_write))) {
|
||||
mr = &io_mem_unassigned;
|
||||
break;
|
||||
@@ -406,10 +405,9 @@ MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr,
|
||||
|
||||
if (xen_enabled() && memory_access_is_direct(mr, is_write)) {
|
||||
hwaddr page = ((addr & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE) - addr;
|
||||
len = MIN(page, len);
|
||||
*plen = MIN(page, *plen);
|
||||
}
|
||||
|
||||
*plen = len;
|
||||
*xlat = addr;
|
||||
rcu_read_unlock();
|
||||
return mr;
|
||||
@@ -429,15 +427,6 @@ address_space_translate_for_iotlb(CPUState *cpu, hwaddr addr,
|
||||
}
|
||||
#endif
|
||||
|
||||
void cpu_exec_init_all(void)
|
||||
{
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
qemu_mutex_init(&ram_list.mutex);
|
||||
memory_map_init();
|
||||
io_mem_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
|
||||
static int cpu_common_post_load(void *opaque, int version_id)
|
||||
@@ -1858,7 +1847,7 @@ static const MemoryRegionOps notdirty_mem_ops = {
|
||||
};
|
||||
|
||||
/* Generate a debug exception if a watchpoint has been hit. */
|
||||
static void check_watchpoint(int offset, int len, int flags)
|
||||
static void check_watchpoint(int offset, int len, MemTxAttrs attrs, int flags)
|
||||
{
|
||||
CPUState *cpu = current_cpu;
|
||||
CPUArchState *env = cpu->env_ptr;
|
||||
@@ -1884,6 +1873,7 @@ static void check_watchpoint(int offset, int len, int flags)
|
||||
wp->flags |= BP_WATCHPOINT_HIT_WRITE;
|
||||
}
|
||||
wp->hitaddr = vaddr;
|
||||
wp->hitattrs = attrs;
|
||||
if (!cpu->watchpoint_hit) {
|
||||
cpu->watchpoint_hit = wp;
|
||||
tb_check_watchpoint(cpu);
|
||||
@@ -1905,69 +1895,93 @@ static void check_watchpoint(int offset, int len, int flags)
|
||||
/* Watchpoint access routines. Watchpoints are inserted using TLB tricks,
|
||||
so these check for a hit then pass through to the normal out-of-line
|
||||
phys routines. */
|
||||
static uint64_t watch_mem_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
static MemTxResult watch_mem_read(void *opaque, hwaddr addr, uint64_t *pdata,
|
||||
unsigned size, MemTxAttrs attrs)
|
||||
{
|
||||
check_watchpoint(addr & ~TARGET_PAGE_MASK, size, BP_MEM_READ);
|
||||
switch (size) {
|
||||
case 1: return ldub_phys(&address_space_memory, addr);
|
||||
case 2: return lduw_phys(&address_space_memory, addr);
|
||||
case 4: return ldl_phys(&address_space_memory, addr);
|
||||
default: abort();
|
||||
}
|
||||
}
|
||||
MemTxResult res;
|
||||
uint64_t data;
|
||||
|
||||
static void watch_mem_write(void *opaque, hwaddr addr,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
check_watchpoint(addr & ~TARGET_PAGE_MASK, size, BP_MEM_WRITE);
|
||||
check_watchpoint(addr & ~TARGET_PAGE_MASK, size, attrs, BP_MEM_READ);
|
||||
switch (size) {
|
||||
case 1:
|
||||
stb_phys(&address_space_memory, addr, val);
|
||||
data = address_space_ldub(&address_space_memory, addr, attrs, &res);
|
||||
break;
|
||||
case 2:
|
||||
stw_phys(&address_space_memory, addr, val);
|
||||
data = address_space_lduw(&address_space_memory, addr, attrs, &res);
|
||||
break;
|
||||
case 4:
|
||||
stl_phys(&address_space_memory, addr, val);
|
||||
data = address_space_ldl(&address_space_memory, addr, attrs, &res);
|
||||
break;
|
||||
default: abort();
|
||||
}
|
||||
*pdata = data;
|
||||
return res;
|
||||
}
|
||||
|
||||
static MemTxResult watch_mem_write(void *opaque, hwaddr addr,
|
||||
uint64_t val, unsigned size,
|
||||
MemTxAttrs attrs)
|
||||
{
|
||||
MemTxResult res;
|
||||
|
||||
check_watchpoint(addr & ~TARGET_PAGE_MASK, size, attrs, BP_MEM_WRITE);
|
||||
switch (size) {
|
||||
case 1:
|
||||
address_space_stb(&address_space_memory, addr, val, attrs, &res);
|
||||
break;
|
||||
case 2:
|
||||
address_space_stw(&address_space_memory, addr, val, attrs, &res);
|
||||
break;
|
||||
case 4:
|
||||
address_space_stl(&address_space_memory, addr, val, attrs, &res);
|
||||
break;
|
||||
default: abort();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps watch_mem_ops = {
|
||||
.read = watch_mem_read,
|
||||
.write = watch_mem_write,
|
||||
.read_with_attrs = watch_mem_read,
|
||||
.write_with_attrs = watch_mem_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static uint64_t subpage_read(void *opaque, hwaddr addr,
|
||||
unsigned len)
|
||||
static MemTxResult subpage_read(void *opaque, hwaddr addr, uint64_t *data,
|
||||
unsigned len, MemTxAttrs attrs)
|
||||
{
|
||||
subpage_t *subpage = opaque;
|
||||
uint8_t buf[8];
|
||||
MemTxResult res;
|
||||
|
||||
#if defined(DEBUG_SUBPAGE)
|
||||
printf("%s: subpage %p len %u addr " TARGET_FMT_plx "\n", __func__,
|
||||
subpage, len, addr);
|
||||
#endif
|
||||
address_space_read(subpage->as, addr + subpage->base, buf, len);
|
||||
res = address_space_read(subpage->as, addr + subpage->base,
|
||||
attrs, buf, len);
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
switch (len) {
|
||||
case 1:
|
||||
return ldub_p(buf);
|
||||
*data = ldub_p(buf);
|
||||
return MEMTX_OK;
|
||||
case 2:
|
||||
return lduw_p(buf);
|
||||
*data = lduw_p(buf);
|
||||
return MEMTX_OK;
|
||||
case 4:
|
||||
return ldl_p(buf);
|
||||
*data = ldl_p(buf);
|
||||
return MEMTX_OK;
|
||||
case 8:
|
||||
return ldq_p(buf);
|
||||
*data = ldq_p(buf);
|
||||
return MEMTX_OK;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void subpage_write(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned len)
|
||||
static MemTxResult subpage_write(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned len, MemTxAttrs attrs)
|
||||
{
|
||||
subpage_t *subpage = opaque;
|
||||
uint8_t buf[8];
|
||||
@@ -1993,7 +2007,8 @@ static void subpage_write(void *opaque, hwaddr addr,
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
address_space_write(subpage->as, addr + subpage->base, buf, len);
|
||||
return address_space_write(subpage->as, addr + subpage->base,
|
||||
attrs, buf, len);
|
||||
}
|
||||
|
||||
static bool subpage_accepts(void *opaque, hwaddr addr,
|
||||
@@ -2010,8 +2025,8 @@ static bool subpage_accepts(void *opaque, hwaddr addr,
|
||||
}
|
||||
|
||||
static const MemoryRegionOps subpage_ops = {
|
||||
.read = subpage_read,
|
||||
.write = subpage_write,
|
||||
.read_with_attrs = subpage_read,
|
||||
.write_with_attrs = subpage_write,
|
||||
.impl.min_access_size = 1,
|
||||
.impl.max_access_size = 8,
|
||||
.valid.min_access_size = 1,
|
||||
@@ -2304,15 +2319,15 @@ static int memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr)
|
||||
return l;
|
||||
}
|
||||
|
||||
bool address_space_rw(AddressSpace *as, hwaddr addr, uint8_t *buf,
|
||||
int len, bool is_write)
|
||||
MemTxResult address_space_rw(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
|
||||
uint8_t *buf, int len, bool is_write)
|
||||
{
|
||||
hwaddr l;
|
||||
uint8_t *ptr;
|
||||
uint64_t val;
|
||||
hwaddr addr1;
|
||||
MemoryRegion *mr;
|
||||
bool error = false;
|
||||
MemTxResult result = MEMTX_OK;
|
||||
|
||||
while (len > 0) {
|
||||
l = len;
|
||||
@@ -2327,22 +2342,26 @@ bool address_space_rw(AddressSpace *as, hwaddr addr, uint8_t *buf,
|
||||
case 8:
|
||||
/* 64 bit write access */
|
||||
val = ldq_p(buf);
|
||||
error |= io_mem_write(mr, addr1, val, 8);
|
||||
result |= memory_region_dispatch_write(mr, addr1, val, 8,
|
||||
attrs);
|
||||
break;
|
||||
case 4:
|
||||
/* 32 bit write access */
|
||||
val = ldl_p(buf);
|
||||
error |= io_mem_write(mr, addr1, val, 4);
|
||||
result |= memory_region_dispatch_write(mr, addr1, val, 4,
|
||||
attrs);
|
||||
break;
|
||||
case 2:
|
||||
/* 16 bit write access */
|
||||
val = lduw_p(buf);
|
||||
error |= io_mem_write(mr, addr1, val, 2);
|
||||
result |= memory_region_dispatch_write(mr, addr1, val, 2,
|
||||
attrs);
|
||||
break;
|
||||
case 1:
|
||||
/* 8 bit write access */
|
||||
val = ldub_p(buf);
|
||||
error |= io_mem_write(mr, addr1, val, 1);
|
||||
result |= memory_region_dispatch_write(mr, addr1, val, 1,
|
||||
attrs);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
@@ -2361,22 +2380,26 @@ bool address_space_rw(AddressSpace *as, hwaddr addr, uint8_t *buf,
|
||||
switch (l) {
|
||||
case 8:
|
||||
/* 64 bit read access */
|
||||
error |= io_mem_read(mr, addr1, &val, 8);
|
||||
result |= memory_region_dispatch_read(mr, addr1, &val, 8,
|
||||
attrs);
|
||||
stq_p(buf, val);
|
||||
break;
|
||||
case 4:
|
||||
/* 32 bit read access */
|
||||
error |= io_mem_read(mr, addr1, &val, 4);
|
||||
result |= memory_region_dispatch_read(mr, addr1, &val, 4,
|
||||
attrs);
|
||||
stl_p(buf, val);
|
||||
break;
|
||||
case 2:
|
||||
/* 16 bit read access */
|
||||
error |= io_mem_read(mr, addr1, &val, 2);
|
||||
result |= memory_region_dispatch_read(mr, addr1, &val, 2,
|
||||
attrs);
|
||||
stw_p(buf, val);
|
||||
break;
|
||||
case 1:
|
||||
/* 8 bit read access */
|
||||
error |= io_mem_read(mr, addr1, &val, 1);
|
||||
result |= memory_region_dispatch_read(mr, addr1, &val, 1,
|
||||
attrs);
|
||||
stb_p(buf, val);
|
||||
break;
|
||||
default:
|
||||
@@ -2393,25 +2416,27 @@ bool address_space_rw(AddressSpace *as, hwaddr addr, uint8_t *buf,
|
||||
addr += l;
|
||||
}
|
||||
|
||||
return error;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool address_space_write(AddressSpace *as, hwaddr addr,
|
||||
const uint8_t *buf, int len)
|
||||
MemTxResult address_space_write(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
|
||||
const uint8_t *buf, int len)
|
||||
{
|
||||
return address_space_rw(as, addr, (uint8_t *)buf, len, true);
|
||||
return address_space_rw(as, addr, attrs, (uint8_t *)buf, len, true);
|
||||
}
|
||||
|
||||
bool address_space_read(AddressSpace *as, hwaddr addr, uint8_t *buf, int len)
|
||||
MemTxResult address_space_read(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
|
||||
uint8_t *buf, int len)
|
||||
{
|
||||
return address_space_rw(as, addr, buf, len, false);
|
||||
return address_space_rw(as, addr, attrs, buf, len, false);
|
||||
}
|
||||
|
||||
|
||||
void cpu_physical_memory_rw(hwaddr addr, uint8_t *buf,
|
||||
int len, int is_write)
|
||||
{
|
||||
address_space_rw(&address_space_memory, addr, buf, len, is_write);
|
||||
address_space_rw(&address_space_memory, addr, MEMTXATTRS_UNSPECIFIED,
|
||||
buf, len, is_write);
|
||||
}
|
||||
|
||||
enum write_rom_type {
|
||||
@@ -2482,48 +2507,79 @@ typedef struct {
|
||||
void *buffer;
|
||||
hwaddr addr;
|
||||
hwaddr len;
|
||||
bool in_use;
|
||||
} BounceBuffer;
|
||||
|
||||
static BounceBuffer bounce;
|
||||
|
||||
typedef struct MapClient {
|
||||
void *opaque;
|
||||
void (*callback)(void *opaque);
|
||||
QEMUBH *bh;
|
||||
QLIST_ENTRY(MapClient) link;
|
||||
} MapClient;
|
||||
|
||||
QemuMutex map_client_list_lock;
|
||||
static QLIST_HEAD(map_client_list, MapClient) map_client_list
|
||||
= QLIST_HEAD_INITIALIZER(map_client_list);
|
||||
|
||||
void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque))
|
||||
static void cpu_unregister_map_client_do(MapClient *client)
|
||||
{
|
||||
MapClient *client = g_malloc(sizeof(*client));
|
||||
|
||||
client->opaque = opaque;
|
||||
client->callback = callback;
|
||||
QLIST_INSERT_HEAD(&map_client_list, client, link);
|
||||
return client;
|
||||
}
|
||||
|
||||
static void cpu_unregister_map_client(void *_client)
|
||||
{
|
||||
MapClient *client = (MapClient *)_client;
|
||||
|
||||
QLIST_REMOVE(client, link);
|
||||
g_free(client);
|
||||
}
|
||||
|
||||
static void cpu_notify_map_clients(void)
|
||||
static void cpu_notify_map_clients_locked(void)
|
||||
{
|
||||
MapClient *client;
|
||||
|
||||
while (!QLIST_EMPTY(&map_client_list)) {
|
||||
client = QLIST_FIRST(&map_client_list);
|
||||
client->callback(client->opaque);
|
||||
cpu_unregister_map_client(client);
|
||||
qemu_bh_schedule(client->bh);
|
||||
cpu_unregister_map_client_do(client);
|
||||
}
|
||||
}
|
||||
|
||||
void cpu_register_map_client(QEMUBH *bh)
|
||||
{
|
||||
MapClient *client = g_malloc(sizeof(*client));
|
||||
|
||||
qemu_mutex_lock(&map_client_list_lock);
|
||||
client->bh = bh;
|
||||
QLIST_INSERT_HEAD(&map_client_list, client, link);
|
||||
if (!atomic_read(&bounce.in_use)) {
|
||||
cpu_notify_map_clients_locked();
|
||||
}
|
||||
qemu_mutex_unlock(&map_client_list_lock);
|
||||
}
|
||||
|
||||
void cpu_exec_init_all(void)
|
||||
{
|
||||
qemu_mutex_init(&ram_list.mutex);
|
||||
memory_map_init();
|
||||
io_mem_init();
|
||||
qemu_mutex_init(&map_client_list_lock);
|
||||
}
|
||||
|
||||
void cpu_unregister_map_client(QEMUBH *bh)
|
||||
{
|
||||
MapClient *client;
|
||||
|
||||
qemu_mutex_lock(&map_client_list_lock);
|
||||
QLIST_FOREACH(client, &map_client_list, link) {
|
||||
if (client->bh == bh) {
|
||||
cpu_unregister_map_client_do(client);
|
||||
break;
|
||||
}
|
||||
}
|
||||
qemu_mutex_unlock(&map_client_list_lock);
|
||||
}
|
||||
|
||||
static void cpu_notify_map_clients(void)
|
||||
{
|
||||
qemu_mutex_lock(&map_client_list_lock);
|
||||
cpu_notify_map_clients_locked();
|
||||
qemu_mutex_unlock(&map_client_list_lock);
|
||||
}
|
||||
|
||||
bool address_space_access_valid(AddressSpace *as, hwaddr addr, int len, bool is_write)
|
||||
{
|
||||
MemoryRegion *mr;
|
||||
@@ -2570,7 +2626,7 @@ void *address_space_map(AddressSpace *as,
|
||||
l = len;
|
||||
mr = address_space_translate(as, addr, &xlat, &l, is_write);
|
||||
if (!memory_access_is_direct(mr, is_write)) {
|
||||
if (bounce.buffer) {
|
||||
if (atomic_xchg(&bounce.in_use, true)) {
|
||||
return NULL;
|
||||
}
|
||||
/* Avoid unbounded allocations */
|
||||
@@ -2582,7 +2638,8 @@ void *address_space_map(AddressSpace *as,
|
||||
memory_region_ref(mr);
|
||||
bounce.mr = mr;
|
||||
if (!is_write) {
|
||||
address_space_read(as, addr, bounce.buffer, l);
|
||||
address_space_read(as, addr, MEMTXATTRS_UNSPECIFIED,
|
||||
bounce.buffer, l);
|
||||
}
|
||||
|
||||
*plen = l;
|
||||
@@ -2635,11 +2692,13 @@ void address_space_unmap(AddressSpace *as, void *buffer, hwaddr len,
|
||||
return;
|
||||
}
|
||||
if (is_write) {
|
||||
address_space_write(as, bounce.addr, bounce.buffer, access_len);
|
||||
address_space_write(as, bounce.addr, MEMTXATTRS_UNSPECIFIED,
|
||||
bounce.buffer, access_len);
|
||||
}
|
||||
qemu_vfree(bounce.buffer);
|
||||
bounce.buffer = NULL;
|
||||
memory_region_unref(bounce.mr);
|
||||
atomic_mb_set(&bounce.in_use, false);
|
||||
cpu_notify_map_clients();
|
||||
}
|
||||
|
||||
@@ -2657,19 +2716,22 @@ void cpu_physical_memory_unmap(void *buffer, hwaddr len,
|
||||
}
|
||||
|
||||
/* warning: addr must be aligned */
|
||||
static inline uint32_t ldl_phys_internal(AddressSpace *as, hwaddr addr,
|
||||
enum device_endian endian)
|
||||
static inline uint32_t address_space_ldl_internal(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs,
|
||||
MemTxResult *result,
|
||||
enum device_endian endian)
|
||||
{
|
||||
uint8_t *ptr;
|
||||
uint64_t val;
|
||||
MemoryRegion *mr;
|
||||
hwaddr l = 4;
|
||||
hwaddr addr1;
|
||||
MemTxResult r;
|
||||
|
||||
mr = address_space_translate(as, addr, &addr1, &l, false);
|
||||
if (l < 4 || !memory_access_is_direct(mr, false)) {
|
||||
/* I/O case */
|
||||
io_mem_read(mr, addr1, &val, 4);
|
||||
r = memory_region_dispatch_read(mr, addr1, &val, 4, attrs);
|
||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||
if (endian == DEVICE_LITTLE_ENDIAN) {
|
||||
val = bswap32(val);
|
||||
@@ -2695,40 +2757,68 @@ static inline uint32_t ldl_phys_internal(AddressSpace *as, hwaddr addr,
|
||||
val = ldl_p(ptr);
|
||||
break;
|
||||
}
|
||||
r = MEMTX_OK;
|
||||
}
|
||||
if (result) {
|
||||
*result = r;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
uint32_t address_space_ldl(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
return address_space_ldl_internal(as, addr, attrs, result,
|
||||
DEVICE_NATIVE_ENDIAN);
|
||||
}
|
||||
|
||||
uint32_t address_space_ldl_le(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
return address_space_ldl_internal(as, addr, attrs, result,
|
||||
DEVICE_LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
uint32_t address_space_ldl_be(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
return address_space_ldl_internal(as, addr, attrs, result,
|
||||
DEVICE_BIG_ENDIAN);
|
||||
}
|
||||
|
||||
uint32_t ldl_phys(AddressSpace *as, hwaddr addr)
|
||||
{
|
||||
return ldl_phys_internal(as, addr, DEVICE_NATIVE_ENDIAN);
|
||||
return address_space_ldl(as, addr, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
uint32_t ldl_le_phys(AddressSpace *as, hwaddr addr)
|
||||
{
|
||||
return ldl_phys_internal(as, addr, DEVICE_LITTLE_ENDIAN);
|
||||
return address_space_ldl_le(as, addr, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
uint32_t ldl_be_phys(AddressSpace *as, hwaddr addr)
|
||||
{
|
||||
return ldl_phys_internal(as, addr, DEVICE_BIG_ENDIAN);
|
||||
return address_space_ldl_be(as, addr, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
/* warning: addr must be aligned */
|
||||
static inline uint64_t ldq_phys_internal(AddressSpace *as, hwaddr addr,
|
||||
enum device_endian endian)
|
||||
static inline uint64_t address_space_ldq_internal(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs,
|
||||
MemTxResult *result,
|
||||
enum device_endian endian)
|
||||
{
|
||||
uint8_t *ptr;
|
||||
uint64_t val;
|
||||
MemoryRegion *mr;
|
||||
hwaddr l = 8;
|
||||
hwaddr addr1;
|
||||
MemTxResult r;
|
||||
|
||||
mr = address_space_translate(as, addr, &addr1, &l,
|
||||
false);
|
||||
if (l < 8 || !memory_access_is_direct(mr, false)) {
|
||||
/* I/O case */
|
||||
io_mem_read(mr, addr1, &val, 8);
|
||||
r = memory_region_dispatch_read(mr, addr1, &val, 8, attrs);
|
||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||
if (endian == DEVICE_LITTLE_ENDIAN) {
|
||||
val = bswap64(val);
|
||||
@@ -2754,48 +2844,88 @@ static inline uint64_t ldq_phys_internal(AddressSpace *as, hwaddr addr,
|
||||
val = ldq_p(ptr);
|
||||
break;
|
||||
}
|
||||
r = MEMTX_OK;
|
||||
}
|
||||
if (result) {
|
||||
*result = r;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
uint64_t address_space_ldq(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
return address_space_ldq_internal(as, addr, attrs, result,
|
||||
DEVICE_NATIVE_ENDIAN);
|
||||
}
|
||||
|
||||
uint64_t address_space_ldq_le(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
return address_space_ldq_internal(as, addr, attrs, result,
|
||||
DEVICE_LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
uint64_t address_space_ldq_be(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
return address_space_ldq_internal(as, addr, attrs, result,
|
||||
DEVICE_BIG_ENDIAN);
|
||||
}
|
||||
|
||||
uint64_t ldq_phys(AddressSpace *as, hwaddr addr)
|
||||
{
|
||||
return ldq_phys_internal(as, addr, DEVICE_NATIVE_ENDIAN);
|
||||
return address_space_ldq(as, addr, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
uint64_t ldq_le_phys(AddressSpace *as, hwaddr addr)
|
||||
{
|
||||
return ldq_phys_internal(as, addr, DEVICE_LITTLE_ENDIAN);
|
||||
return address_space_ldq_le(as, addr, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
uint64_t ldq_be_phys(AddressSpace *as, hwaddr addr)
|
||||
{
|
||||
return ldq_phys_internal(as, addr, DEVICE_BIG_ENDIAN);
|
||||
return address_space_ldq_be(as, addr, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
/* XXX: optimize */
|
||||
uint32_t ldub_phys(AddressSpace *as, hwaddr addr)
|
||||
uint32_t address_space_ldub(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
uint8_t val;
|
||||
address_space_rw(as, addr, &val, 1, 0);
|
||||
MemTxResult r;
|
||||
|
||||
r = address_space_rw(as, addr, attrs, &val, 1, 0);
|
||||
if (result) {
|
||||
*result = r;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
uint32_t ldub_phys(AddressSpace *as, hwaddr addr)
|
||||
{
|
||||
return address_space_ldub(as, addr, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
/* warning: addr must be aligned */
|
||||
static inline uint32_t lduw_phys_internal(AddressSpace *as, hwaddr addr,
|
||||
enum device_endian endian)
|
||||
static inline uint32_t address_space_lduw_internal(AddressSpace *as,
|
||||
hwaddr addr,
|
||||
MemTxAttrs attrs,
|
||||
MemTxResult *result,
|
||||
enum device_endian endian)
|
||||
{
|
||||
uint8_t *ptr;
|
||||
uint64_t val;
|
||||
MemoryRegion *mr;
|
||||
hwaddr l = 2;
|
||||
hwaddr addr1;
|
||||
MemTxResult r;
|
||||
|
||||
mr = address_space_translate(as, addr, &addr1, &l,
|
||||
false);
|
||||
if (l < 2 || !memory_access_is_direct(mr, false)) {
|
||||
/* I/O case */
|
||||
io_mem_read(mr, addr1, &val, 2);
|
||||
r = memory_region_dispatch_read(mr, addr1, &val, 2, attrs);
|
||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||
if (endian == DEVICE_LITTLE_ENDIAN) {
|
||||
val = bswap16(val);
|
||||
@@ -2821,39 +2951,66 @@ static inline uint32_t lduw_phys_internal(AddressSpace *as, hwaddr addr,
|
||||
val = lduw_p(ptr);
|
||||
break;
|
||||
}
|
||||
r = MEMTX_OK;
|
||||
}
|
||||
if (result) {
|
||||
*result = r;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
uint32_t address_space_lduw(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
return address_space_lduw_internal(as, addr, attrs, result,
|
||||
DEVICE_NATIVE_ENDIAN);
|
||||
}
|
||||
|
||||
uint32_t address_space_lduw_le(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
return address_space_lduw_internal(as, addr, attrs, result,
|
||||
DEVICE_LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
uint32_t address_space_lduw_be(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
return address_space_lduw_internal(as, addr, attrs, result,
|
||||
DEVICE_BIG_ENDIAN);
|
||||
}
|
||||
|
||||
uint32_t lduw_phys(AddressSpace *as, hwaddr addr)
|
||||
{
|
||||
return lduw_phys_internal(as, addr, DEVICE_NATIVE_ENDIAN);
|
||||
return address_space_lduw(as, addr, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
uint32_t lduw_le_phys(AddressSpace *as, hwaddr addr)
|
||||
{
|
||||
return lduw_phys_internal(as, addr, DEVICE_LITTLE_ENDIAN);
|
||||
return address_space_lduw_le(as, addr, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
uint32_t lduw_be_phys(AddressSpace *as, hwaddr addr)
|
||||
{
|
||||
return lduw_phys_internal(as, addr, DEVICE_BIG_ENDIAN);
|
||||
return address_space_lduw_be(as, addr, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
/* warning: addr must be aligned. The ram page is not masked as dirty
|
||||
and the code inside is not invalidated. It is useful if the dirty
|
||||
bits are used to track modified PTEs */
|
||||
void stl_phys_notdirty(AddressSpace *as, hwaddr addr, uint32_t val)
|
||||
void address_space_stl_notdirty(AddressSpace *as, hwaddr addr, uint32_t val,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
uint8_t *ptr;
|
||||
MemoryRegion *mr;
|
||||
hwaddr l = 4;
|
||||
hwaddr addr1;
|
||||
MemTxResult r;
|
||||
|
||||
mr = address_space_translate(as, addr, &addr1, &l,
|
||||
true);
|
||||
if (l < 4 || !memory_access_is_direct(mr, true)) {
|
||||
io_mem_write(mr, addr1, val, 4);
|
||||
r = memory_region_dispatch_write(mr, addr1, val, 4, attrs);
|
||||
} else {
|
||||
addr1 += memory_region_get_ram_addr(mr) & TARGET_PAGE_MASK;
|
||||
ptr = qemu_get_ram_ptr(addr1);
|
||||
@@ -2867,18 +3024,30 @@ void stl_phys_notdirty(AddressSpace *as, hwaddr addr, uint32_t val)
|
||||
cpu_physical_memory_set_dirty_range_nocode(addr1, 4);
|
||||
}
|
||||
}
|
||||
r = MEMTX_OK;
|
||||
}
|
||||
if (result) {
|
||||
*result = r;
|
||||
}
|
||||
}
|
||||
|
||||
void stl_phys_notdirty(AddressSpace *as, hwaddr addr, uint32_t val)
|
||||
{
|
||||
address_space_stl_notdirty(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
/* warning: addr must be aligned */
|
||||
static inline void stl_phys_internal(AddressSpace *as,
|
||||
hwaddr addr, uint32_t val,
|
||||
enum device_endian endian)
|
||||
static inline void address_space_stl_internal(AddressSpace *as,
|
||||
hwaddr addr, uint32_t val,
|
||||
MemTxAttrs attrs,
|
||||
MemTxResult *result,
|
||||
enum device_endian endian)
|
||||
{
|
||||
uint8_t *ptr;
|
||||
MemoryRegion *mr;
|
||||
hwaddr l = 4;
|
||||
hwaddr addr1;
|
||||
MemTxResult r;
|
||||
|
||||
mr = address_space_translate(as, addr, &addr1, &l,
|
||||
true);
|
||||
@@ -2892,7 +3061,7 @@ static inline void stl_phys_internal(AddressSpace *as,
|
||||
val = bswap32(val);
|
||||
}
|
||||
#endif
|
||||
io_mem_write(mr, addr1, val, 4);
|
||||
r = memory_region_dispatch_write(mr, addr1, val, 4, attrs);
|
||||
} else {
|
||||
/* RAM case */
|
||||
addr1 += memory_region_get_ram_addr(mr) & TARGET_PAGE_MASK;
|
||||
@@ -2909,40 +3078,79 @@ static inline void stl_phys_internal(AddressSpace *as,
|
||||
break;
|
||||
}
|
||||
invalidate_and_set_dirty(addr1, 4);
|
||||
r = MEMTX_OK;
|
||||
}
|
||||
if (result) {
|
||||
*result = r;
|
||||
}
|
||||
}
|
||||
|
||||
void address_space_stl(AddressSpace *as, hwaddr addr, uint32_t val,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
address_space_stl_internal(as, addr, val, attrs, result,
|
||||
DEVICE_NATIVE_ENDIAN);
|
||||
}
|
||||
|
||||
void address_space_stl_le(AddressSpace *as, hwaddr addr, uint32_t val,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
address_space_stl_internal(as, addr, val, attrs, result,
|
||||
DEVICE_LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
void address_space_stl_be(AddressSpace *as, hwaddr addr, uint32_t val,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
address_space_stl_internal(as, addr, val, attrs, result,
|
||||
DEVICE_BIG_ENDIAN);
|
||||
}
|
||||
|
||||
void stl_phys(AddressSpace *as, hwaddr addr, uint32_t val)
|
||||
{
|
||||
stl_phys_internal(as, addr, val, DEVICE_NATIVE_ENDIAN);
|
||||
address_space_stl(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
void stl_le_phys(AddressSpace *as, hwaddr addr, uint32_t val)
|
||||
{
|
||||
stl_phys_internal(as, addr, val, DEVICE_LITTLE_ENDIAN);
|
||||
address_space_stl_le(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
void stl_be_phys(AddressSpace *as, hwaddr addr, uint32_t val)
|
||||
{
|
||||
stl_phys_internal(as, addr, val, DEVICE_BIG_ENDIAN);
|
||||
address_space_stl_be(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
/* XXX: optimize */
|
||||
void stb_phys(AddressSpace *as, hwaddr addr, uint32_t val)
|
||||
void address_space_stb(AddressSpace *as, hwaddr addr, uint32_t val,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
uint8_t v = val;
|
||||
address_space_rw(as, addr, &v, 1, 1);
|
||||
MemTxResult r;
|
||||
|
||||
r = address_space_rw(as, addr, attrs, &v, 1, 1);
|
||||
if (result) {
|
||||
*result = r;
|
||||
}
|
||||
}
|
||||
|
||||
void stb_phys(AddressSpace *as, hwaddr addr, uint32_t val)
|
||||
{
|
||||
address_space_stb(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
/* warning: addr must be aligned */
|
||||
static inline void stw_phys_internal(AddressSpace *as,
|
||||
hwaddr addr, uint32_t val,
|
||||
enum device_endian endian)
|
||||
static inline void address_space_stw_internal(AddressSpace *as,
|
||||
hwaddr addr, uint32_t val,
|
||||
MemTxAttrs attrs,
|
||||
MemTxResult *result,
|
||||
enum device_endian endian)
|
||||
{
|
||||
uint8_t *ptr;
|
||||
MemoryRegion *mr;
|
||||
hwaddr l = 2;
|
||||
hwaddr addr1;
|
||||
MemTxResult r;
|
||||
|
||||
mr = address_space_translate(as, addr, &addr1, &l, true);
|
||||
if (l < 2 || !memory_access_is_direct(mr, true)) {
|
||||
@@ -2955,7 +3163,7 @@ static inline void stw_phys_internal(AddressSpace *as,
|
||||
val = bswap16(val);
|
||||
}
|
||||
#endif
|
||||
io_mem_write(mr, addr1, val, 2);
|
||||
r = memory_region_dispatch_write(mr, addr1, val, 2, attrs);
|
||||
} else {
|
||||
/* RAM case */
|
||||
addr1 += memory_region_get_ram_addr(mr) & TARGET_PAGE_MASK;
|
||||
@@ -2972,41 +3180,95 @@ static inline void stw_phys_internal(AddressSpace *as,
|
||||
break;
|
||||
}
|
||||
invalidate_and_set_dirty(addr1, 2);
|
||||
r = MEMTX_OK;
|
||||
}
|
||||
if (result) {
|
||||
*result = r;
|
||||
}
|
||||
}
|
||||
|
||||
void address_space_stw(AddressSpace *as, hwaddr addr, uint32_t val,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
address_space_stw_internal(as, addr, val, attrs, result,
|
||||
DEVICE_NATIVE_ENDIAN);
|
||||
}
|
||||
|
||||
void address_space_stw_le(AddressSpace *as, hwaddr addr, uint32_t val,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
address_space_stw_internal(as, addr, val, attrs, result,
|
||||
DEVICE_LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
void address_space_stw_be(AddressSpace *as, hwaddr addr, uint32_t val,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
address_space_stw_internal(as, addr, val, attrs, result,
|
||||
DEVICE_BIG_ENDIAN);
|
||||
}
|
||||
|
||||
void stw_phys(AddressSpace *as, hwaddr addr, uint32_t val)
|
||||
{
|
||||
stw_phys_internal(as, addr, val, DEVICE_NATIVE_ENDIAN);
|
||||
address_space_stw(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
void stw_le_phys(AddressSpace *as, hwaddr addr, uint32_t val)
|
||||
{
|
||||
stw_phys_internal(as, addr, val, DEVICE_LITTLE_ENDIAN);
|
||||
address_space_stw_le(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
void stw_be_phys(AddressSpace *as, hwaddr addr, uint32_t val)
|
||||
{
|
||||
stw_phys_internal(as, addr, val, DEVICE_BIG_ENDIAN);
|
||||
address_space_stw_be(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
/* XXX: optimize */
|
||||
void address_space_stq(AddressSpace *as, hwaddr addr, uint64_t val,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
MemTxResult r;
|
||||
val = tswap64(val);
|
||||
r = address_space_rw(as, addr, attrs, (void *) &val, 8, 1);
|
||||
if (result) {
|
||||
*result = r;
|
||||
}
|
||||
}
|
||||
|
||||
void address_space_stq_le(AddressSpace *as, hwaddr addr, uint64_t val,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
MemTxResult r;
|
||||
val = cpu_to_le64(val);
|
||||
r = address_space_rw(as, addr, attrs, (void *) &val, 8, 1);
|
||||
if (result) {
|
||||
*result = r;
|
||||
}
|
||||
}
|
||||
void address_space_stq_be(AddressSpace *as, hwaddr addr, uint64_t val,
|
||||
MemTxAttrs attrs, MemTxResult *result)
|
||||
{
|
||||
MemTxResult r;
|
||||
val = cpu_to_be64(val);
|
||||
r = address_space_rw(as, addr, attrs, (void *) &val, 8, 1);
|
||||
if (result) {
|
||||
*result = r;
|
||||
}
|
||||
}
|
||||
|
||||
void stq_phys(AddressSpace *as, hwaddr addr, uint64_t val)
|
||||
{
|
||||
val = tswap64(val);
|
||||
address_space_rw(as, addr, (void *) &val, 8, 1);
|
||||
address_space_stq(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
void stq_le_phys(AddressSpace *as, hwaddr addr, uint64_t val)
|
||||
{
|
||||
val = cpu_to_le64(val);
|
||||
address_space_rw(as, addr, (void *) &val, 8, 1);
|
||||
address_space_stq_le(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
void stq_be_phys(AddressSpace *as, hwaddr addr, uint64_t val)
|
||||
{
|
||||
val = cpu_to_be64(val);
|
||||
address_space_rw(as, addr, (void *) &val, 8, 1);
|
||||
address_space_stq_be(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
/* virtual memory access for debug (includes writing to ROM) */
|
||||
@@ -3030,7 +3292,8 @@ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
|
||||
if (is_write) {
|
||||
cpu_physical_memory_write_rom(cpu->as, phys_addr, buf, l);
|
||||
} else {
|
||||
address_space_rw(cpu->as, phys_addr, buf, l, 0);
|
||||
address_space_rw(cpu->as, phys_addr, MEMTXATTRS_UNSPECIFIED,
|
||||
buf, l, 0);
|
||||
}
|
||||
len -= l;
|
||||
buf += l;
|
||||
|
@@ -998,8 +998,7 @@ ETEXI
|
||||
.params = "protocol hostname port tls-port cert-subject",
|
||||
.help = "send migration info to spice/vnc client",
|
||||
.user_print = monitor_user_noop,
|
||||
.mhandler.cmd_async = client_migrate_info,
|
||||
.flags = MONITOR_CMD_ASYNC,
|
||||
.mhandler.cmd_new = client_migrate_info,
|
||||
},
|
||||
|
||||
STEXI
|
||||
|
6
hmp.c
6
hmp.c
@@ -391,8 +391,7 @@ static void print_block_info(Monitor *mon, BlockInfo *info,
|
||||
inserted->iops_size);
|
||||
}
|
||||
|
||||
/* TODO: inserted->image should never be null */
|
||||
if (verbose && inserted->image) {
|
||||
if (verbose) {
|
||||
monitor_printf(mon, "\nImages:\n");
|
||||
image_info = inserted->image;
|
||||
while (1) {
|
||||
@@ -1062,7 +1061,8 @@ void hmp_drive_backup(Monitor *mon, const QDict *qdict)
|
||||
|
||||
qmp_drive_backup(device, filename, !!format, format,
|
||||
full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP,
|
||||
true, mode, false, 0, false, 0, false, 0, &err);
|
||||
true, mode, false, 0, false, NULL,
|
||||
false, 0, false, 0, &err);
|
||||
hmp_handle_error(mon, &err);
|
||||
}
|
||||
|
||||
|
1
hmp.h
1
hmp.h
@@ -109,7 +109,6 @@ void set_link_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||
void netdev_add_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||
void netdev_del_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||
void ringbuf_write_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||
void ringbuf_read_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||
void watchdog_action_completion(ReadLineState *rs, int nb_args,
|
||||
const char *str);
|
||||
void migrate_set_capability_completion(ReadLineState *rs, int nb_args,
|
||||
|
@@ -31,7 +31,6 @@
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/acpi/acpi.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "qemu/range.h"
|
||||
#include "exec/ioport.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/pci/pci_bus.h"
|
||||
@@ -120,7 +119,7 @@ static bool acpi_pcihp_pc_no_hotplug(AcpiPciHpState *s, PCIDevice *dev)
|
||||
static void acpi_pcihp_eject_slot(AcpiPciHpState *s, unsigned bsel, unsigned slots)
|
||||
{
|
||||
BusChild *kid, *next;
|
||||
int slot = ffs(slots) - 1;
|
||||
int slot = ctz32(slots);
|
||||
PCIBus *bus = acpi_pcihp_find_hotplug_bus(s, bsel);
|
||||
|
||||
if (!bus) {
|
||||
|
@@ -157,9 +157,12 @@ static void clipper_init(MachineState *machine)
|
||||
load_image_targphys(initrd_filename, initrd_base,
|
||||
ram_size - initrd_base);
|
||||
|
||||
stq_phys(&address_space_memory,
|
||||
param_offset + 0x100, initrd_base + 0xfffffc0000000000ULL);
|
||||
stq_phys(&address_space_memory, param_offset + 0x108, initrd_size);
|
||||
address_space_stq(&address_space_memory, param_offset + 0x100,
|
||||
initrd_base + 0xfffffc0000000000ULL,
|
||||
MEMTXATTRS_UNSPECIFIED,
|
||||
NULL);
|
||||
address_space_stq(&address_space_memory, param_offset + 0x108,
|
||||
initrd_size, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -613,7 +613,8 @@ static bool make_iommu_tlbe(hwaddr taddr, hwaddr mask, IOMMUTLBEntry *ret)
|
||||
translation, given the address of the PTE. */
|
||||
static bool pte_translate(hwaddr pte_addr, IOMMUTLBEntry *ret)
|
||||
{
|
||||
uint64_t pte = ldq_phys(&address_space_memory, pte_addr);
|
||||
uint64_t pte = address_space_ldq(&address_space_memory, pte_addr,
|
||||
MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
|
||||
/* Check valid bit. */
|
||||
if ((pte & 1) == 0) {
|
||||
|
@@ -170,7 +170,8 @@ static void default_reset_secondary(ARMCPU *cpu,
|
||||
{
|
||||
CPUARMState *env = &cpu->env;
|
||||
|
||||
stl_phys_notdirty(&address_space_memory, info->smp_bootreg_addr, 0);
|
||||
address_space_stl_notdirty(&address_space_memory, info->smp_bootreg_addr,
|
||||
0, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
env->regs[15] = info->smp_loader_start;
|
||||
}
|
||||
|
||||
@@ -180,7 +181,8 @@ static inline bool have_dtb(const struct arm_boot_info *info)
|
||||
}
|
||||
|
||||
#define WRITE_WORD(p, value) do { \
|
||||
stl_phys_notdirty(&address_space_memory, p, value); \
|
||||
address_space_stl_notdirty(&address_space_memory, p, value, \
|
||||
MEMTXATTRS_UNSPECIFIED, NULL); \
|
||||
p += 4; \
|
||||
} while (0)
|
||||
|
||||
|
@@ -69,11 +69,17 @@ static void hb_reset_secondary(ARMCPU *cpu, const struct arm_boot_info *info)
|
||||
|
||||
switch (info->nb_cpus) {
|
||||
case 4:
|
||||
stl_phys_notdirty(&address_space_memory, SMP_BOOT_REG + 0x30, 0);
|
||||
address_space_stl_notdirty(&address_space_memory,
|
||||
SMP_BOOT_REG + 0x30, 0,
|
||||
MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
case 3:
|
||||
stl_phys_notdirty(&address_space_memory, SMP_BOOT_REG + 0x20, 0);
|
||||
address_space_stl_notdirty(&address_space_memory,
|
||||
SMP_BOOT_REG + 0x20, 0,
|
||||
MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
case 2:
|
||||
stl_phys_notdirty(&address_space_memory, SMP_BOOT_REG + 0x10, 0);
|
||||
address_space_stl_notdirty(&address_space_memory,
|
||||
SMP_BOOT_REG + 0x10, 0,
|
||||
MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
env->regs[15] = SMP_BOOT_ADDR;
|
||||
break;
|
||||
default:
|
||||
|
@@ -579,7 +579,10 @@ static uint32_t mipid_txrx(void *opaque, uint32_t cmd, int len)
|
||||
|
||||
case 0x26: /* GAMSET */
|
||||
if (!s->pm) {
|
||||
s->gamma = ffs(s->param[0] & 0xf) - 1;
|
||||
s->gamma = ctz32(s->param[0] & 0xf);
|
||||
if (s->gamma == 32) {
|
||||
s->gamma = -1; /* XXX: should this be 0? */
|
||||
}
|
||||
} else if (s->pm < 0) {
|
||||
s->pm = 1;
|
||||
}
|
||||
|
@@ -2004,8 +2004,7 @@ static void omap_mpuio_write(void *opaque, hwaddr addr,
|
||||
case 0x04: /* OUTPUT_REG */
|
||||
diff = (s->outputs ^ value) & ~s->dir;
|
||||
s->outputs = value;
|
||||
while ((ln = ffs(diff))) {
|
||||
ln --;
|
||||
while ((ln = ctz32(diff)) != 32) {
|
||||
if (s->handler[ln])
|
||||
qemu_set_irq(s->handler[ln], (value >> ln) & 1);
|
||||
diff &= ~(1 << ln);
|
||||
@@ -2017,8 +2016,7 @@ static void omap_mpuio_write(void *opaque, hwaddr addr,
|
||||
s->dir = value;
|
||||
|
||||
value = s->outputs & ~s->dir;
|
||||
while ((ln = ffs(diff))) {
|
||||
ln --;
|
||||
while ((ln = ctz32(diff)) != 32) {
|
||||
if (s->handler[ln])
|
||||
qemu_set_irq(s->handler[ln], (value >> ln) & 1);
|
||||
diff &= ~(1 << ln);
|
||||
|
@@ -274,7 +274,7 @@ static void pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
s->cpu->env.uncached_cpsr = ARM_CPU_MODE_SVC;
|
||||
s->cpu->env.daif = PSTATE_A | PSTATE_F | PSTATE_I;
|
||||
s->cpu->env.cp15.sctlr_ns = 0;
|
||||
s->cpu->env.cp15.c1_coproc = 0;
|
||||
s->cpu->env.cp15.cpacr_el1 = 0;
|
||||
s->cpu->env.cp15.ttbr0_el[1] = 0;
|
||||
s->cpu->env.cp15.dacr_ns = 0;
|
||||
s->pm_regs[PSSR >> 2] |= 0x8; /* Set STS */
|
||||
|
@@ -137,7 +137,7 @@ static void pxa2xx_gpio_handler_update(PXA2xxGPIOInfo *s) {
|
||||
level = s->olevel[i] & s->dir[i];
|
||||
|
||||
for (diff = s->prev_level[i] ^ level; diff; diff ^= 1 << bit) {
|
||||
bit = ffs(diff) - 1;
|
||||
bit = ctz32(diff);
|
||||
line = bit + 32 * i;
|
||||
qemu_set_irq(s->handler[line], (level >> bit) & 1);
|
||||
}
|
||||
|
@@ -528,7 +528,7 @@ static void strongarm_gpio_handler_update(StrongARMGPIOInfo *s)
|
||||
level = s->olevel & s->dir;
|
||||
|
||||
for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) {
|
||||
bit = ffs(diff) - 1;
|
||||
bit = ctz32(diff);
|
||||
qemu_set_irq(s->handler[bit], (level >> bit) & 1);
|
||||
}
|
||||
|
||||
@@ -745,7 +745,7 @@ static void strongarm_ppc_handler_update(StrongARMPPCInfo *s)
|
||||
level = s->olevel & s->dir;
|
||||
|
||||
for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) {
|
||||
bit = ffs(diff) - 1;
|
||||
bit = ctz32(diff);
|
||||
qemu_set_irq(s->handler[bit], (level >> bit) & 1);
|
||||
}
|
||||
|
||||
|
@@ -71,13 +71,6 @@ IO_READ_PROTO (gus_readb)
|
||||
return gus_read (&s->emu, nport, 1);
|
||||
}
|
||||
|
||||
IO_READ_PROTO (gus_readw)
|
||||
{
|
||||
GUSState *s = opaque;
|
||||
|
||||
return gus_read (&s->emu, nport, 2);
|
||||
}
|
||||
|
||||
IO_WRITE_PROTO (gus_writeb)
|
||||
{
|
||||
GUSState *s = opaque;
|
||||
@@ -85,13 +78,6 @@ IO_WRITE_PROTO (gus_writeb)
|
||||
gus_write (&s->emu, nport, 1, val);
|
||||
}
|
||||
|
||||
IO_WRITE_PROTO (gus_writew)
|
||||
{
|
||||
GUSState *s = opaque;
|
||||
|
||||
gus_write (&s->emu, nport, 2, val);
|
||||
}
|
||||
|
||||
static int write_audio (GUSState *s, int samples)
|
||||
{
|
||||
int net = 0;
|
||||
@@ -236,17 +222,13 @@ static const VMStateDescription vmstate_gus = {
|
||||
|
||||
static const MemoryRegionPortio gus_portio_list1[] = {
|
||||
{0x000, 1, 1, .write = gus_writeb },
|
||||
{0x000, 1, 2, .write = gus_writew },
|
||||
{0x006, 10, 1, .read = gus_readb, .write = gus_writeb },
|
||||
{0x006, 10, 2, .read = gus_readw, .write = gus_writew },
|
||||
{0x100, 8, 1, .read = gus_readb, .write = gus_writeb },
|
||||
{0x100, 8, 2, .read = gus_readw, .write = gus_writew },
|
||||
PORTIO_END_OF_LIST (),
|
||||
};
|
||||
|
||||
static const MemoryRegionPortio gus_portio_list2[] = {
|
||||
{0, 1, 1, .read = gus_readb },
|
||||
{0, 1, 2, .read = gus_readw },
|
||||
{0, 2, 1, .read = gus_readb },
|
||||
PORTIO_END_OF_LIST (),
|
||||
};
|
||||
|
||||
|
@@ -1121,12 +1121,6 @@ static IO_WRITE_PROTO (mixer_write_datab)
|
||||
s->mixer_regs[s->mixer_nreg] = val;
|
||||
}
|
||||
|
||||
static IO_WRITE_PROTO (mixer_write_indexw)
|
||||
{
|
||||
mixer_write_indexb (opaque, nport, val & 0xff);
|
||||
mixer_write_datab (opaque, nport, (val >> 8) & 0xff);
|
||||
}
|
||||
|
||||
static IO_READ_PROTO (mixer_read)
|
||||
{
|
||||
SB16State *s = opaque;
|
||||
@@ -1345,7 +1339,6 @@ static const VMStateDescription vmstate_sb16 = {
|
||||
|
||||
static const MemoryRegionPortio sb16_ioport_list[] = {
|
||||
{ 4, 1, 1, .write = mixer_write_indexb },
|
||||
{ 4, 1, 2, .write = mixer_write_indexw },
|
||||
{ 5, 1, 1, .read = mixer_read, .write = mixer_write_datab },
|
||||
{ 6, 1, 1, .read = dsp_read, .write = dsp_write },
|
||||
{ 10, 1, 1, .read = dsp_read },
|
||||
|
@@ -535,8 +535,6 @@ struct FDCtrl {
|
||||
uint8_t pwrd;
|
||||
/* Floppy drives */
|
||||
uint8_t num_floppies;
|
||||
/* Sun4m quirks? */
|
||||
int sun4m;
|
||||
FDrive drives[MAX_FD];
|
||||
int reset_sensei;
|
||||
uint32_t check_media_rate;
|
||||
@@ -885,13 +883,6 @@ static void fdctrl_reset_irq(FDCtrl *fdctrl)
|
||||
|
||||
static void fdctrl_raise_irq(FDCtrl *fdctrl)
|
||||
{
|
||||
/* Sparc mutation */
|
||||
if (fdctrl->sun4m && (fdctrl->msr & FD_MSR_CMDBUSY)) {
|
||||
/* XXX: not sure */
|
||||
fdctrl->msr &= ~FD_MSR_CMDBUSY;
|
||||
fdctrl->msr |= FD_MSR_RQM | FD_MSR_DIO;
|
||||
return;
|
||||
}
|
||||
if (!(fdctrl->sra & FD_SRA_INTPEND)) {
|
||||
qemu_set_irq(fdctrl->irq, 1);
|
||||
fdctrl->sra |= FD_SRA_INTPEND;
|
||||
@@ -1080,12 +1071,6 @@ static uint32_t fdctrl_read_main_status(FDCtrl *fdctrl)
|
||||
fdctrl->dsr &= ~FD_DSR_PWRDOWN;
|
||||
fdctrl->dor |= FD_DOR_nRESET;
|
||||
|
||||
/* Sparc mutation */
|
||||
if (fdctrl->sun4m) {
|
||||
retval |= FD_MSR_DIO;
|
||||
fdctrl_reset_irq(fdctrl);
|
||||
};
|
||||
|
||||
FLOPPY_DPRINTF("main status register: 0x%02x\n", retval);
|
||||
|
||||
return retval;
|
||||
@@ -2241,8 +2226,6 @@ static void sun4m_fdc_initfn(Object *obj)
|
||||
FDCtrlSysBus *sys = SYSBUS_FDC(obj);
|
||||
FDCtrl *fdctrl = &sys->state;
|
||||
|
||||
fdctrl->sun4m = 1;
|
||||
|
||||
memory_region_init_io(&fdctrl->iomem, obj, &fdctrl_mem_strict_ops,
|
||||
fdctrl, "fdctrl", 0x08);
|
||||
sysbus_init_mmio(sbd, &fdctrl->iomem);
|
||||
|
@@ -621,7 +621,6 @@ static int m25p80_init(SSISlave *ss)
|
||||
|
||||
s->size = s->pi->sector_size * s->pi->n_sectors;
|
||||
s->dirty_page = -1;
|
||||
s->storage = blk_blockalign(s->blk, s->size);
|
||||
|
||||
/* FIXME use a qdev drive property instead of drive_get_next() */
|
||||
dinfo = drive_get_next(IF_MTD);
|
||||
@@ -629,6 +628,9 @@ static int m25p80_init(SSISlave *ss)
|
||||
if (dinfo) {
|
||||
DB_PRINT_L(0, "Binding to IF_MTD drive\n");
|
||||
s->blk = blk_by_legacy_dinfo(dinfo);
|
||||
blk_attach_dev_nofail(s->blk, s);
|
||||
|
||||
s->storage = blk_blockalign(s->blk, s->size);
|
||||
|
||||
/* FIXME: Move to late init */
|
||||
if (blk_read(s->blk, 0, s->storage,
|
||||
@@ -638,6 +640,7 @@ static int m25p80_init(SSISlave *ss)
|
||||
}
|
||||
} else {
|
||||
DB_PRINT_L(0, "No BDRV - binding to RAM\n");
|
||||
s->storage = blk_blockalign(NULL, s->size);
|
||||
memset(s->storage, 0xFF, s->size);
|
||||
}
|
||||
|
||||
|
@@ -615,6 +615,13 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data,
|
||||
n->bar.intmc = n->bar.intms;
|
||||
break;
|
||||
case 0x14:
|
||||
/* Windows first sends data, then sends enable bit */
|
||||
if (!NVME_CC_EN(data) && !NVME_CC_EN(n->bar.cc) &&
|
||||
!NVME_CC_SHN(data) && !NVME_CC_SHN(n->bar.cc))
|
||||
{
|
||||
n->bar.cc = data;
|
||||
}
|
||||
|
||||
if (NVME_CC_EN(data) && !NVME_CC_EN(n->bar.cc)) {
|
||||
n->bar.cc = data;
|
||||
if (nvme_start_ctrl(n)) {
|
||||
|
@@ -515,7 +515,7 @@ void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
|
||||
type = virtio_ldl_p(VIRTIO_DEVICE(req->dev), &req->out.type);
|
||||
|
||||
/* VIRTIO_BLK_T_OUT defines the command direction. VIRTIO_BLK_T_BARRIER
|
||||
* is an optional flag. Altough a guest should not send this flag if
|
||||
* is an optional flag. Although a guest should not send this flag if
|
||||
* not negotiated we ignored it in the past. So keep ignoring it. */
|
||||
switch (type & ~(VIRTIO_BLK_T_OUT | VIRTIO_BLK_T_BARRIER)) {
|
||||
case VIRTIO_BLK_T_IN:
|
||||
|
@@ -707,7 +707,7 @@ static void sdp_service_record_build(struct sdp_service_record_s *record,
|
||||
len += sdp_attr_max_size(&def->attributes[record->attributes ++].data,
|
||||
&record->uuids);
|
||||
}
|
||||
record->uuids = 1 << ffs(record->uuids - 1);
|
||||
record->uuids = pow2ceil(record->uuids);
|
||||
record->attribute_list =
|
||||
g_malloc0(record->attributes * sizeof(*record->attribute_list));
|
||||
record->uuid =
|
||||
|
@@ -364,6 +364,7 @@ static void console_class_init(ObjectClass *klass, void *data)
|
||||
ec->can_handle_event = can_handle_event;
|
||||
ec->read_event_data = read_event_data;
|
||||
ec->write_event_data = write_event_data;
|
||||
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
|
||||
}
|
||||
|
||||
static const TypeInfo sclp_console_info = {
|
||||
|
@@ -266,6 +266,7 @@ static void console_class_init(ObjectClass *klass, void *data)
|
||||
ec->can_handle_event = can_handle_event;
|
||||
ec->read_event_data = read_event_data;
|
||||
ec->write_event_data = write_event_data;
|
||||
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
|
||||
}
|
||||
|
||||
static const TypeInfo sclp_console_info = {
|
||||
|
@@ -814,12 +814,12 @@ static uint32_t find_free_port_id(VirtIOSerial *vser)
|
||||
|
||||
max_nr_ports = vser->serial.max_virtserial_ports;
|
||||
for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
|
||||
uint32_t map, bit;
|
||||
uint32_t map, zeroes;
|
||||
|
||||
map = vser->ports_map[i];
|
||||
bit = ffs(~map);
|
||||
if (bit) {
|
||||
return (bit - 1) + i * 32;
|
||||
zeroes = ctz32(~map);
|
||||
if (zeroes != 32) {
|
||||
return zeroes + i * 32;
|
||||
}
|
||||
}
|
||||
return VIRTIO_CONSOLE_BAD_ID;
|
||||
|
@@ -835,12 +835,12 @@ err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
ram_addr_t rom_add_blob(const char *name, const void *blob, size_t len,
|
||||
MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t len,
|
||||
size_t max_len, hwaddr addr, const char *fw_file_name,
|
||||
FWCfgReadCallback fw_callback, void *callback_opaque)
|
||||
{
|
||||
Rom *rom;
|
||||
ram_addr_t ret = RAM_ADDR_MAX;
|
||||
MemoryRegion *mr = NULL;
|
||||
|
||||
rom = g_malloc0(sizeof(*rom));
|
||||
rom->name = g_strdup(name);
|
||||
@@ -858,7 +858,7 @@ ram_addr_t rom_add_blob(const char *name, const void *blob, size_t len,
|
||||
|
||||
if (rom_file_has_mr) {
|
||||
data = rom_set_mr(rom, OBJECT(fw_cfg), devpath);
|
||||
ret = memory_region_get_ram_addr(rom->mr);
|
||||
mr = rom->mr;
|
||||
} else {
|
||||
data = rom->data;
|
||||
}
|
||||
@@ -867,7 +867,7 @@ ram_addr_t rom_add_blob(const char *name, const void *blob, size_t len,
|
||||
fw_callback, callback_opaque,
|
||||
data, rom->datasize);
|
||||
}
|
||||
return ret;
|
||||
return mr;
|
||||
}
|
||||
|
||||
/* This function is specific for elf program because we don't need to allocate
|
||||
|
@@ -21,7 +21,7 @@ common-obj-$(CONFIG_ZAURUS) += tc6393xb.o
|
||||
ifeq ($(CONFIG_MILKYMIST_TMU2),y)
|
||||
common-obj-y += milkymist-tmu2.o
|
||||
milkymist-tmu2.o-cflags := $(OPENGL_CFLAGS)
|
||||
libs_softmmu += $(OPENGL_LIBS)
|
||||
milkymist-tmu2.o-libs += $(OPENGL_LIBS)
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_OMAP) += omap_dss.o
|
||||
|
@@ -696,7 +696,7 @@ static inline void qxl_push_free_res(PCIQXLDevice *d, int flush)
|
||||
|
||||
/* called from spice server thread context only */
|
||||
static void interface_release_resource(QXLInstance *sin,
|
||||
struct QXLReleaseInfoExt ext)
|
||||
QXLReleaseInfoExt ext)
|
||||
{
|
||||
PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
|
||||
QXLReleaseRing *ring;
|
||||
|
@@ -171,7 +171,7 @@ static void tc6393xb_gpio_handler_update(TC6393xbState *s)
|
||||
level = s->gpio_level & s->gpio_dir;
|
||||
|
||||
for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) {
|
||||
bit = ffs(diff) - 1;
|
||||
bit = ctz32(diff);
|
||||
qemu_set_irq(s->handler[bit], (level >> bit) & 1);
|
||||
}
|
||||
|
||||
|
@@ -205,10 +205,22 @@ again:
|
||||
if (size == 0) {
|
||||
/* Transfer complete. */
|
||||
if (ch->lli) {
|
||||
ch->src = ldl_le_phys(&address_space_memory, ch->lli);
|
||||
ch->dest = ldl_le_phys(&address_space_memory, ch->lli + 4);
|
||||
ch->ctrl = ldl_le_phys(&address_space_memory, ch->lli + 12);
|
||||
ch->lli = ldl_le_phys(&address_space_memory, ch->lli + 8);
|
||||
ch->src = address_space_ldl_le(&address_space_memory,
|
||||
ch->lli,
|
||||
MEMTXATTRS_UNSPECIFIED,
|
||||
NULL);
|
||||
ch->dest = address_space_ldl_le(&address_space_memory,
|
||||
ch->lli + 4,
|
||||
MEMTXATTRS_UNSPECIFIED,
|
||||
NULL);
|
||||
ch->ctrl = address_space_ldl_le(&address_space_memory,
|
||||
ch->lli + 12,
|
||||
MEMTXATTRS_UNSPECIFIED,
|
||||
NULL);
|
||||
ch->lli = address_space_ldl_le(&address_space_memory,
|
||||
ch->lli + 8,
|
||||
MEMTXATTRS_UNSPECIFIED,
|
||||
NULL);
|
||||
} else {
|
||||
ch->conf &= ~PL080_CCONF_E;
|
||||
}
|
||||
|
@@ -263,7 +263,8 @@ static uint32_t iommu_page_get_flags(IOMMUState *s, hwaddr addr)
|
||||
iopte = s->regs[IOMMU_BASE] << 4;
|
||||
addr &= ~s->iostart;
|
||||
iopte += (addr >> (IOMMU_PAGE_SHIFT - 2)) & ~3;
|
||||
ret = ldl_be_phys(&address_space_memory, iopte);
|
||||
ret = address_space_ldl_be(&address_space_memory, iopte,
|
||||
MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
trace_sun4m_iommu_page_get_flags(pa, iopte, ret);
|
||||
return ret;
|
||||
}
|
||||
|
@@ -96,7 +96,7 @@ static int max7310_tx(I2CSlave *i2c, uint8_t data)
|
||||
case 0x01: /* Output port */
|
||||
for (diff = (data ^ s->level) & ~s->direction; diff;
|
||||
diff &= ~(1 << line)) {
|
||||
line = ffs(diff) - 1;
|
||||
line = ctz32(diff);
|
||||
if (s->handler[line])
|
||||
qemu_set_irq(s->handler[line], (data >> line) & 1);
|
||||
}
|
||||
|
@@ -125,8 +125,7 @@ static void omap_gpio_write(void *opaque, hwaddr addr,
|
||||
case 0x04: /* DATA_OUTPUT */
|
||||
diff = (s->outputs ^ value) & ~s->dir;
|
||||
s->outputs = value;
|
||||
while ((ln = ffs(diff))) {
|
||||
ln --;
|
||||
while ((ln = ctz32(diff)) != 32) {
|
||||
if (s->handler[ln])
|
||||
qemu_set_irq(s->handler[ln], (value >> ln) & 1);
|
||||
diff &= ~(1 << ln);
|
||||
@@ -138,8 +137,7 @@ static void omap_gpio_write(void *opaque, hwaddr addr,
|
||||
s->dir = value;
|
||||
|
||||
value = s->outputs & ~s->dir;
|
||||
while ((ln = ffs(diff))) {
|
||||
ln --;
|
||||
while ((ln = ctz32(diff)) != 32) {
|
||||
if (s->handler[ln])
|
||||
qemu_set_irq(s->handler[ln], (value >> ln) & 1);
|
||||
diff &= ~(1 << ln);
|
||||
@@ -253,8 +251,7 @@ static inline void omap2_gpio_module_out_update(struct omap2_gpio_s *s,
|
||||
|
||||
s->outputs ^= diff;
|
||||
diff &= ~s->dir;
|
||||
while ((ln = ffs(diff))) {
|
||||
ln --;
|
||||
while ((ln = ctz32(diff)) != 32) {
|
||||
qemu_set_irq(s->handler[ln], (s->outputs >> ln) & 1);
|
||||
diff &= ~(1 << ln);
|
||||
}
|
||||
@@ -442,8 +439,8 @@ static void omap2_gpio_module_write(void *opaque, hwaddr addr,
|
||||
s->dir = value;
|
||||
|
||||
value = s->outputs & ~s->dir;
|
||||
while ((ln = ffs(diff))) {
|
||||
diff &= ~(1 <<-- ln);
|
||||
while ((ln = ctz32(diff)) != 32) {
|
||||
diff &= ~(1 << ln);
|
||||
qemu_set_irq(s->handler[ln], (value >> ln) & 1);
|
||||
}
|
||||
|
||||
|
@@ -65,7 +65,7 @@ static inline void scoop_gpio_handler_update(ScoopInfo *s) {
|
||||
level = s->gpio_level & s->gpio_dir;
|
||||
|
||||
for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) {
|
||||
bit = ffs(diff) - 1;
|
||||
bit = ctz32(diff);
|
||||
qemu_set_irq(s->handler[bit], (level >> bit) & 1);
|
||||
}
|
||||
|
||||
|
@@ -171,9 +171,13 @@ static uint32_t omap_i2c_read(void *opaque, hwaddr addr)
|
||||
case 0x0c: /* I2C_IV */
|
||||
if (s->revision >= OMAP2_INTR_REV)
|
||||
break;
|
||||
ret = ffs(s->stat & s->mask);
|
||||
if (ret)
|
||||
s->stat ^= 1 << (ret - 1);
|
||||
ret = ctz32(s->stat & s->mask);
|
||||
if (ret != 32) {
|
||||
s->stat ^= 1 << ret;
|
||||
ret++;
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
omap_i2c_interrupts_update(s);
|
||||
return ret;
|
||||
|
||||
|
@@ -26,7 +26,6 @@
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/bitmap.h"
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/range.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "qom/cpu.h"
|
||||
@@ -58,7 +57,6 @@
|
||||
|
||||
#include "qapi/qmp/qint.h"
|
||||
#include "qom/qom-qobject.h"
|
||||
#include "exec/ram_addr.h"
|
||||
|
||||
/* These are used to size the ACPI tables for -M pc-i440fx-1.7 and
|
||||
* -M pc-i440fx-2.0. Even if the actual amount of AML generated grows
|
||||
@@ -1323,13 +1321,13 @@ static inline void acpi_build_tables_cleanup(AcpiBuildTables *tables, bool mfre)
|
||||
typedef
|
||||
struct AcpiBuildState {
|
||||
/* Copy of table in RAM (for patching). */
|
||||
ram_addr_t table_ram;
|
||||
MemoryRegion *table_mr;
|
||||
/* Is table patched? */
|
||||
uint8_t patched;
|
||||
PcGuestInfo *guest_info;
|
||||
void *rsdp;
|
||||
ram_addr_t rsdp_ram;
|
||||
ram_addr_t linker_ram;
|
||||
MemoryRegion *rsdp_mr;
|
||||
MemoryRegion *linker_mr;
|
||||
} AcpiBuildState;
|
||||
|
||||
static bool acpi_get_mcfg(AcpiMcfgInfo *mcfg)
|
||||
@@ -1513,15 +1511,15 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables)
|
||||
g_array_free(table_offsets, true);
|
||||
}
|
||||
|
||||
static void acpi_ram_update(ram_addr_t ram, GArray *data)
|
||||
static void acpi_ram_update(MemoryRegion *mr, GArray *data)
|
||||
{
|
||||
uint32_t size = acpi_data_len(data);
|
||||
|
||||
/* Make sure RAM size is correct - in case it got changed e.g. by migration */
|
||||
qemu_ram_resize(ram, size, &error_abort);
|
||||
memory_region_ram_resize(mr, size, &error_abort);
|
||||
|
||||
memcpy(qemu_get_ram_ptr(ram), data->data, size);
|
||||
cpu_physical_memory_set_dirty_range_nocode(ram, size);
|
||||
memcpy(memory_region_get_ram_ptr(mr), data->data, size);
|
||||
memory_region_set_dirty(mr, 0, size);
|
||||
}
|
||||
|
||||
static void acpi_build_update(void *build_opaque, uint32_t offset)
|
||||
@@ -1539,15 +1537,15 @@ static void acpi_build_update(void *build_opaque, uint32_t offset)
|
||||
|
||||
acpi_build(build_state->guest_info, &tables);
|
||||
|
||||
acpi_ram_update(build_state->table_ram, tables.table_data);
|
||||
acpi_ram_update(build_state->table_mr, tables.table_data);
|
||||
|
||||
if (build_state->rsdp) {
|
||||
memcpy(build_state->rsdp, tables.rsdp->data, acpi_data_len(tables.rsdp));
|
||||
} else {
|
||||
acpi_ram_update(build_state->rsdp_ram, tables.rsdp);
|
||||
acpi_ram_update(build_state->rsdp_mr, tables.rsdp);
|
||||
}
|
||||
|
||||
acpi_ram_update(build_state->linker_ram, tables.linker);
|
||||
acpi_ram_update(build_state->linker_mr, tables.linker);
|
||||
acpi_build_tables_cleanup(&tables, true);
|
||||
}
|
||||
|
||||
@@ -1557,8 +1555,9 @@ static void acpi_build_reset(void *build_opaque)
|
||||
build_state->patched = 0;
|
||||
}
|
||||
|
||||
static ram_addr_t acpi_add_rom_blob(AcpiBuildState *build_state, GArray *blob,
|
||||
const char *name, uint64_t max_size)
|
||||
static MemoryRegion *acpi_add_rom_blob(AcpiBuildState *build_state,
|
||||
GArray *blob, const char *name,
|
||||
uint64_t max_size)
|
||||
{
|
||||
return rom_add_blob(name, blob->data, acpi_data_len(blob), max_size, -1,
|
||||
name, acpi_build_update, build_state);
|
||||
@@ -1604,12 +1603,12 @@ void acpi_setup(PcGuestInfo *guest_info)
|
||||
acpi_build(build_state->guest_info, &tables);
|
||||
|
||||
/* Now expose it all to Guest */
|
||||
build_state->table_ram = acpi_add_rom_blob(build_state, tables.table_data,
|
||||
build_state->table_mr = acpi_add_rom_blob(build_state, tables.table_data,
|
||||
ACPI_BUILD_TABLE_FILE,
|
||||
ACPI_BUILD_TABLE_MAX_SIZE);
|
||||
assert(build_state->table_ram != RAM_ADDR_MAX);
|
||||
assert(build_state->table_mr != NULL);
|
||||
|
||||
build_state->linker_ram =
|
||||
build_state->linker_mr =
|
||||
acpi_add_rom_blob(build_state, tables.linker, "etc/table-loader", 0);
|
||||
|
||||
fw_cfg_add_file(guest_info->fw_cfg, ACPI_BUILD_TPMLOG_FILE,
|
||||
@@ -1627,10 +1626,10 @@ void acpi_setup(PcGuestInfo *guest_info)
|
||||
fw_cfg_add_file_callback(guest_info->fw_cfg, ACPI_BUILD_RSDP_FILE,
|
||||
acpi_build_update, build_state,
|
||||
build_state->rsdp, rsdp_size);
|
||||
build_state->rsdp_ram = (ram_addr_t)-1;
|
||||
build_state->rsdp_mr = NULL;
|
||||
} else {
|
||||
build_state->rsdp = NULL;
|
||||
build_state->rsdp_ram = acpi_add_rom_blob(build_state, tables.rsdp,
|
||||
build_state->rsdp_mr = acpi_add_rom_blob(build_state, tables.rsdp,
|
||||
ACPI_BUILD_RSDP_FILE, 0);
|
||||
}
|
||||
|
||||
|
@@ -246,7 +246,8 @@ static void vtd_generate_interrupt(IntelIOMMUState *s, hwaddr mesg_addr_reg,
|
||||
data = vtd_get_long_raw(s, mesg_data_reg);
|
||||
|
||||
VTD_DPRINTF(FLOG, "msi: addr 0x%"PRIx64 " data 0x%"PRIx32, addr, data);
|
||||
stl_le_phys(&address_space_memory, addr, data);
|
||||
address_space_stl_le(&address_space_memory, addr, data,
|
||||
MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
/* Generate a fault event to software via MSI if conditions are met.
|
||||
|
@@ -2436,8 +2436,8 @@ void ide_init2(IDEBus *bus, qemu_irq irq)
|
||||
|
||||
static const MemoryRegionPortio ide_portio_list[] = {
|
||||
{ 0, 8, 1, .read = ide_ioport_read, .write = ide_ioport_write },
|
||||
{ 0, 2, 2, .read = ide_data_readw, .write = ide_data_writew },
|
||||
{ 0, 4, 4, .read = ide_data_readl, .write = ide_data_writel },
|
||||
{ 0, 1, 2, .read = ide_data_readw, .write = ide_data_writew },
|
||||
{ 0, 1, 4, .read = ide_data_readl, .write = ide_data_writel },
|
||||
PORTIO_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
@@ -23,7 +23,7 @@
|
||||
static void aw_a10_pic_update(AwA10PICState *s)
|
||||
{
|
||||
uint8_t i;
|
||||
int irq = 0, fiq = 0, pending;
|
||||
int irq = 0, fiq = 0, zeroes;
|
||||
|
||||
s->vector = 0;
|
||||
|
||||
@@ -32,9 +32,9 @@ static void aw_a10_pic_update(AwA10PICState *s)
|
||||
fiq |= s->select[i] & s->irq_pending[i] & ~s->mask[i];
|
||||
|
||||
if (!s->vector) {
|
||||
pending = ffs(s->irq_pending[i] & ~s->mask[i]);
|
||||
if (pending) {
|
||||
s->vector = (i * 32 + pending - 1) * 4;
|
||||
zeroes = ctz32(s->irq_pending[i] & ~s->mask[i]);
|
||||
if (zeroes != 32) {
|
||||
s->vector = (i * 32 + zeroes) * 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -243,15 +243,6 @@ static void apic_reset_common(DeviceState *dev)
|
||||
info->vapic_base_update(s);
|
||||
|
||||
apic_init_reset(dev);
|
||||
|
||||
if (bsp) {
|
||||
/*
|
||||
* LINT0 delivery mode on CPU #0 is set to ExtInt at initialization
|
||||
* time typically by BIOS, so PIC interrupt can be delivered to the
|
||||
* processor when local APIC is enabled.
|
||||
*/
|
||||
s->lvt[APIC_LVT_LINT0] = 0x700;
|
||||
}
|
||||
}
|
||||
|
||||
/* This function is only used for old state version 1 and 2 */
|
||||
|
@@ -60,7 +60,7 @@ struct omap_intr_handler_s {
|
||||
|
||||
static void omap_inth_sir_update(struct omap_intr_handler_s *s, int is_fiq)
|
||||
{
|
||||
int i, j, sir_intr, p_intr, p, f;
|
||||
int i, j, sir_intr, p_intr, p;
|
||||
uint32_t level;
|
||||
sir_intr = 0;
|
||||
p_intr = 255;
|
||||
@@ -72,14 +72,15 @@ static void omap_inth_sir_update(struct omap_intr_handler_s *s, int is_fiq)
|
||||
for (j = 0; j < s->nbanks; ++j) {
|
||||
level = s->bank[j].irqs & ~s->bank[j].mask &
|
||||
(is_fiq ? s->bank[j].fiq : ~s->bank[j].fiq);
|
||||
for (f = ffs(level), i = f - 1, level >>= f - 1; f; i += f,
|
||||
level >>= f) {
|
||||
|
||||
while (level != 0) {
|
||||
i = ctz32(level);
|
||||
p = s->bank[j].priority[i];
|
||||
if (p <= p_intr) {
|
||||
p_intr = p;
|
||||
sir_intr = 32 * j + i;
|
||||
}
|
||||
f = ffs(level >> 1);
|
||||
level &= level - 1;
|
||||
}
|
||||
}
|
||||
s->sir_intr[is_fiq] = sir_intr;
|
||||
|
@@ -113,15 +113,15 @@ void microblaze_load_kernel(MicroBlazeCPU *cpu, hwaddr ddr_base,
|
||||
const char *kernel_filename;
|
||||
const char *kernel_cmdline;
|
||||
const char *dtb_arg;
|
||||
char *filename = NULL;
|
||||
|
||||
machine_opts = qemu_get_machine_opts();
|
||||
kernel_filename = qemu_opt_get(machine_opts, "kernel");
|
||||
kernel_cmdline = qemu_opt_get(machine_opts, "append");
|
||||
dtb_arg = qemu_opt_get(machine_opts, "dtb");
|
||||
if (dtb_arg) { /* Preference a -dtb argument */
|
||||
dtb_filename = dtb_arg;
|
||||
} else { /* default to pcbios dtb as passed by machine_init */
|
||||
dtb_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_filename);
|
||||
/* default to pcbios dtb as passed by machine_init */
|
||||
if (!dtb_arg) {
|
||||
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_filename);
|
||||
}
|
||||
|
||||
boot_info.machine_cpu_reset = machine_cpu_reset;
|
||||
@@ -203,7 +203,8 @@ void microblaze_load_kernel(MicroBlazeCPU *cpu, hwaddr ddr_base,
|
||||
boot_info.initrd_start,
|
||||
boot_info.initrd_end,
|
||||
kernel_cmdline,
|
||||
dtb_filename);
|
||||
/* Preference a -dtb argument */
|
||||
dtb_arg ? dtb_arg : filename);
|
||||
}
|
||||
|
||||
g_free(filename);
|
||||
}
|
||||
|
@@ -168,6 +168,7 @@ static int64_t load_kernel (CPUMIPSState *env)
|
||||
rom_add_blob_fixed("prom", prom_buf, prom_size,
|
||||
cpu_mips_kseg0_to_phys(NULL, ENVP_ADDR));
|
||||
|
||||
g_free(prom_buf);
|
||||
return kernel_entry;
|
||||
}
|
||||
|
||||
|
@@ -61,7 +61,8 @@ static void main_cpu_reset(void *opaque)
|
||||
static uint64_t rtc_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
uint8_t val;
|
||||
address_space_read(&address_space_memory, 0x90000071, &val, 1);
|
||||
address_space_read(&address_space_memory, 0x90000071,
|
||||
MEMTXATTRS_UNSPECIFIED, &val, 1);
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -69,7 +70,8 @@ static void rtc_write(void *opaque, hwaddr addr,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
uint8_t buf = val & 0xff;
|
||||
address_space_write(&address_space_memory, 0x90000071, &buf, 1);
|
||||
address_space_write(&address_space_memory, 0x90000071,
|
||||
MEMTXATTRS_UNSPECIFIED, &buf, 1);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps rtc_ops = {
|
||||
|
@@ -861,6 +861,7 @@ static int64_t load_kernel (void)
|
||||
rom_add_blob_fixed("prom", prom_buf, prom_size,
|
||||
cpu_mips_kseg0_to_phys(NULL, ENVP_ADDR));
|
||||
|
||||
g_free(prom_buf);
|
||||
return kernel_entry;
|
||||
}
|
||||
|
||||
|
@@ -139,6 +139,7 @@ static int64_t load_kernel(void)
|
||||
rom_add_blob_fixed("params", params_buf, params_size,
|
||||
(16 << 20) - 264);
|
||||
|
||||
g_free(params_buf);
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
@@ -279,7 +279,7 @@ static const MemoryRegionOps edu_mmio_ops = {
|
||||
};
|
||||
|
||||
/*
|
||||
* We purposedly use a thread, so that users are forced to wait for the status
|
||||
* We purposely use a thread, so that users are forced to wait for the status
|
||||
* register.
|
||||
*/
|
||||
static void *edu_fact_thread(void *opaque)
|
||||
|
@@ -68,6 +68,7 @@ typedef struct APCState {
|
||||
} APCState;
|
||||
|
||||
#define MISC_SIZE 1
|
||||
#define LED_SIZE 2
|
||||
#define SYSCTRL_SIZE 4
|
||||
|
||||
#define AUX1_TC 0x02
|
||||
@@ -452,13 +453,13 @@ static int slavio_misc_init1(SysBusDevice *sbd)
|
||||
/* 16 bit registers */
|
||||
/* ss600mp diag LEDs */
|
||||
memory_region_init_io(&s->led_iomem, OBJECT(s), &slavio_led_mem_ops, s,
|
||||
"leds", MISC_SIZE);
|
||||
"leds", LED_SIZE);
|
||||
sysbus_init_mmio(sbd, &s->led_iomem);
|
||||
|
||||
/* 32 bit registers */
|
||||
/* System control */
|
||||
memory_region_init_io(&s->sysctrl_iomem, OBJECT(s), &slavio_sysctrl_mem_ops, s,
|
||||
"system-control", MISC_SIZE);
|
||||
"system-control", SYSCTRL_SIZE);
|
||||
sysbus_init_mmio(sbd, &s->sysctrl_iomem);
|
||||
|
||||
/* AUX 1 (Misc System Functions) */
|
||||
|
@@ -1590,7 +1590,7 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp)
|
||||
n->max_queues = MAX(n->nic_conf.peers.queues, 1);
|
||||
if (n->max_queues * 2 + 1 > VIRTIO_PCI_QUEUE_MAX) {
|
||||
error_setg(errp, "Invalid number of queues (= %" PRIu32 "), "
|
||||
"must be a postive integer less than %d.",
|
||||
"must be a positive integer less than %d.",
|
||||
n->max_queues, (VIRTIO_PCI_QUEUE_MAX - 1) / 2);
|
||||
virtio_cleanup(vdev);
|
||||
return;
|
||||
|
@@ -172,13 +172,6 @@ bool vmxnet_rx_pkt_has_virt_hdr(struct VmxnetRxPkt *pkt)
|
||||
return pkt->has_virt_hdr;
|
||||
}
|
||||
|
||||
uint16_t vmxnet_rx_pkt_get_num_frags(struct VmxnetRxPkt *pkt)
|
||||
{
|
||||
assert(pkt);
|
||||
|
||||
return pkt->vec_len;
|
||||
}
|
||||
|
||||
uint16_t vmxnet_rx_pkt_get_vlan_tag(struct VmxnetRxPkt *pkt)
|
||||
{
|
||||
assert(pkt);
|
||||
|
@@ -113,15 +113,6 @@ bool vmxnet_rx_pkt_is_vlan_stripped(struct VmxnetRxPkt *pkt);
|
||||
*/
|
||||
bool vmxnet_rx_pkt_has_virt_hdr(struct VmxnetRxPkt *pkt);
|
||||
|
||||
/**
|
||||
* returns number of frags attached to the packet
|
||||
*
|
||||
* @pkt: packet
|
||||
* @ret: number of frags
|
||||
*
|
||||
*/
|
||||
uint16_t vmxnet_rx_pkt_get_num_frags(struct VmxnetRxPkt *pkt);
|
||||
|
||||
/**
|
||||
* attach data to rx packet
|
||||
*
|
||||
|
@@ -101,27 +101,6 @@ static const TypeInfo i82801b11_bridge_info = {
|
||||
.class_init = i82801b11_bridge_class_init,
|
||||
};
|
||||
|
||||
PCIBus *ich9_d2pbr_init(PCIBus *bus, int devfn, int sec_bus)
|
||||
{
|
||||
PCIDevice *d;
|
||||
PCIBridge *br;
|
||||
char buf[16];
|
||||
DeviceState *qdev;
|
||||
|
||||
d = pci_create_multifunction(bus, devfn, true, "i82801b11-bridge");
|
||||
if (!d) {
|
||||
return NULL;
|
||||
}
|
||||
br = PCI_BRIDGE(d);
|
||||
qdev = DEVICE(d);
|
||||
|
||||
snprintf(buf, sizeof(buf), "pci.%d", sec_bus);
|
||||
pci_bridge_map_irq(br, buf, pci_swizzle_map_irq_fn);
|
||||
qdev_init_nofail(qdev);
|
||||
|
||||
return pci_bridge_get_sec_bus(br);
|
||||
}
|
||||
|
||||
static void d2pbr_register(void)
|
||||
{
|
||||
type_register_static(&i82801b11_bridge_info);
|
||||
|
@@ -289,7 +289,8 @@ static IOMMUTLBEntry pbm_translate_iommu(MemoryRegion *iommu, hwaddr addr,
|
||||
}
|
||||
}
|
||||
|
||||
tte = ldq_be_phys(&address_space_memory, baseaddr + offset);
|
||||
tte = address_space_ldq_be(&address_space_memory, baseaddr + offset,
|
||||
MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
|
||||
if (!(tte & IOMMU_TTE_DATA_V)) {
|
||||
/* Invalid mapping */
|
||||
|
@@ -427,7 +427,7 @@ static uint32_t bonito_sbridge_pciaddr(void *opaque, hwaddr addr)
|
||||
cfgaddr |= (s->regs[BONITO_PCIMAP_CFG] & 0xffff) << 16;
|
||||
|
||||
idsel = (cfgaddr & BONITO_PCICONF_IDSEL_MASK) >> BONITO_PCICONF_IDSEL_OFFSET;
|
||||
devno = ffs(idsel) - 1;
|
||||
devno = ctz32(idsel);
|
||||
funno = (cfgaddr & BONITO_PCICONF_FUN_MASK) >> BONITO_PCICONF_FUN_OFFSET;
|
||||
regno = (cfgaddr & BONITO_PCICONF_REG_MASK) >> BONITO_PCICONF_REG_OFFSET;
|
||||
|
||||
|
@@ -140,7 +140,8 @@ static uint64_t raven_io_read(void *opaque, hwaddr addr,
|
||||
uint8_t buf[4];
|
||||
|
||||
addr = raven_io_address(s, addr);
|
||||
address_space_read(&s->pci_io_as, addr + 0x80000000, buf, size);
|
||||
address_space_read(&s->pci_io_as, addr + 0x80000000,
|
||||
MEMTXATTRS_UNSPECIFIED, buf, size);
|
||||
|
||||
if (size == 1) {
|
||||
return buf[0];
|
||||
@@ -171,7 +172,8 @@ static void raven_io_write(void *opaque, hwaddr addr,
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
address_space_write(&s->pci_io_as, addr + 0x80000000, buf, size);
|
||||
address_space_write(&s->pci_io_as, addr + 0x80000000,
|
||||
MEMTXATTRS_UNSPECIFIED, buf, size);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps raven_io_ops = {
|
||||
|
@@ -92,7 +92,10 @@ static uint32_t unin_get_config_reg(uint32_t reg, uint32_t addr)
|
||||
uint32_t slot, func;
|
||||
|
||||
/* Grab CFA0 style values */
|
||||
slot = ffs(reg & 0xfffff800) - 1;
|
||||
slot = ctz32(reg & 0xfffff800);
|
||||
if (slot == 32) {
|
||||
slot = -1; /* XXX: should this be 0? */
|
||||
}
|
||||
func = (reg >> 8) & 7;
|
||||
|
||||
/* ... and then convert them to x86 format */
|
||||
|
15
hw/pci/msi.c
15
hw/pci/msi.c
@@ -72,7 +72,7 @@ static inline uint8_t msi_cap_sizeof(uint16_t flags)
|
||||
static inline unsigned int msi_nr_vectors(uint16_t flags)
|
||||
{
|
||||
return 1U <<
|
||||
((flags & PCI_MSI_FLAGS_QSIZE) >> (ffs(PCI_MSI_FLAGS_QSIZE) - 1));
|
||||
((flags & PCI_MSI_FLAGS_QSIZE) >> ctz32(PCI_MSI_FLAGS_QSIZE));
|
||||
}
|
||||
|
||||
static inline uint8_t msi_flags_off(const PCIDevice* dev)
|
||||
@@ -175,9 +175,9 @@ int msi_init(struct PCIDevice *dev, uint8_t offset,
|
||||
assert(nr_vectors > 0);
|
||||
assert(nr_vectors <= PCI_MSI_VECTORS_MAX);
|
||||
/* the nr of MSI vectors is up to 32 */
|
||||
vectors_order = ffs(nr_vectors) - 1;
|
||||
vectors_order = ctz32(nr_vectors);
|
||||
|
||||
flags = vectors_order << (ffs(PCI_MSI_FLAGS_QMASK) - 1);
|
||||
flags = vectors_order << ctz32(PCI_MSI_FLAGS_QMASK);
|
||||
if (msi64bit) {
|
||||
flags |= PCI_MSI_FLAGS_64BIT;
|
||||
}
|
||||
@@ -291,7 +291,8 @@ void msi_notify(PCIDevice *dev, unsigned int vector)
|
||||
"notify vector 0x%x"
|
||||
" address: 0x%"PRIx64" data: 0x%"PRIx32"\n",
|
||||
vector, msg.address, msg.data);
|
||||
stl_le_phys(&dev->bus_master_as, msg.address, msg.data);
|
||||
address_space_stl_le(&dev->bus_master_as, msg.address, msg.data,
|
||||
MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
/* Normally called by pci_default_write_config(). */
|
||||
@@ -354,12 +355,12 @@ void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len)
|
||||
* just don't crash the host
|
||||
*/
|
||||
log_num_vecs =
|
||||
(flags & PCI_MSI_FLAGS_QSIZE) >> (ffs(PCI_MSI_FLAGS_QSIZE) - 1);
|
||||
(flags & PCI_MSI_FLAGS_QSIZE) >> ctz32(PCI_MSI_FLAGS_QSIZE);
|
||||
log_max_vecs =
|
||||
(flags & PCI_MSI_FLAGS_QMASK) >> (ffs(PCI_MSI_FLAGS_QMASK) - 1);
|
||||
(flags & PCI_MSI_FLAGS_QMASK) >> ctz32(PCI_MSI_FLAGS_QMASK);
|
||||
if (log_num_vecs > log_max_vecs) {
|
||||
flags &= ~PCI_MSI_FLAGS_QSIZE;
|
||||
flags |= log_max_vecs << (ffs(PCI_MSI_FLAGS_QSIZE) - 1);
|
||||
flags |= log_max_vecs << ctz32(PCI_MSI_FLAGS_QSIZE);
|
||||
pci_set_word(dev->config + msi_flags_off(dev), flags);
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user