Compare commits
26
Commits
v1.4.1
...
stable-1.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
89400a80f5 | ||
|
|
e85b521519 | ||
|
|
f890185392 | ||
|
|
745f6c0ef7 | ||
|
|
0182df5ae5 | ||
|
|
7f28f0f1f6 | ||
|
|
45bbe1fa89 | ||
|
|
06efdc4f4d | ||
|
|
0c70b5ad59 | ||
|
|
b90fd157f7 | ||
|
|
7322cb17fa | ||
|
|
1d7723ffc7 | ||
|
|
67b460a404 | ||
|
|
84247bbe28 | ||
|
|
2ebcc590c9 | ||
|
|
69001b3145 | ||
|
|
3accab7365 | ||
|
|
60259539ee | ||
|
|
93399d0827 | ||
|
|
074dd56a01 | ||
|
|
d10d2510b9 | ||
|
|
5613bda4ac | ||
|
|
c5675a98bb | ||
|
|
e355efd962 | ||
|
|
4d7f4556fc | ||
|
|
0486c27a36 |
No files matched your search
+1
-10
@@ -16,16 +16,7 @@ block-obj-y += qapi-types.o qapi-visit.o
|
||||
|
||||
block-obj-y += qemu-coroutine.o qemu-coroutine-lock.o qemu-coroutine-io.o
|
||||
block-obj-y += qemu-coroutine-sleep.o
|
||||
ifeq ($(CONFIG_UCONTEXT_COROUTINE),y)
|
||||
block-obj-$(CONFIG_POSIX) += coroutine-ucontext.o
|
||||
else
|
||||
ifeq ($(CONFIG_SIGALTSTACK_COROUTINE),y)
|
||||
block-obj-$(CONFIG_POSIX) += coroutine-sigaltstack.o
|
||||
else
|
||||
block-obj-$(CONFIG_POSIX) += coroutine-gthread.o
|
||||
endif
|
||||
endif
|
||||
block-obj-$(CONFIG_WIN32) += coroutine-win32.o
|
||||
block-obj-y += coroutine-$(CONFIG_COROUTINE_BACKEND).o
|
||||
|
||||
ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy)
|
||||
# Lots of the fsdev/9pcode is pulled in by vl.c via qemu_fsdev_add.
|
||||
|
||||
@@ -41,6 +41,9 @@ static void entropy_available(void *opaque)
|
||||
ssize_t len;
|
||||
|
||||
len = read(s->fd, buffer, s->size);
|
||||
if (len < 0 && errno == EAGAIN) {
|
||||
return;
|
||||
}
|
||||
g_assert(len != -1);
|
||||
|
||||
s->receive_func(s->opaque, buffer, len);
|
||||
|
||||
+1
-1
@@ -274,7 +274,7 @@ static int nbd_co_send_request(BDRVNBDState *s, struct nbd_request *request,
|
||||
ret = qemu_co_sendv(s->sock, qiov->iov, qiov->niov,
|
||||
offset, request->len);
|
||||
if (ret != request->len) {
|
||||
return -EIO;
|
||||
rc = -EIO;
|
||||
}
|
||||
}
|
||||
qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, NULL,
|
||||
|
||||
+33
-4
@@ -63,7 +63,8 @@
|
||||
typedef enum {
|
||||
RBD_AIO_READ,
|
||||
RBD_AIO_WRITE,
|
||||
RBD_AIO_DISCARD
|
||||
RBD_AIO_DISCARD,
|
||||
RBD_AIO_FLUSH
|
||||
} RBDAIOCmd;
|
||||
|
||||
typedef struct RBDAIOCB {
|
||||
@@ -379,8 +380,7 @@ static void qemu_rbd_complete_aio(RADOSCB *rcb)
|
||||
|
||||
r = rcb->ret;
|
||||
|
||||
if (acb->cmd == RBD_AIO_WRITE ||
|
||||
acb->cmd == RBD_AIO_DISCARD) {
|
||||
if (acb->cmd != RBD_AIO_READ) {
|
||||
if (r < 0) {
|
||||
acb->ret = r;
|
||||
acb->error = 1;
|
||||
@@ -658,6 +658,16 @@ static int rbd_aio_discard_wrapper(rbd_image_t image,
|
||||
#endif
|
||||
}
|
||||
|
||||
static int rbd_aio_flush_wrapper(rbd_image_t image,
|
||||
rbd_completion_t comp)
|
||||
{
|
||||
#ifdef LIBRBD_SUPPORTS_AIO_FLUSH
|
||||
return rbd_aio_flush(image, comp);
|
||||
#else
|
||||
return -ENOTSUP;
|
||||
#endif
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *rbd_start_aio(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
QEMUIOVector *qiov,
|
||||
@@ -678,7 +688,7 @@ static BlockDriverAIOCB *rbd_start_aio(BlockDriverState *bs,
|
||||
acb = qemu_aio_get(&rbd_aiocb_info, bs, cb, opaque);
|
||||
acb->cmd = cmd;
|
||||
acb->qiov = qiov;
|
||||
if (cmd == RBD_AIO_DISCARD) {
|
||||
if (cmd == RBD_AIO_DISCARD || cmd == RBD_AIO_FLUSH) {
|
||||
acb->bounce = NULL;
|
||||
} else {
|
||||
acb->bounce = qemu_blockalign(bs, qiov->size);
|
||||
@@ -722,6 +732,9 @@ static BlockDriverAIOCB *rbd_start_aio(BlockDriverState *bs,
|
||||
case RBD_AIO_DISCARD:
|
||||
r = rbd_aio_discard_wrapper(s->image, off, size, c);
|
||||
break;
|
||||
case RBD_AIO_FLUSH:
|
||||
r = rbd_aio_flush_wrapper(s->image, c);
|
||||
break;
|
||||
default:
|
||||
r = -EINVAL;
|
||||
}
|
||||
@@ -761,6 +774,16 @@ static BlockDriverAIOCB *qemu_rbd_aio_writev(BlockDriverState *bs,
|
||||
RBD_AIO_WRITE);
|
||||
}
|
||||
|
||||
#ifdef LIBRBD_SUPPORTS_AIO_FLUSH
|
||||
static BlockDriverAIOCB *qemu_rbd_aio_flush(BlockDriverState *bs,
|
||||
BlockDriverCompletionFunc *cb,
|
||||
void *opaque)
|
||||
{
|
||||
return rbd_start_aio(bs, 0, NULL, 0, cb, opaque, RBD_AIO_FLUSH);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int qemu_rbd_co_flush(BlockDriverState *bs)
|
||||
{
|
||||
#if LIBRBD_VERSION_CODE >= LIBRBD_VERSION(0, 1, 1)
|
||||
@@ -771,6 +794,7 @@ static int qemu_rbd_co_flush(BlockDriverState *bs)
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
static int qemu_rbd_getinfo(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||
{
|
||||
@@ -948,7 +972,12 @@ static BlockDriver bdrv_rbd = {
|
||||
|
||||
.bdrv_aio_readv = qemu_rbd_aio_readv,
|
||||
.bdrv_aio_writev = qemu_rbd_aio_writev,
|
||||
|
||||
#ifdef LIBRBD_SUPPORTS_AIO_FLUSH
|
||||
.bdrv_aio_flush = qemu_rbd_aio_flush,
|
||||
#else
|
||||
.bdrv_co_flush_to_disk = qemu_rbd_co_flush,
|
||||
#endif
|
||||
|
||||
#ifdef LIBRBD_SUPPORTS_DISCARD
|
||||
.bdrv_aio_discard = qemu_rbd_aio_discard,
|
||||
|
||||
@@ -1435,6 +1435,7 @@ fi
|
||||
if test "$seccomp" != "no" ; then
|
||||
if $pkg_config --atleast-version=1.0.0 libseccomp --modversion >/dev/null 2>&1; then
|
||||
libs_softmmu="$libs_softmmu `$pkg_config --libs libseccomp`"
|
||||
QEMU_CFLAGS="$QEMU_CFLAGS `$pkg_config --cflags libseccomp`"
|
||||
seccomp="yes"
|
||||
else
|
||||
if test "$seccomp" = "yes"; then
|
||||
@@ -3035,34 +3036,67 @@ fi
|
||||
##########################################
|
||||
# check and set a backend for coroutine
|
||||
|
||||
# default is ucontext, but always fallback to gthread
|
||||
# windows autodetected by make
|
||||
if test "$coroutine" = "" -o "$coroutine" = "ucontext"; then
|
||||
if test "$darwin" != "yes"; then
|
||||
cat > $TMPC << EOF
|
||||
# We prefer ucontext, but it's not always possible. The fallback
|
||||
# is sigcontext. gthread is not selectable except explicitly, because
|
||||
# it is not functional enough to run QEMU proper. (It is occasionally
|
||||
# useful for debugging purposes.) On Windows the only valid backend
|
||||
# is the Windows-specific one.
|
||||
|
||||
ucontext_works=no
|
||||
if test "$darwin" != "yes"; then
|
||||
cat > $TMPC << EOF
|
||||
#include <ucontext.h>
|
||||
#ifdef __stub_makecontext
|
||||
#error Ignoring glibc stub makecontext which will always fail
|
||||
#endif
|
||||
int main(void) { makecontext(0, 0, 0); return 0; }
|
||||
EOF
|
||||
if compile_prog "" "" ; then
|
||||
coroutine_backend=ucontext
|
||||
else
|
||||
coroutine_backend=gthread
|
||||
fi
|
||||
if compile_prog "" "" ; then
|
||||
ucontext_works=yes
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "$coroutine" = ""; then
|
||||
if test "$mingw32" = "yes"; then
|
||||
coroutine=win32
|
||||
elif test "$ucontext_works" = "yes"; then
|
||||
coroutine=ucontext
|
||||
else
|
||||
coroutine=sigaltstack
|
||||
fi
|
||||
elif test "$coroutine" = "gthread" ; then
|
||||
coroutine_backend=gthread
|
||||
elif test "$coroutine" = "windows" ; then
|
||||
coroutine_backend=windows
|
||||
elif test "$coroutine" = "sigaltstack" ; then
|
||||
coroutine_backend=sigaltstack
|
||||
else
|
||||
echo
|
||||
echo "Error: unknown coroutine backend $coroutine"
|
||||
echo
|
||||
exit 1
|
||||
case $coroutine in
|
||||
windows)
|
||||
if test "$mingw32" != "yes"; then
|
||||
echo
|
||||
echo "Error: 'windows' coroutine backend only valid for Windows"
|
||||
echo
|
||||
exit 1
|
||||
fi
|
||||
# Unfortunately the user visible backend name doesn't match the
|
||||
# coroutine-*.c filename for this case, so we have to adjust it here.
|
||||
coroutine=win32
|
||||
;;
|
||||
ucontext)
|
||||
if test "$ucontext_works" != "yes"; then
|
||||
feature_not_found "ucontext"
|
||||
fi
|
||||
;;
|
||||
gthread|sigaltstack)
|
||||
if test "$mingw32" = "yes"; then
|
||||
echo
|
||||
echo "Error: only the 'windows' coroutine backend is valid for Windows"
|
||||
echo
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo
|
||||
echo "Error: unknown coroutine backend $coroutine"
|
||||
echo
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
##########################################
|
||||
@@ -3345,7 +3379,7 @@ echo "OpenGL support $opengl"
|
||||
echo "libiscsi support $libiscsi"
|
||||
echo "build guest agent $guest_agent"
|
||||
echo "seccomp support $seccomp"
|
||||
echo "coroutine backend $coroutine_backend"
|
||||
echo "coroutine backend $coroutine"
|
||||
echo "GlusterFS support $glusterfs"
|
||||
echo "virtio-blk-data-plane $virtio_blk_data_plane"
|
||||
echo "gcov $gcov_tool"
|
||||
@@ -3668,11 +3702,7 @@ if test "$rbd" = "yes" ; then
|
||||
echo "CONFIG_RBD=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$coroutine_backend" = "ucontext" ; then
|
||||
echo "CONFIG_UCONTEXT_COROUTINE=y" >> $config_host_mak
|
||||
elif test "$coroutine_backend" = "sigaltstack" ; then
|
||||
echo "CONFIG_SIGALTSTACK_COROUTINE=y" >> $config_host_mak
|
||||
fi
|
||||
echo "CONFIG_COROUTINE_BACKEND=$coroutine" >> $config_host_mak
|
||||
|
||||
if test "$open_by_handle_at" = "yes" ; then
|
||||
echo "CONFIG_OPEN_BY_HANDLE=y" >> $config_host_mak
|
||||
|
||||
+44
-14
@@ -51,12 +51,32 @@ void cpu_resume_from_signal(CPUArchState *env, void *puc)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Execute a TB, and fix up the CPU state afterwards if necessary */
|
||||
static inline tcg_target_ulong cpu_tb_exec(CPUArchState *env, uint8_t *tb_ptr)
|
||||
{
|
||||
tcg_target_ulong next_tb = tcg_qemu_tb_exec(env, tb_ptr);
|
||||
if ((next_tb & TB_EXIT_MASK) > TB_EXIT_IDX1) {
|
||||
/* We didn't start executing this TB (eg because the instruction
|
||||
* counter hit zero); we must restore the guest PC to the address
|
||||
* of the start of the TB.
|
||||
*/
|
||||
TranslationBlock *tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK);
|
||||
cpu_pc_from_tb(env, tb);
|
||||
}
|
||||
if ((next_tb & TB_EXIT_MASK) == TB_EXIT_REQUESTED) {
|
||||
/* We were asked to stop executing TBs (probably a pending
|
||||
* interrupt. We've now stopped, so clear the flag.
|
||||
*/
|
||||
env->tcg_exit_req = 0;
|
||||
}
|
||||
return next_tb;
|
||||
}
|
||||
|
||||
/* Execute the code without caching the generated code. An interpreter
|
||||
could be used if available. */
|
||||
static void cpu_exec_nocache(CPUArchState *env, int max_cycles,
|
||||
TranslationBlock *orig_tb)
|
||||
{
|
||||
tcg_target_ulong next_tb;
|
||||
TranslationBlock *tb;
|
||||
|
||||
/* Should never happen.
|
||||
@@ -68,14 +88,8 @@ static void cpu_exec_nocache(CPUArchState *env, int max_cycles,
|
||||
max_cycles);
|
||||
env->current_tb = tb;
|
||||
/* execute the generated code */
|
||||
next_tb = tcg_qemu_tb_exec(env, tb->tc_ptr);
|
||||
cpu_tb_exec(env, tb->tc_ptr);
|
||||
env->current_tb = NULL;
|
||||
|
||||
if ((next_tb & 3) == 2) {
|
||||
/* Restore PC. This may happen if async event occurs before
|
||||
the TB starts executing. */
|
||||
cpu_pc_from_tb(env, tb);
|
||||
}
|
||||
tb_phys_invalidate(tb, -1);
|
||||
tb_free(tb);
|
||||
}
|
||||
@@ -583,7 +597,8 @@ int cpu_exec(CPUArchState *env)
|
||||
spans two pages, we cannot safely do a direct
|
||||
jump. */
|
||||
if (next_tb != 0 && tb->page_addr[1] == -1) {
|
||||
tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
|
||||
tb_add_jump((TranslationBlock *)(next_tb & ~TB_EXIT_MASK),
|
||||
next_tb & TB_EXIT_MASK, tb);
|
||||
}
|
||||
spin_unlock(&tb_lock);
|
||||
|
||||
@@ -596,13 +611,24 @@ int cpu_exec(CPUArchState *env)
|
||||
if (likely(!env->exit_request)) {
|
||||
tc_ptr = tb->tc_ptr;
|
||||
/* execute the generated code */
|
||||
next_tb = tcg_qemu_tb_exec(env, tc_ptr);
|
||||
if ((next_tb & 3) == 2) {
|
||||
next_tb = cpu_tb_exec(env, tc_ptr);
|
||||
switch (next_tb & TB_EXIT_MASK) {
|
||||
case TB_EXIT_REQUESTED:
|
||||
/* Something asked us to stop executing
|
||||
* chained TBs; just continue round the main
|
||||
* loop. Whatever requested the exit will also
|
||||
* have set something else (eg exit_request or
|
||||
* interrupt_request) which we will handle
|
||||
* next time around the loop.
|
||||
*/
|
||||
tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK);
|
||||
next_tb = 0;
|
||||
break;
|
||||
case TB_EXIT_ICOUNT_EXPIRED:
|
||||
{
|
||||
/* Instruction counter expired. */
|
||||
int insns_left;
|
||||
tb = (TranslationBlock *)(next_tb & ~3);
|
||||
/* Restore PC. */
|
||||
cpu_pc_from_tb(env, tb);
|
||||
tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK);
|
||||
insns_left = env->icount_decr.u32;
|
||||
if (env->icount_extra && insns_left >= 0) {
|
||||
/* Refill decrementer and continue execution. */
|
||||
@@ -623,6 +649,10 @@ int cpu_exec(CPUArchState *env)
|
||||
next_tb = 0;
|
||||
cpu_loop_exit(env);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
env->current_tb = NULL;
|
||||
|
||||
@@ -493,7 +493,7 @@ void cpu_reset_interrupt(CPUArchState *env, int mask)
|
||||
void cpu_exit(CPUArchState *env)
|
||||
{
|
||||
env->exit_request = 1;
|
||||
cpu_unlink_tb(env);
|
||||
env->tcg_exit_req = 1;
|
||||
}
|
||||
|
||||
void cpu_abort(CPUArchState *env, const char *fmt, ...)
|
||||
|
||||
@@ -284,7 +284,7 @@ static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
|
||||
if ((fs_ctx->export_flags & V9FS_SM_MAPPED) ||
|
||||
(fs_ctx->export_flags & V9FS_SM_MAPPED_FILE)) {
|
||||
int fd;
|
||||
fd = open(rpath(fs_ctx, path, buffer), O_RDONLY);
|
||||
fd = open(rpath(fs_ctx, path, buffer), O_RDONLY | O_NOFOLLOW);
|
||||
if (fd == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
+1
-1
@@ -659,7 +659,7 @@ static mode_t v9mode_to_mode(uint32_t mode, V9fsString *extension)
|
||||
ret |= S_IFIFO;
|
||||
}
|
||||
if (mode & P9_STAT_MODE_DEVICE) {
|
||||
if (extension && extension->data[0] == 'c') {
|
||||
if (extension->size && extension->data[0] == 'c') {
|
||||
ret |= S_IFCHR;
|
||||
} else {
|
||||
ret |= S_IFBLK;
|
||||
|
||||
+1
-1
@@ -96,7 +96,7 @@ typedef struct DeviceClass {
|
||||
/* Private to qdev / bus. */
|
||||
qdev_initfn init; /* TODO remove, once users are converted to realize */
|
||||
qdev_event unplug;
|
||||
qdev_event exit;
|
||||
qdev_event exit; /* TODO remove, once users are converted to unrealize */
|
||||
const char *bus_type;
|
||||
} DeviceClass;
|
||||
|
||||
|
||||
@@ -180,6 +180,19 @@ static void device_realize(DeviceState *dev, Error **err)
|
||||
}
|
||||
}
|
||||
|
||||
static void device_unrealize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_GET_CLASS(dev);
|
||||
|
||||
if (dc->exit) {
|
||||
int rc = dc->exit(dev);
|
||||
if (rc < 0) {
|
||||
error_setg(errp, "Device exit failed.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
|
||||
int required_for_version)
|
||||
{
|
||||
@@ -692,6 +705,9 @@ static void device_set_realized(Object *obj, bool value, Error **err)
|
||||
device_reset(dev);
|
||||
}
|
||||
} else if (!value && dev->realized) {
|
||||
if (qdev_get_vmsd(dev)) {
|
||||
vmstate_unregister(dev, qdev_get_vmsd(dev), dev);
|
||||
}
|
||||
if (dc->unrealize) {
|
||||
dc->unrealize(dev, &local_err);
|
||||
}
|
||||
@@ -758,7 +774,6 @@ static void device_class_base_init(ObjectClass *class, void *data)
|
||||
static void device_unparent(Object *obj)
|
||||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
DeviceClass *dc = DEVICE_GET_CLASS(dev);
|
||||
BusState *bus;
|
||||
|
||||
while (dev->num_child_bus) {
|
||||
@@ -766,12 +781,7 @@ static void device_unparent(Object *obj)
|
||||
qbus_free(bus);
|
||||
}
|
||||
if (dev->realized) {
|
||||
if (qdev_get_vmsd(dev)) {
|
||||
vmstate_unregister(dev, qdev_get_vmsd(dev), dev);
|
||||
}
|
||||
if (dc->exit) {
|
||||
dc->exit(dev);
|
||||
}
|
||||
object_property_set_bool(obj, false, "realized", NULL);
|
||||
}
|
||||
if (dev->parent_bus) {
|
||||
bus_remove_child(dev->parent_bus, dev);
|
||||
@@ -786,6 +796,7 @@ static void device_class_init(ObjectClass *class, void *data)
|
||||
|
||||
class->unparent = device_unparent;
|
||||
dc->realize = device_realize;
|
||||
dc->unrealize = device_unrealize;
|
||||
}
|
||||
|
||||
void device_reset(DeviceState *dev)
|
||||
|
||||
@@ -662,10 +662,16 @@ static void virtio_ccw_notify(DeviceState *d, uint16_t vector)
|
||||
}
|
||||
|
||||
if (vector < VIRTIO_PCI_QUEUE_MAX) {
|
||||
if (!dev->indicators) {
|
||||
return;
|
||||
}
|
||||
indicators = ldq_phys(dev->indicators);
|
||||
indicators |= 1ULL << vector;
|
||||
stq_phys(dev->indicators, indicators);
|
||||
} else {
|
||||
if (!dev->indicators2) {
|
||||
return;
|
||||
}
|
||||
vector = 0;
|
||||
indicators = ldq_phys(dev->indicators2);
|
||||
indicators |= 1ULL << vector;
|
||||
|
||||
@@ -1985,6 +1985,10 @@ static int usbredir_post_load(void *priv, int version_id)
|
||||
{
|
||||
USBRedirDevice *dev = priv;
|
||||
|
||||
if (dev->parser == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (dev->device_info.speed) {
|
||||
case usb_redir_speed_low:
|
||||
dev->dev.speed = USB_SPEED_LOW;
|
||||
|
||||
+1
-1
@@ -291,7 +291,7 @@ static void virtio_balloon_set_config(VirtIODevice *vdev,
|
||||
dev->actual = le32_to_cpu(config.actual);
|
||||
if (dev->actual != oldactual) {
|
||||
qemu_balloon_changed(ram_size -
|
||||
(dev->actual << VIRTIO_BALLOON_PFN_SHIFT));
|
||||
((ram_addr_t) dev->actual << VIRTIO_BALLOON_PFN_SHIFT));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -161,6 +161,7 @@ typedef struct CPUWatchpoint {
|
||||
uint32_t halted; /* Nonzero if the CPU is in suspend state */ \
|
||||
uint32_t interrupt_request; \
|
||||
volatile sig_atomic_t exit_request; \
|
||||
volatile sig_atomic_t tcg_exit_req; \
|
||||
CPU_COMMON_TLB \
|
||||
struct TranslationBlock *tb_jmp_cache[TB_JMP_CACHE_SIZE]; \
|
||||
/* buffer for temporaries in the code generator */ \
|
||||
|
||||
@@ -7,10 +7,18 @@
|
||||
|
||||
static TCGArg *icount_arg;
|
||||
static int icount_label;
|
||||
static int exitreq_label;
|
||||
|
||||
static inline void gen_icount_start(void)
|
||||
{
|
||||
TCGv_i32 count;
|
||||
TCGv_i32 flag;
|
||||
|
||||
exitreq_label = gen_new_label();
|
||||
flag = tcg_temp_local_new_i32();
|
||||
tcg_gen_ld_i32(flag, cpu_env, offsetof(CPUArchState, tcg_exit_req));
|
||||
tcg_gen_brcondi_i32(TCG_COND_NE, flag, 0, exitreq_label);
|
||||
tcg_temp_free_i32(flag);
|
||||
|
||||
if (!use_icount)
|
||||
return;
|
||||
@@ -29,10 +37,13 @@ static inline void gen_icount_start(void)
|
||||
|
||||
static void gen_icount_end(TranslationBlock *tb, int num_insns)
|
||||
{
|
||||
gen_set_label(exitreq_label);
|
||||
tcg_gen_exit_tb((tcg_target_long)tb + TB_EXIT_REQUESTED);
|
||||
|
||||
if (use_icount) {
|
||||
*icount_arg = num_insns;
|
||||
gen_set_label(icount_label);
|
||||
tcg_gen_exit_tb((tcg_target_long)tb + 2);
|
||||
tcg_gen_exit_tb((tcg_target_long)tb + TB_EXIT_ICOUNT_EXPIRED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -628,7 +628,7 @@ static int net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
|
||||
vhostfdname || (tap->has_vhostforce && tap->vhostforce)) {
|
||||
int vhostfd;
|
||||
|
||||
if (tap->has_vhostfd) {
|
||||
if (tap->has_vhostfd || tap->has_vhostfds) {
|
||||
vhostfd = monitor_handle_fd_param(cur_mon, vhostfdname);
|
||||
if (vhostfd == -1) {
|
||||
return -1;
|
||||
|
||||
+12
@@ -23,6 +23,7 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
@@ -67,6 +68,13 @@ static BOOL WINAPI qemu_ctrl_handler(DWORD type)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static TIMECAPS mm_tc;
|
||||
|
||||
static void os_undo_timer_resolution(void)
|
||||
{
|
||||
timeEndPeriod(mm_tc.wPeriodMin);
|
||||
}
|
||||
|
||||
void os_setup_early_signal_handling(void)
|
||||
{
|
||||
/* Note: cpu_interrupt() is currently not SMP safe, so we force
|
||||
@@ -88,6 +96,10 @@ void os_setup_early_signal_handling(void)
|
||||
SetProcessAffinityMask(h, mask);
|
||||
}
|
||||
}
|
||||
|
||||
timeGetDevCaps(&mm_tc, sizeof(mm_tc));
|
||||
timeBeginPeriod(mm_tc.wPeriodMin);
|
||||
atexit(os_undo_timer_resolution);
|
||||
}
|
||||
|
||||
/* Look for support files in the same directory as the executable. */
|
||||
|
||||
+7
-12
@@ -2092,18 +2092,13 @@ QEMU supports using either local sheepdog devices or remote networked
|
||||
devices.
|
||||
|
||||
Syntax for specifying a sheepdog device
|
||||
@table @list
|
||||
``sheepdog:<vdiname>''
|
||||
|
||||
``sheepdog:<vdiname>:<snapid>''
|
||||
|
||||
``sheepdog:<vdiname>:<tag>''
|
||||
|
||||
``sheepdog:<host>:<port>:<vdiname>''
|
||||
|
||||
``sheepdog:<host>:<port>:<vdiname>:<snapid>''
|
||||
|
||||
``sheepdog:<host>:<port>:<vdiname>:<tag>''
|
||||
@table @code
|
||||
@item sheepdog:<vdiname>
|
||||
@item sheepdog:<vdiname>:<snapid>
|
||||
@item sheepdog:<vdiname>:<tag>
|
||||
@item sheepdog:<host>:<port>:<vdiname>
|
||||
@item sheepdog:<host>:<port>:<vdiname>:<snapid>
|
||||
@item sheepdog:<host>:<port>:<vdiname>:<tag>
|
||||
@end table
|
||||
|
||||
Example
|
||||
|
||||
+6
-18
@@ -624,28 +624,14 @@ static void CALLBACK mm_alarm_handler(UINT uTimerID, UINT uMsg,
|
||||
static int mm_start_timer(struct qemu_alarm_timer *t)
|
||||
{
|
||||
timeGetDevCaps(&mm_tc, sizeof(mm_tc));
|
||||
|
||||
timeBeginPeriod(mm_tc.wPeriodMin);
|
||||
|
||||
mm_timer = timeSetEvent(mm_tc.wPeriodMin, /* interval (ms) */
|
||||
mm_tc.wPeriodMin, /* resolution */
|
||||
mm_alarm_handler, /* function */
|
||||
(DWORD_PTR)t, /* parameter */
|
||||
TIME_ONESHOT | TIME_CALLBACK_FUNCTION);
|
||||
|
||||
if (!mm_timer) {
|
||||
fprintf(stderr, "Failed to initialize win32 alarm timer\n");
|
||||
timeEndPeriod(mm_tc.wPeriodMin);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mm_stop_timer(struct qemu_alarm_timer *t)
|
||||
{
|
||||
timeKillEvent(mm_timer);
|
||||
timeEndPeriod(mm_tc.wPeriodMin);
|
||||
if (mm_timer) {
|
||||
timeKillEvent(mm_timer);
|
||||
}
|
||||
}
|
||||
|
||||
static void mm_rearm_timer(struct qemu_alarm_timer *t, int64_t delta)
|
||||
@@ -657,7 +643,9 @@ static void mm_rearm_timer(struct qemu_alarm_timer *t, int64_t delta)
|
||||
nearest_delta_ms = mm_tc.wPeriodMax;
|
||||
}
|
||||
|
||||
timeKillEvent(mm_timer);
|
||||
if (mm_timer) {
|
||||
timeKillEvent(mm_timer);
|
||||
}
|
||||
mm_timer = timeSetEvent((UINT)nearest_delta_ms,
|
||||
mm_tc.wPeriodMin,
|
||||
mm_alarm_handler,
|
||||
|
||||
+129
-4
@@ -162,9 +162,135 @@ static GuestFileHandle *guest_file_handle_find(int64_t id, Error **err)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
typedef const char * const ccpc;
|
||||
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
|
||||
/* http://pubs.opengroup.org/onlinepubs/9699919799/functions/fopen.html */
|
||||
static const struct {
|
||||
ccpc *forms;
|
||||
int oflag_base;
|
||||
} guest_file_open_modes[] = {
|
||||
{ (ccpc[]){ "r", NULL }, O_RDONLY },
|
||||
{ (ccpc[]){ "rb", NULL }, O_RDONLY | O_BINARY },
|
||||
{ (ccpc[]){ "w", NULL }, O_WRONLY | O_CREAT | O_TRUNC },
|
||||
{ (ccpc[]){ "wb", NULL }, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY },
|
||||
{ (ccpc[]){ "a", NULL }, O_WRONLY | O_CREAT | O_APPEND },
|
||||
{ (ccpc[]){ "ab", NULL }, O_WRONLY | O_CREAT | O_APPEND | O_BINARY },
|
||||
{ (ccpc[]){ "r+", NULL }, O_RDWR },
|
||||
{ (ccpc[]){ "rb+", "r+b", NULL }, O_RDWR | O_BINARY },
|
||||
{ (ccpc[]){ "w+", NULL }, O_RDWR | O_CREAT | O_TRUNC },
|
||||
{ (ccpc[]){ "wb+", "w+b", NULL }, O_RDWR | O_CREAT | O_TRUNC | O_BINARY },
|
||||
{ (ccpc[]){ "a+", NULL }, O_RDWR | O_CREAT | O_APPEND },
|
||||
{ (ccpc[]){ "ab+", "a+b", NULL }, O_RDWR | O_CREAT | O_APPEND | O_BINARY }
|
||||
};
|
||||
|
||||
static int
|
||||
find_open_flag(const char *mode_str, Error **err)
|
||||
{
|
||||
unsigned mode;
|
||||
|
||||
for (mode = 0; mode < ARRAY_SIZE(guest_file_open_modes); ++mode) {
|
||||
ccpc *form;
|
||||
|
||||
form = guest_file_open_modes[mode].forms;
|
||||
while (*form != NULL && strcmp(*form, mode_str) != 0) {
|
||||
++form;
|
||||
}
|
||||
if (*form != NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mode == ARRAY_SIZE(guest_file_open_modes)) {
|
||||
error_setg(err, "invalid file open mode '%s'", mode_str);
|
||||
return -1;
|
||||
}
|
||||
return guest_file_open_modes[mode].oflag_base | O_NOCTTY | O_NONBLOCK;
|
||||
}
|
||||
|
||||
#define DEFAULT_NEW_FILE_MODE (S_IRUSR | S_IWUSR | \
|
||||
S_IRGRP | S_IWGRP | \
|
||||
S_IROTH | S_IWOTH)
|
||||
|
||||
static FILE *
|
||||
safe_open_or_create(const char *path, const char *mode, Error **err)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
int oflag;
|
||||
|
||||
oflag = find_open_flag(mode, &local_err);
|
||||
if (local_err == NULL) {
|
||||
int fd;
|
||||
|
||||
/* If the caller wants / allows creation of a new file, we implement it
|
||||
* with a two step process: open() + (open() / fchmod()).
|
||||
*
|
||||
* First we insist on creating the file exclusively as a new file. If
|
||||
* that succeeds, we're free to set any file-mode bits on it. (The
|
||||
* motivation is that we want to set those file-mode bits independently
|
||||
* of the current umask.)
|
||||
*
|
||||
* If the exclusive creation fails because the file already exists
|
||||
* (EEXIST is not possible for any other reason), we just attempt to
|
||||
* open the file, but in this case we won't be allowed to change the
|
||||
* file-mode bits on the preexistent file.
|
||||
*
|
||||
* The pathname should never disappear between the two open()s in
|
||||
* practice. If it happens, then someone very likely tried to race us.
|
||||
* In this case just go ahead and report the ENOENT from the second
|
||||
* open() to the caller.
|
||||
*
|
||||
* If the caller wants to open a preexistent file, then the first
|
||||
* open() is decisive and its third argument is ignored, and the second
|
||||
* open() and the fchmod() are never called.
|
||||
*/
|
||||
fd = open(path, oflag | ((oflag & O_CREAT) ? O_EXCL : 0), 0);
|
||||
if (fd == -1 && errno == EEXIST) {
|
||||
oflag &= ~(unsigned)O_CREAT;
|
||||
fd = open(path, oflag);
|
||||
}
|
||||
|
||||
if (fd == -1) {
|
||||
error_setg_errno(&local_err, errno, "failed to open file '%s' "
|
||||
"(mode: '%s')", path, mode);
|
||||
} else {
|
||||
qemu_set_cloexec(fd);
|
||||
|
||||
if ((oflag & O_CREAT) && fchmod(fd, DEFAULT_NEW_FILE_MODE) == -1) {
|
||||
error_setg_errno(&local_err, errno, "failed to set permission "
|
||||
"0%03o on new file '%s' (mode: '%s')",
|
||||
(unsigned)DEFAULT_NEW_FILE_MODE, path, mode);
|
||||
} else {
|
||||
FILE *f;
|
||||
|
||||
f = fdopen(fd, mode);
|
||||
if (f == NULL) {
|
||||
error_setg_errno(&local_err, errno, "failed to associate "
|
||||
"stdio stream with file descriptor %d, "
|
||||
"file '%s' (mode: '%s')", fd, path, mode);
|
||||
} else {
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
if (oflag & O_CREAT) {
|
||||
unlink(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
error_propagate(err, local_err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, Error **err)
|
||||
{
|
||||
FILE *fh;
|
||||
Error *local_err = NULL;
|
||||
int fd;
|
||||
int64_t ret = -1, handle;
|
||||
|
||||
@@ -172,10 +298,9 @@ int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, E
|
||||
mode = "r";
|
||||
}
|
||||
slog("guest-file-open called, filepath: %s, mode: %s", path, mode);
|
||||
fh = fopen(path, mode);
|
||||
if (!fh) {
|
||||
error_setg_errno(err, errno, "failed to open file '%s' (mode: '%s')",
|
||||
path, mode);
|
||||
fh = safe_open_or_create(path, mode, &local_err);
|
||||
if (local_err != NULL) {
|
||||
error_propagate(err, local_err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -478,7 +478,7 @@ static void become_daemon(const char *pidfile)
|
||||
}
|
||||
}
|
||||
|
||||
umask(0);
|
||||
umask(S_IRWXG | S_IRWXO);
|
||||
sid = setsid();
|
||||
if (sid < 0) {
|
||||
goto fail;
|
||||
|
||||
@@ -24,8 +24,8 @@ DEF_HELPER_FLAGS_1(clz, TCG_CALL_NO_RWG_SE, tl, tl)
|
||||
#ifdef TARGET_MIPS64
|
||||
DEF_HELPER_FLAGS_1(dclo, TCG_CALL_NO_RWG_SE, tl, tl)
|
||||
DEF_HELPER_FLAGS_1(dclz, TCG_CALL_NO_RWG_SE, tl, tl)
|
||||
DEF_HELPER_4(dmult, void, env, int, tl, tl)
|
||||
DEF_HELPER_4(dmultu, void, env, int, tl, tl)
|
||||
DEF_HELPER_4(dmult, void, env, tl, tl, int)
|
||||
DEF_HELPER_4(dmultu, void, env, tl, tl, int)
|
||||
#endif
|
||||
|
||||
DEF_HELPER_3(muls, tl, env, tl, tl)
|
||||
|
||||
@@ -268,14 +268,14 @@ target_ulong helper_mulshiu(CPUMIPSState *env, target_ulong arg1,
|
||||
}
|
||||
|
||||
#ifdef TARGET_MIPS64
|
||||
void helper_dmult(CPUMIPSState *env, int acc, target_ulong arg1,
|
||||
target_ulong arg2)
|
||||
void helper_dmult(CPUMIPSState *env, target_ulong arg1,
|
||||
target_ulong arg2, int acc)
|
||||
{
|
||||
muls64(&(env->active_tc.LO[acc]), &(env->active_tc.HI[acc]), arg1, arg2);
|
||||
}
|
||||
|
||||
void helper_dmultu(CPUMIPSState *env, int acc, target_ulong arg1,
|
||||
target_ulong arg2)
|
||||
void helper_dmultu(CPUMIPSState *env, target_ulong arg1,
|
||||
target_ulong arg2, int acc)
|
||||
{
|
||||
mulu64(&(env->active_tc.LO[acc]), &(env->active_tc.HI[acc]), arg1, arg2);
|
||||
}
|
||||
|
||||
@@ -2777,11 +2777,11 @@ static void gen_muldiv(DisasContext *ctx, uint32_t opc,
|
||||
opn = "ddivu";
|
||||
break;
|
||||
case OPC_DMULT:
|
||||
gen_helper_dmult(cpu_env, acc, t0, t1);
|
||||
gen_helper_0e2i(dmult, t0, t1, acc);
|
||||
opn = "dmult";
|
||||
break;
|
||||
case OPC_DMULTU:
|
||||
gen_helper_dmultu(cpu_env, acc, t0, t1);
|
||||
gen_helper_0e2i(dmultu, t0, t1, acc);
|
||||
opn = "dmultu";
|
||||
break;
|
||||
#endif
|
||||
|
||||
@@ -4916,11 +4916,6 @@ static void init_proc_603E (CPUPPCState *env)
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000);
|
||||
/* XXX : not implemented */
|
||||
spr_register(env, SPR_IABR, "IABR",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000);
|
||||
/* Memory management */
|
||||
gen_low_BATs(env);
|
||||
gen_6xx_7xx_soft_tlb(env, 64, 2);
|
||||
|
||||
@@ -1024,6 +1024,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
|
||||
/* Simplify LT/GE comparisons vs zero to a single compare
|
||||
vs the high word of the input. */
|
||||
s->gen_opc_buf[op_index] = INDEX_op_setcond_i32;
|
||||
reset_temp(args[0]);
|
||||
gen_args[0] = args[0];
|
||||
gen_args[1] = args[2];
|
||||
gen_args[2] = args[4];
|
||||
|
||||
@@ -660,7 +660,54 @@ TCGv_i64 tcg_const_local_i64(int64_t val);
|
||||
|
||||
extern uint8_t *code_gen_prologue;
|
||||
|
||||
/* TCG targets may use a different definition of tcg_qemu_tb_exec. */
|
||||
/**
|
||||
* tcg_qemu_tb_exec:
|
||||
* @env: CPUArchState * for the CPU
|
||||
* @tb_ptr: address of generated code for the TB to execute
|
||||
*
|
||||
* Start executing code from a given translation block.
|
||||
* Where translation blocks have been linked, execution
|
||||
* may proceed from the given TB into successive ones.
|
||||
* Control eventually returns only when some action is needed
|
||||
* from the top-level loop: either control must pass to a TB
|
||||
* which has not yet been directly linked, or an asynchronous
|
||||
* event such as an interrupt needs handling.
|
||||
*
|
||||
* The return value is a pointer to the next TB to execute
|
||||
* (if known; otherwise zero). This pointer is assumed to be
|
||||
* 4-aligned, and the bottom two bits are used to return further
|
||||
* information:
|
||||
* 0, 1: the link between this TB and the next is via the specified
|
||||
* TB index (0 or 1). That is, we left the TB via (the equivalent
|
||||
* of) "goto_tb <index>". The main loop uses this to determine
|
||||
* how to link the TB just executed to the next.
|
||||
* 2: we are using instruction counting code generation, and we
|
||||
* did not start executing this TB because the instruction counter
|
||||
* would hit zero midway through it. In this case the next-TB pointer
|
||||
* returned is the TB we were about to execute, and the caller must
|
||||
* arrange to execute the remaining count of instructions.
|
||||
* 3: we stopped because the CPU's exit_request flag was set
|
||||
* (usually meaning that there is an interrupt that needs to be
|
||||
* handled). The next-TB pointer returned is the TB we were
|
||||
* about to execute when we noticed the pending exit request.
|
||||
*
|
||||
* If the bottom two bits indicate an exit-via-index then the CPU
|
||||
* state is correctly synchronised and ready for execution of the next
|
||||
* TB (and in particular the guest PC is the address to execute next).
|
||||
* Otherwise, we gave up on execution of this TB before it started, and
|
||||
* the caller must fix up the CPU state by calling cpu_pc_from_tb()
|
||||
* with the next-TB pointer we return.
|
||||
*
|
||||
* Note that TCG targets may use a different definition of tcg_qemu_tb_exec
|
||||
* to this default (which just calls the prologue.code emitted by
|
||||
* tcg_target_qemu_prologue()).
|
||||
*/
|
||||
#define TB_EXIT_MASK 3
|
||||
#define TB_EXIT_IDX0 0
|
||||
#define TB_EXIT_IDX1 1
|
||||
#define TB_EXIT_ICOUNT_EXPIRED 2
|
||||
#define TB_EXIT_REQUESTED 3
|
||||
|
||||
#if !defined(tcg_qemu_tb_exec)
|
||||
# define tcg_qemu_tb_exec(env, tb_ptr) \
|
||||
((tcg_target_ulong (*)(void *, void *))code_gen_prologue)(env, tb_ptr)
|
||||
|
||||
+1
-13
@@ -24,19 +24,7 @@ gcov-files-test-string-input-visitor-y = qapi/string-input-visitor.c
|
||||
check-unit-y += tests/test-string-output-visitor$(EXESUF)
|
||||
gcov-files-test-string-output-visitor-y = qapi/string-output-visitor.c
|
||||
check-unit-y += tests/test-coroutine$(EXESUF)
|
||||
ifeq ($(CONFIG_WIN32),y)
|
||||
gcov-files-test-coroutine-y = coroutine-win32.c
|
||||
else
|
||||
ifeq ($(CONFIG_UCONTEXT_COROUTINE),y)
|
||||
gcov-files-test-coroutine-y = coroutine-ucontext.c
|
||||
else
|
||||
ifeq ($(CONFIG_SIGALTSTACK_COROUTINE),y)
|
||||
gcov-files-test-coroutine-y = coroutine-sigaltstack.c
|
||||
else
|
||||
gcov-files-test-coroutine-y = coroutine-gthread.c
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
gcov-files-test-coroutine-y = coroutine-$(CONFIG_COROUTINE_BACKEND).c
|
||||
check-unit-y += tests/test-visitor-serialization$(EXESUF)
|
||||
check-unit-y += tests/test-iov$(EXESUF)
|
||||
gcov-files-test-iov-y = util/iov.c
|
||||
|
||||
Executable
+75
@@ -0,0 +1,75 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Test qemu-img rebase with zero clusters
|
||||
#
|
||||
# Copyright (C) 2013 Red Hat, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# creator
|
||||
owner=pbonzini@redhat.com
|
||||
|
||||
seq=`basename $0`
|
||||
echo "QA output created by $seq"
|
||||
|
||||
here=`pwd`
|
||||
tmp=/tmp/$$
|
||||
status=1 # failure is the default!
|
||||
|
||||
_cleanup()
|
||||
{
|
||||
_cleanup_test_img
|
||||
rm -f $TEST_IMG.old
|
||||
rm -f $TEST_IMG.new
|
||||
}
|
||||
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
# get standard environment, filters and checks
|
||||
. ./common.rc
|
||||
. ./common.filter
|
||||
|
||||
_supported_fmt qcow2 qed
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
|
||||
if test "$IMGFMT" = qcow2 && test $IMGOPTS = ""; then
|
||||
IMGOPTS=compat=1.1
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "== Creating images =="
|
||||
|
||||
size=10M
|
||||
_make_test_img $size
|
||||
$QEMU_IO -c "write -P 0x40 0 1048576" $TEST_IMG | _filter_qemu_io
|
||||
mv $TEST_IMG $TEST_IMG.old
|
||||
|
||||
_make_test_img $size
|
||||
$QEMU_IO -c "write -P 0x5a 0 1048576" $TEST_IMG | _filter_qemu_io
|
||||
mv $TEST_IMG $TEST_IMG.new
|
||||
|
||||
_make_test_img -b $TEST_IMG.old $size
|
||||
$QEMU_IO -c "write -z 0 1048576" $TEST_IMG | _filter_qemu_io
|
||||
|
||||
echo
|
||||
echo "== Rebasing the image =="
|
||||
|
||||
$QEMU_IMG rebase -b $TEST_IMG.new $TEST_IMG
|
||||
$QEMU_IO -c "read -P 0x00 0 1048576" $TEST_IMG | _filter_qemu_io
|
||||
|
||||
# success, all done
|
||||
echo "*** done"
|
||||
rm -f $seq.full
|
||||
status=0
|
||||
@@ -0,0 +1,17 @@
|
||||
QA output created by 050
|
||||
|
||||
== Creating images ==
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=10485760
|
||||
wrote 1048576/1048576 bytes at offset 0
|
||||
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=10485760
|
||||
wrote 1048576/1048576 bytes at offset 0
|
||||
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=10485760 backing_file='TEST_DIR/t.IMGFMT.old'
|
||||
wrote 1048576/1048576 bytes at offset 0
|
||||
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
|
||||
== Rebasing the image ==
|
||||
read 1048576/1048576 bytes at offset 0
|
||||
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
*** done
|
||||
@@ -54,3 +54,4 @@
|
||||
045 rw auto
|
||||
046 rw auto aio
|
||||
047 rw auto
|
||||
050 rw auto backing quick
|
||||
+2
-71
@@ -1350,55 +1350,6 @@ static TranslationBlock *tb_find_pc(uintptr_t tc_ptr)
|
||||
return &tbs[m_max];
|
||||
}
|
||||
|
||||
static void tb_reset_jump_recursive(TranslationBlock *tb);
|
||||
|
||||
static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
|
||||
{
|
||||
TranslationBlock *tb1, *tb_next, **ptb;
|
||||
unsigned int n1;
|
||||
|
||||
tb1 = tb->jmp_next[n];
|
||||
if (tb1 != NULL) {
|
||||
/* find head of list */
|
||||
for (;;) {
|
||||
n1 = (uintptr_t)tb1 & 3;
|
||||
tb1 = (TranslationBlock *)((uintptr_t)tb1 & ~3);
|
||||
if (n1 == 2) {
|
||||
break;
|
||||
}
|
||||
tb1 = tb1->jmp_next[n1];
|
||||
}
|
||||
/* we are now sure now that tb jumps to tb1 */
|
||||
tb_next = tb1;
|
||||
|
||||
/* remove tb from the jmp_first list */
|
||||
ptb = &tb_next->jmp_first;
|
||||
for (;;) {
|
||||
tb1 = *ptb;
|
||||
n1 = (uintptr_t)tb1 & 3;
|
||||
tb1 = (TranslationBlock *)((uintptr_t)tb1 & ~3);
|
||||
if (n1 == n && tb1 == tb) {
|
||||
break;
|
||||
}
|
||||
ptb = &tb1->jmp_next[n1];
|
||||
}
|
||||
*ptb = tb->jmp_next[n];
|
||||
tb->jmp_next[n] = NULL;
|
||||
|
||||
/* suppress the jump to next tb in generated code */
|
||||
tb_reset_jump(tb, n);
|
||||
|
||||
/* suppress jumps in the tb on which we could have jumped */
|
||||
tb_reset_jump_recursive(tb_next);
|
||||
}
|
||||
}
|
||||
|
||||
static void tb_reset_jump_recursive(TranslationBlock *tb)
|
||||
{
|
||||
tb_reset_jump_recursive2(tb, 0);
|
||||
tb_reset_jump_recursive2(tb, 1);
|
||||
}
|
||||
|
||||
#if defined(TARGET_HAS_ICE) && !defined(CONFIG_USER_ONLY)
|
||||
void tb_invalidate_phys_addr(hwaddr addr)
|
||||
{
|
||||
@@ -1417,26 +1368,6 @@ void tb_invalidate_phys_addr(hwaddr addr)
|
||||
}
|
||||
#endif /* TARGET_HAS_ICE && !defined(CONFIG_USER_ONLY) */
|
||||
|
||||
void cpu_unlink_tb(CPUArchState *env)
|
||||
{
|
||||
/* FIXME: TB unchaining isn't SMP safe. For now just ignore the
|
||||
problem and hope the cpu will stop of its own accord. For userspace
|
||||
emulation this often isn't actually as bad as it sounds. Often
|
||||
signals are used primarily to interrupt blocking syscalls. */
|
||||
TranslationBlock *tb;
|
||||
static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
spin_lock(&interrupt_lock);
|
||||
tb = env->current_tb;
|
||||
/* if the cpu is currently executing code, we must unlink it and
|
||||
all the potentially executing TB */
|
||||
if (tb) {
|
||||
env->current_tb = NULL;
|
||||
tb_reset_jump_recursive(tb);
|
||||
}
|
||||
spin_unlock(&interrupt_lock);
|
||||
}
|
||||
|
||||
void tb_check_watchpoint(CPUArchState *env)
|
||||
{
|
||||
TranslationBlock *tb;
|
||||
@@ -1476,7 +1407,7 @@ static void tcg_handle_interrupt(CPUArchState *env, int mask)
|
||||
cpu_abort(env, "Raised interrupt while not in I/O function");
|
||||
}
|
||||
} else {
|
||||
cpu_unlink_tb(env);
|
||||
env->tcg_exit_req = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1617,7 +1548,7 @@ void dump_exec_info(FILE *f, fprintf_function cpu_fprintf)
|
||||
void cpu_interrupt(CPUArchState *env, int mask)
|
||||
{
|
||||
env->interrupt_request |= mask;
|
||||
cpu_unlink_tb(env);
|
||||
env->tcg_exit_req = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in new issue
Block a user