Compare commits
96
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dfa83a6bae | ||
|
|
35a616edef | ||
|
|
35c30d3efd | ||
|
|
f4c861fd68 | ||
|
|
b7a197c39e | ||
|
|
85611098ff | ||
|
|
ce4f451bbb | ||
|
|
6722c126f3 | ||
|
|
8dd45dcd83 | ||
|
|
e750591c8a | ||
|
|
f9c0ae2723 | ||
|
|
c8bd74d1d5 | ||
|
|
d1557697fd | ||
|
|
86d6fe4cb0 | ||
|
|
9634e45e0b | ||
|
|
0dc545e977 | ||
|
|
358f0ee234 | ||
|
|
961c74a841 | ||
|
|
98fe91ed66 | ||
|
|
46addaa0b5 | ||
|
|
5a4568717c | ||
|
|
87740cecc3 | ||
|
|
8df2a9acd2 | ||
|
|
c5c71e87aa | ||
|
|
2060efae47 | ||
|
|
8d64975c98 | ||
|
|
9b4420ad62 | ||
|
|
99c3468d8f | ||
|
|
1c17e8c7d3 | ||
|
|
ffd060d51f | ||
|
|
e4fb4bea37 | ||
|
|
edc0a65326 | ||
|
|
c62f6c8f67 | ||
|
|
3d8b7aed60 | ||
|
|
27ed14c4d7 | ||
|
|
6a45a1b8e4 | ||
|
|
6cacd2651a | ||
|
|
e8248a5af1 | ||
|
|
81cb0a5657 | ||
|
|
6130c46232 | ||
|
|
49ef542e41 | ||
|
|
c270245a53 | ||
|
|
9272707a1f | ||
|
|
c759f1a078 | ||
|
|
714b54401c | ||
|
|
e7e08380c3 | ||
|
|
c631ee6520 | ||
|
|
b153c8d3f3 | ||
|
|
f45048225a | ||
|
|
ae0fa48f51 | ||
|
|
bb3a1da4d4 | ||
|
|
b48a391cff | ||
|
|
cc883fe42d | ||
|
|
4072585ecf | ||
|
|
959fad0ff1 | ||
|
|
a4bb522ee5 | ||
|
|
cf6c213981 | ||
|
|
cf3297868c | ||
|
|
ad9c167fd2 | ||
|
|
d8e231fce2 | ||
|
|
53cd79c117 | ||
|
|
3dd15f3e58 | ||
|
|
4c59860506 | ||
|
|
b575af0730 | ||
|
|
d3b59789e8 | ||
|
|
e5b3a24181 | ||
|
|
f2a581010c | ||
|
|
e05ca82002 | ||
|
|
638b836620 | ||
|
|
87a8adc087 | ||
|
|
b6df74c465 | ||
|
|
0ca4f94195 | ||
|
|
993ebe4a0b | ||
|
|
6cec43e178 | ||
|
|
b8df9208f3 | ||
|
|
ae6e8ef11e | ||
|
|
4d0ecde44a | ||
|
|
342b0711cd | ||
|
|
c0c8584142 | ||
|
|
58c24a4775 | ||
|
|
b7ccb83f44 | ||
|
|
81b23ef82c | ||
|
|
6a460ed18a | ||
|
|
a6f2cb037a | ||
|
|
cf811fff2a | ||
|
|
05b685fbab | ||
|
|
e8d3b1a25f | ||
|
|
c8623c0215 | ||
|
|
2a6cdd6d35 | ||
|
|
e4603fe139 | ||
|
|
5a24f20a72 | ||
|
|
9be6e69f12 | ||
|
|
085feb61db | ||
|
|
7b4b0b5795 | ||
|
|
9c04146ad4 | ||
|
|
ecf2e5a46d |
No files matched your search
+2
-8
@@ -37,14 +37,8 @@
|
||||
/qemu-tech.html
|
||||
/qemu-doc.info
|
||||
/qemu-tech.info
|
||||
/qemu.1
|
||||
/qemu.pod
|
||||
/qemu-img.1
|
||||
/qemu-img.pod
|
||||
/qemu-img
|
||||
/qemu-nbd
|
||||
/qemu-nbd.8
|
||||
/qemu-nbd.pod
|
||||
/qemu-options.def
|
||||
/qemu-options.texi
|
||||
/qemu-img-cmds.texi
|
||||
@@ -56,8 +50,7 @@
|
||||
/qmp-commands.txt
|
||||
/vscclient
|
||||
/fsdev/virtfs-proxy-helper
|
||||
/fsdev/virtfs-proxy-helper.1
|
||||
/fsdev/virtfs-proxy-helper.pod
|
||||
*.[1-9]
|
||||
*.a
|
||||
*.aux
|
||||
*.cp
|
||||
@@ -70,6 +63,7 @@
|
||||
*.ky
|
||||
*.log
|
||||
*.pdf
|
||||
*.pod
|
||||
*.cps
|
||||
*.fns
|
||||
*.kys
|
||||
|
||||
@@ -72,12 +72,13 @@ int aio_bh_poll(AioContext *ctx)
|
||||
/* Make sure that fetching bh happens before accessing its members */
|
||||
smp_read_barrier_depends();
|
||||
next = bh->next;
|
||||
if (!bh->deleted && bh->scheduled) {
|
||||
bh->scheduled = 0;
|
||||
/* Paired with write barrier in bh schedule to ensure reading for
|
||||
* idle & callbacks coming after bh's scheduling.
|
||||
*/
|
||||
smp_rmb();
|
||||
/* The atomic_xchg is paired with the one in qemu_bh_schedule. The
|
||||
* implicit memory barrier ensures that the callback sees all writes
|
||||
* done by the scheduling thread. It also ensures that the scheduling
|
||||
* thread sees the zero before bh->cb has run, and thus will call
|
||||
* aio_notify again if necessary.
|
||||
*/
|
||||
if (!bh->deleted && atomic_xchg(&bh->scheduled, 0)) {
|
||||
if (!bh->idle)
|
||||
ret = 1;
|
||||
bh->idle = 0;
|
||||
@@ -108,33 +109,28 @@ int aio_bh_poll(AioContext *ctx)
|
||||
|
||||
void qemu_bh_schedule_idle(QEMUBH *bh)
|
||||
{
|
||||
if (bh->scheduled)
|
||||
return;
|
||||
bh->idle = 1;
|
||||
/* Make sure that idle & any writes needed by the callback are done
|
||||
* before the locations are read in the aio_bh_poll.
|
||||
*/
|
||||
smp_wmb();
|
||||
bh->scheduled = 1;
|
||||
atomic_mb_set(&bh->scheduled, 1);
|
||||
}
|
||||
|
||||
void qemu_bh_schedule(QEMUBH *bh)
|
||||
{
|
||||
AioContext *ctx;
|
||||
|
||||
if (bh->scheduled)
|
||||
return;
|
||||
ctx = bh->ctx;
|
||||
bh->idle = 0;
|
||||
/* Make sure that:
|
||||
/* The memory barrier implicit in atomic_xchg makes sure that:
|
||||
* 1. idle & any writes needed by the callback are done before the
|
||||
* locations are read in the aio_bh_poll.
|
||||
* 2. ctx is loaded before scheduled is set and the callback has a chance
|
||||
* to execute.
|
||||
*/
|
||||
smp_mb();
|
||||
bh->scheduled = 1;
|
||||
aio_notify(ctx);
|
||||
if (atomic_xchg(&bh->scheduled, 1) == 0) {
|
||||
aio_notify(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -99,8 +99,6 @@ static QLIST_HEAD(, BlockDriver) bdrv_drivers =
|
||||
|
||||
static void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
|
||||
int nr_sectors);
|
||||
static void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
|
||||
int nr_sectors);
|
||||
/* If non-zero, use only whitelisted block drivers */
|
||||
static int use_bdrv_whitelist;
|
||||
|
||||
@@ -1382,7 +1380,7 @@ int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp)
|
||||
QemuOpts *opts = NULL;
|
||||
QDict *snapshot_options;
|
||||
BlockDriverState *bs_snapshot;
|
||||
Error *local_err;
|
||||
Error *local_err = NULL;
|
||||
int ret;
|
||||
|
||||
/* if snapshot, we create a temporary backing file and open it
|
||||
@@ -3118,19 +3116,6 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline uint64_t bdrv_get_align(BlockDriverState *bs)
|
||||
{
|
||||
/* TODO Lift BDRV_SECTOR_SIZE restriction in BlockDriver interface */
|
||||
return MAX(BDRV_SECTOR_SIZE, bs->request_alignment);
|
||||
}
|
||||
|
||||
static inline bool bdrv_req_is_aligned(BlockDriverState *bs,
|
||||
int64_t offset, size_t bytes)
|
||||
{
|
||||
int64_t align = bdrv_get_align(bs);
|
||||
return !(offset & (align - 1) || (bytes & (align - 1)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle a read request in coroutine context
|
||||
*/
|
||||
@@ -3141,7 +3126,8 @@ static int coroutine_fn bdrv_co_do_preadv(BlockDriverState *bs,
|
||||
BlockDriver *drv = bs->drv;
|
||||
BdrvTrackedRequest req;
|
||||
|
||||
uint64_t align = bdrv_get_align(bs);
|
||||
/* TODO Lift BDRV_SECTOR_SIZE restriction in BlockDriver interface */
|
||||
uint64_t align = MAX(BDRV_SECTOR_SIZE, bs->request_alignment);
|
||||
uint8_t *head_buf = NULL;
|
||||
uint8_t *tail_buf = NULL;
|
||||
QEMUIOVector local_qiov;
|
||||
@@ -3375,6 +3361,94 @@ static int coroutine_fn bdrv_aligned_pwritev(BlockDriverState *bs,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int coroutine_fn bdrv_co_do_zero_pwritev(BlockDriverState *bs,
|
||||
int64_t offset,
|
||||
unsigned int bytes,
|
||||
BdrvRequestFlags flags,
|
||||
BdrvTrackedRequest *req)
|
||||
{
|
||||
uint8_t *buf = NULL;
|
||||
QEMUIOVector local_qiov;
|
||||
struct iovec iov;
|
||||
uint64_t align = MAX(BDRV_SECTOR_SIZE, bs->request_alignment);
|
||||
unsigned int head_padding_bytes, tail_padding_bytes;
|
||||
int ret = 0;
|
||||
|
||||
head_padding_bytes = offset & (align - 1);
|
||||
tail_padding_bytes = align - ((offset + bytes) & (align - 1));
|
||||
|
||||
|
||||
assert(flags & BDRV_REQ_ZERO_WRITE);
|
||||
if (head_padding_bytes || tail_padding_bytes) {
|
||||
buf = qemu_blockalign(bs, align);
|
||||
iov = (struct iovec) {
|
||||
.iov_base = buf,
|
||||
.iov_len = align,
|
||||
};
|
||||
qemu_iovec_init_external(&local_qiov, &iov, 1);
|
||||
}
|
||||
if (head_padding_bytes) {
|
||||
uint64_t zero_bytes = MIN(bytes, align - head_padding_bytes);
|
||||
|
||||
/* RMW the unaligned part before head. */
|
||||
mark_request_serialising(req, align);
|
||||
wait_serialising_requests(req);
|
||||
BLKDBG_EVENT(bs, BLKDBG_PWRITEV_RMW_HEAD);
|
||||
ret = bdrv_aligned_preadv(bs, req, offset & ~(align - 1), align,
|
||||
align, &local_qiov, 0);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
BLKDBG_EVENT(bs, BLKDBG_PWRITEV_RMW_AFTER_HEAD);
|
||||
|
||||
memset(buf + head_padding_bytes, 0, zero_bytes);
|
||||
ret = bdrv_aligned_pwritev(bs, req, offset & ~(align - 1), align,
|
||||
&local_qiov,
|
||||
flags & ~BDRV_REQ_ZERO_WRITE);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
offset += zero_bytes;
|
||||
bytes -= zero_bytes;
|
||||
}
|
||||
|
||||
assert(!bytes || (offset & (align - 1)) == 0);
|
||||
if (bytes >= align) {
|
||||
/* Write the aligned part in the middle. */
|
||||
uint64_t aligned_bytes = bytes & ~(align - 1);
|
||||
ret = bdrv_aligned_pwritev(bs, req, offset, aligned_bytes,
|
||||
NULL, flags);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
bytes -= aligned_bytes;
|
||||
offset += aligned_bytes;
|
||||
}
|
||||
|
||||
assert(!bytes || (offset & (align - 1)) == 0);
|
||||
if (bytes) {
|
||||
assert(align == tail_padding_bytes + bytes);
|
||||
/* RMW the unaligned part after tail. */
|
||||
mark_request_serialising(req, align);
|
||||
wait_serialising_requests(req);
|
||||
BLKDBG_EVENT(bs, BLKDBG_PWRITEV_RMW_TAIL);
|
||||
ret = bdrv_aligned_preadv(bs, req, offset, align,
|
||||
align, &local_qiov, 0);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
BLKDBG_EVENT(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL);
|
||||
|
||||
memset(buf, 0, bytes);
|
||||
ret = bdrv_aligned_pwritev(bs, req, offset, align,
|
||||
&local_qiov, flags & ~BDRV_REQ_ZERO_WRITE);
|
||||
}
|
||||
fail:
|
||||
qemu_vfree(buf);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle a write request in coroutine context
|
||||
*/
|
||||
@@ -3383,7 +3457,8 @@ static int coroutine_fn bdrv_co_do_pwritev(BlockDriverState *bs,
|
||||
BdrvRequestFlags flags)
|
||||
{
|
||||
BdrvTrackedRequest req;
|
||||
uint64_t align = bdrv_get_align(bs);
|
||||
/* TODO Lift BDRV_SECTOR_SIZE restriction in BlockDriver interface */
|
||||
uint64_t align = MAX(BDRV_SECTOR_SIZE, bs->request_alignment);
|
||||
uint8_t *head_buf = NULL;
|
||||
uint8_t *tail_buf = NULL;
|
||||
QEMUIOVector local_qiov;
|
||||
@@ -3414,6 +3489,11 @@ static int coroutine_fn bdrv_co_do_pwritev(BlockDriverState *bs,
|
||||
*/
|
||||
tracked_request_begin(&req, bs, offset, bytes, true);
|
||||
|
||||
if (!qiov) {
|
||||
ret = bdrv_co_do_zero_pwritev(bs, offset, bytes, flags, &req);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (offset & (align - 1)) {
|
||||
QEMUIOVector head_qiov;
|
||||
struct iovec head_iov;
|
||||
@@ -3482,23 +3562,19 @@ static int coroutine_fn bdrv_co_do_pwritev(BlockDriverState *bs,
|
||||
bytes = ROUND_UP(bytes, align);
|
||||
}
|
||||
|
||||
if (use_local_qiov) {
|
||||
/* Local buffer may have non-zero data. */
|
||||
flags &= ~BDRV_REQ_ZERO_WRITE;
|
||||
}
|
||||
ret = bdrv_aligned_pwritev(bs, &req, offset, bytes,
|
||||
use_local_qiov ? &local_qiov : qiov,
|
||||
flags);
|
||||
|
||||
fail:
|
||||
tracked_request_end(&req);
|
||||
|
||||
if (use_local_qiov) {
|
||||
qemu_iovec_destroy(&local_qiov);
|
||||
}
|
||||
qemu_vfree(head_buf);
|
||||
qemu_vfree(tail_buf);
|
||||
|
||||
out:
|
||||
tracked_request_end(&req);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -3526,32 +3602,14 @@ int coroutine_fn bdrv_co_write_zeroes(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors,
|
||||
BdrvRequestFlags flags)
|
||||
{
|
||||
int ret;
|
||||
|
||||
trace_bdrv_co_write_zeroes(bs, sector_num, nb_sectors, flags);
|
||||
|
||||
if (!(bs->open_flags & BDRV_O_UNMAP)) {
|
||||
flags &= ~BDRV_REQ_MAY_UNMAP;
|
||||
}
|
||||
if (bdrv_req_is_aligned(bs, sector_num << BDRV_SECTOR_BITS,
|
||||
nb_sectors << BDRV_SECTOR_BITS)) {
|
||||
ret = bdrv_co_do_writev(bs, sector_num, nb_sectors, NULL,
|
||||
BDRV_REQ_ZERO_WRITE | flags);
|
||||
} else {
|
||||
uint8_t *buf;
|
||||
QEMUIOVector local_qiov;
|
||||
size_t bytes = nb_sectors << BDRV_SECTOR_BITS;
|
||||
|
||||
buf = qemu_memalign(bdrv_opt_mem_align(bs), bytes);
|
||||
memset(buf, 0, bytes);
|
||||
qemu_iovec_init(&local_qiov, 1);
|
||||
qemu_iovec_add(&local_qiov, buf, bytes);
|
||||
|
||||
ret = bdrv_co_do_writev(bs, sector_num, nb_sectors, &local_qiov,
|
||||
BDRV_REQ_ZERO_WRITE | flags);
|
||||
qemu_vfree(buf);
|
||||
}
|
||||
return ret;
|
||||
return bdrv_co_do_writev(bs, sector_num, nb_sectors, NULL,
|
||||
BDRV_REQ_ZERO_WRITE | flags);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4142,28 +4200,54 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Coroutine wrapper for bdrv_get_block_status() */
|
||||
static void coroutine_fn bdrv_get_block_status_co_entry(void *opaque)
|
||||
static int64_t coroutine_fn bdrv_co_get_block_status_above(BlockDriverState *bs,
|
||||
BlockDriverState *base,
|
||||
int64_t sector_num,
|
||||
int nb_sectors,
|
||||
int *pnum)
|
||||
{
|
||||
BlockDriverState *p;
|
||||
int64_t ret = 0;
|
||||
|
||||
assert(bs != base);
|
||||
for (p = bs; p != base; p = p->backing_hd) {
|
||||
ret = bdrv_co_get_block_status(p, sector_num, nb_sectors, pnum);
|
||||
if (ret < 0 || ret & BDRV_BLOCK_ALLOCATED) {
|
||||
break;
|
||||
}
|
||||
/* [sector_num, pnum] unallocated on this layer, which could be only
|
||||
* the first part of [sector_num, nb_sectors]. */
|
||||
nb_sectors = MIN(nb_sectors, *pnum);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Coroutine wrapper for bdrv_get_block_status_above() */
|
||||
static void coroutine_fn bdrv_get_block_status_above_co_entry(void *opaque)
|
||||
{
|
||||
BdrvCoGetBlockStatusData *data = opaque;
|
||||
BlockDriverState *bs = data->bs;
|
||||
|
||||
data->ret = bdrv_co_get_block_status(bs, data->sector_num, data->nb_sectors,
|
||||
data->pnum);
|
||||
data->ret = bdrv_co_get_block_status_above(data->bs, data->base,
|
||||
data->sector_num,
|
||||
data->nb_sectors,
|
||||
data->pnum);
|
||||
data->done = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Synchronous wrapper around bdrv_co_get_block_status().
|
||||
* Synchronous wrapper around bdrv_co_get_block_status_above().
|
||||
*
|
||||
* See bdrv_co_get_block_status() for details.
|
||||
* See bdrv_co_get_block_status_above() for details.
|
||||
*/
|
||||
int64_t bdrv_get_block_status(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors, int *pnum)
|
||||
int64_t bdrv_get_block_status_above(BlockDriverState *bs,
|
||||
BlockDriverState *base,
|
||||
int64_t sector_num,
|
||||
int nb_sectors, int *pnum)
|
||||
{
|
||||
Coroutine *co;
|
||||
BdrvCoGetBlockStatusData data = {
|
||||
.bs = bs,
|
||||
.base = base,
|
||||
.sector_num = sector_num,
|
||||
.nb_sectors = nb_sectors,
|
||||
.pnum = pnum,
|
||||
@@ -4172,11 +4256,11 @@ int64_t bdrv_get_block_status(BlockDriverState *bs, int64_t sector_num,
|
||||
|
||||
if (qemu_in_coroutine()) {
|
||||
/* Fast-path if already in coroutine context */
|
||||
bdrv_get_block_status_co_entry(&data);
|
||||
bdrv_get_block_status_above_co_entry(&data);
|
||||
} else {
|
||||
AioContext *aio_context = bdrv_get_aio_context(bs);
|
||||
|
||||
co = qemu_coroutine_create(bdrv_get_block_status_co_entry);
|
||||
co = qemu_coroutine_create(bdrv_get_block_status_above_co_entry);
|
||||
qemu_coroutine_enter(co, &data);
|
||||
while (!data.done) {
|
||||
aio_poll(aio_context, true);
|
||||
@@ -4185,6 +4269,14 @@ int64_t bdrv_get_block_status(BlockDriverState *bs, int64_t sector_num,
|
||||
return data.ret;
|
||||
}
|
||||
|
||||
int64_t bdrv_get_block_status(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
int nb_sectors, int *pnum)
|
||||
{
|
||||
return bdrv_get_block_status_above(bs, bs->backing_hd,
|
||||
sector_num, nb_sectors, pnum);
|
||||
}
|
||||
|
||||
int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors, int *pnum)
|
||||
{
|
||||
@@ -5205,8 +5297,6 @@ int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num,
|
||||
return -EROFS;
|
||||
}
|
||||
|
||||
bdrv_reset_dirty(bs, sector_num, nb_sectors);
|
||||
|
||||
/* Do nothing if disabled. */
|
||||
if (!(bs->open_flags & BDRV_O_UNMAP)) {
|
||||
return 0;
|
||||
@@ -5216,6 +5306,8 @@ int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num,
|
||||
return 0;
|
||||
}
|
||||
|
||||
bdrv_set_dirty(bs, sector_num, nb_sectors);
|
||||
|
||||
max_discard = MIN_NON_ZERO(bs->bl.max_discard, BDRV_REQUEST_MAX_SECTORS);
|
||||
while (nb_sectors > 0) {
|
||||
int ret;
|
||||
@@ -5526,15 +5618,6 @@ static void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
|
||||
}
|
||||
}
|
||||
|
||||
static void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
|
||||
int nr_sectors)
|
||||
{
|
||||
BdrvDirtyBitmap *bitmap;
|
||||
QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
|
||||
hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
|
||||
}
|
||||
}
|
||||
|
||||
int64_t bdrv_get_dirty_count(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
|
||||
{
|
||||
return hbitmap_count(bitmap->bitmap);
|
||||
|
||||
+34
-7
@@ -56,6 +56,7 @@ typedef struct IscsiLun {
|
||||
uint64_t num_blocks;
|
||||
int events;
|
||||
QEMUTimer *nop_timer;
|
||||
QEMUTimer *event_timer;
|
||||
uint8_t lbpme;
|
||||
uint8_t lbprz;
|
||||
uint8_t has_write_same;
|
||||
@@ -95,6 +96,7 @@ typedef struct IscsiAIOCB {
|
||||
#endif
|
||||
} IscsiAIOCB;
|
||||
|
||||
#define EVENT_INTERVAL 250
|
||||
#define NOP_INTERVAL 5000
|
||||
#define MAX_NOP_FAILURES 3
|
||||
#define ISCSI_CMD_RETRIES ARRAY_SIZE(iscsi_retry_times)
|
||||
@@ -256,21 +258,30 @@ static void
|
||||
iscsi_set_events(IscsiLun *iscsilun)
|
||||
{
|
||||
struct iscsi_context *iscsi = iscsilun->iscsi;
|
||||
int ev;
|
||||
int ev = iscsi_which_events(iscsi);
|
||||
|
||||
/* We always register a read handler. */
|
||||
ev = POLLIN;
|
||||
ev |= iscsi_which_events(iscsi);
|
||||
if (ev != iscsilun->events) {
|
||||
aio_set_fd_handler(iscsilun->aio_context,
|
||||
iscsi_get_fd(iscsi),
|
||||
iscsi_process_read,
|
||||
(ev & POLLIN) ? iscsi_process_read : NULL,
|
||||
(ev & POLLOUT) ? iscsi_process_write : NULL,
|
||||
iscsilun);
|
||||
|
||||
iscsilun->events = ev;
|
||||
}
|
||||
|
||||
iscsilun->events = ev;
|
||||
/* newer versions of libiscsi may return zero events. In this
|
||||
* case start a timer to ensure we are able to return to service
|
||||
* once this situation changes. */
|
||||
if (!ev) {
|
||||
timer_mod(iscsilun->event_timer,
|
||||
qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + EVENT_INTERVAL);
|
||||
}
|
||||
}
|
||||
|
||||
static void iscsi_timed_set_events(void *opaque)
|
||||
{
|
||||
IscsiLun *iscsilun = opaque;
|
||||
iscsi_set_events(iscsilun);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1214,6 +1225,11 @@ static void iscsi_detach_aio_context(BlockDriverState *bs)
|
||||
timer_free(iscsilun->nop_timer);
|
||||
iscsilun->nop_timer = NULL;
|
||||
}
|
||||
if (iscsilun->event_timer) {
|
||||
timer_del(iscsilun->event_timer);
|
||||
timer_free(iscsilun->event_timer);
|
||||
iscsilun->event_timer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void iscsi_attach_aio_context(BlockDriverState *bs,
|
||||
@@ -1230,6 +1246,11 @@ static void iscsi_attach_aio_context(BlockDriverState *bs,
|
||||
iscsi_nop_timed_event, iscsilun);
|
||||
timer_mod(iscsilun->nop_timer,
|
||||
qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + NOP_INTERVAL);
|
||||
|
||||
/* Prepare a timer for a delayed call to iscsi_set_events */
|
||||
iscsilun->event_timer = aio_timer_new(iscsilun->aio_context,
|
||||
QEMU_CLOCK_REALTIME, SCALE_MS,
|
||||
iscsi_timed_set_events, iscsilun);
|
||||
}
|
||||
|
||||
static bool iscsi_is_write_protected(IscsiLun *iscsilun)
|
||||
@@ -1480,6 +1501,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));
|
||||
@@ -1493,6 +1517,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);
|
||||
|
||||
+24
-4
@@ -57,6 +57,7 @@ typedef struct MirrorBlockJob {
|
||||
int in_flight;
|
||||
int sectors_in_flight;
|
||||
int ret;
|
||||
bool unmap;
|
||||
} MirrorBlockJob;
|
||||
|
||||
typedef struct MirrorOp {
|
||||
@@ -167,6 +168,8 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
|
||||
int64_t end, sector_num, next_chunk, next_sector, hbitmap_next_sector;
|
||||
uint64_t delay_ns = 0;
|
||||
MirrorOp *op;
|
||||
int pnum;
|
||||
int64_t ret;
|
||||
|
||||
s->sector_num = hbitmap_iter_next(&s->hbi);
|
||||
if (s->sector_num < 0) {
|
||||
@@ -295,8 +298,22 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
|
||||
s->in_flight++;
|
||||
s->sectors_in_flight += nb_sectors;
|
||||
trace_mirror_one_iteration(s, sector_num, nb_sectors);
|
||||
bdrv_aio_readv(source, sector_num, &op->qiov, nb_sectors,
|
||||
mirror_read_complete, op);
|
||||
|
||||
ret = bdrv_get_block_status_above(source, NULL, sector_num,
|
||||
nb_sectors, &pnum);
|
||||
if (ret < 0 || pnum < nb_sectors ||
|
||||
(ret & BDRV_BLOCK_DATA && !(ret & BDRV_BLOCK_ZERO))) {
|
||||
bdrv_aio_readv(source, sector_num, &op->qiov, nb_sectors,
|
||||
mirror_read_complete, op);
|
||||
} else if (ret & BDRV_BLOCK_ZERO) {
|
||||
bdrv_aio_write_zeroes(s->target, sector_num, op->nb_sectors,
|
||||
s->unmap ? BDRV_REQ_MAY_UNMAP : 0,
|
||||
mirror_write_complete, op);
|
||||
} else {
|
||||
assert(!(ret & BDRV_BLOCK_DATA));
|
||||
bdrv_aio_discard(s->target, sector_num, op->nb_sectors,
|
||||
mirror_write_complete, op);
|
||||
}
|
||||
return delay_ns;
|
||||
}
|
||||
|
||||
@@ -660,6 +677,7 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target,
|
||||
int64_t buf_size,
|
||||
BlockdevOnError on_source_error,
|
||||
BlockdevOnError on_target_error,
|
||||
bool unmap,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque, Error **errp,
|
||||
const BlockJobDriver *driver,
|
||||
@@ -702,6 +720,7 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target,
|
||||
s->base = base;
|
||||
s->granularity = granularity;
|
||||
s->buf_size = MAX(buf_size, granularity);
|
||||
s->unmap = unmap;
|
||||
|
||||
s->dirty_bitmap = bdrv_create_dirty_bitmap(bs, granularity, errp);
|
||||
if (!s->dirty_bitmap) {
|
||||
@@ -720,6 +739,7 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target,
|
||||
int64_t speed, int64_t granularity, int64_t buf_size,
|
||||
MirrorSyncMode mode, BlockdevOnError on_source_error,
|
||||
BlockdevOnError on_target_error,
|
||||
bool unmap,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
@@ -730,7 +750,7 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target,
|
||||
base = mode == MIRROR_SYNC_MODE_TOP ? bs->backing_hd : NULL;
|
||||
mirror_start_job(bs, target, replaces,
|
||||
speed, granularity, buf_size,
|
||||
on_source_error, on_target_error, cb, opaque, errp,
|
||||
on_source_error, on_target_error, unmap, cb, opaque, errp,
|
||||
&mirror_job_driver, is_none_mode, base);
|
||||
}
|
||||
|
||||
@@ -778,7 +798,7 @@ void commit_active_start(BlockDriverState *bs, BlockDriverState *base,
|
||||
|
||||
bdrv_ref(base);
|
||||
mirror_start_job(bs, base, NULL, speed, 0, 0,
|
||||
on_error, on_error, cb, opaque, &local_err,
|
||||
on_error, on_error, false, cb, opaque, &local_err,
|
||||
&commit_active_job_driver, false, base);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
#include "sysemu/sysemu.h"
|
||||
#include <nfsc/libnfs.h>
|
||||
|
||||
#define QEMU_NFS_MAX_READAHEAD_SIZE 1048576
|
||||
|
||||
typedef struct NFSClient {
|
||||
struct nfs_context *context;
|
||||
struct nfsfh *fh;
|
||||
@@ -327,6 +329,11 @@ static int64_t nfs_client_open(NFSClient *client, const char *filename,
|
||||
nfs_set_tcp_syncnt(client->context, val);
|
||||
#ifdef LIBNFS_FEATURE_READAHEAD
|
||||
} else if (!strcmp(qp->p[i].name, "readahead")) {
|
||||
if (val > QEMU_NFS_MAX_READAHEAD_SIZE) {
|
||||
error_report("NFS Warning: Truncating NFS readahead"
|
||||
" size to %d", QEMU_NFS_MAX_READAHEAD_SIZE);
|
||||
val = QEMU_NFS_MAX_READAHEAD_SIZE;
|
||||
}
|
||||
nfs_set_readahead(client->context, val);
|
||||
#endif
|
||||
} else {
|
||||
|
||||
@@ -833,6 +833,11 @@ static int64_t alloc_clusters_noref(BlockDriverState *bs, uint64_t size)
|
||||
uint64_t i, nb_clusters, refcount;
|
||||
int ret;
|
||||
|
||||
/* We can't allocate clusters if they may still be queued for discard. */
|
||||
if (s->cache_discards) {
|
||||
qcow2_process_discards(bs, 0);
|
||||
}
|
||||
|
||||
nb_clusters = size_to_clusters(s, size);
|
||||
retry:
|
||||
for(i = 0; i < nb_clusters; i++) {
|
||||
|
||||
+22
-7
@@ -140,6 +140,7 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
|
||||
return 3;
|
||||
}
|
||||
bs->backing_format[ext.len] = '\0';
|
||||
s->image_backing_format = g_strdup(bs->backing_format);
|
||||
#ifdef DEBUG_EXT
|
||||
printf("Qcow2: Got format extension %s\n", bs->backing_format);
|
||||
#endif
|
||||
@@ -884,6 +885,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
goto fail;
|
||||
}
|
||||
bs->backing_file[len] = '\0';
|
||||
s->image_backing_file = g_strdup(bs->backing_file);
|
||||
}
|
||||
|
||||
/* Internal snapshots */
|
||||
@@ -1457,6 +1459,9 @@ static void qcow2_close(BlockDriverState *bs)
|
||||
g_free(s->unknown_header_fields);
|
||||
cleanup_unknown_header_ext(bs);
|
||||
|
||||
g_free(s->image_backing_file);
|
||||
g_free(s->image_backing_format);
|
||||
|
||||
g_free(s->cluster_cache);
|
||||
qemu_vfree(s->cluster_data);
|
||||
qcow2_refcount_close(bs);
|
||||
@@ -1622,9 +1627,10 @@ int qcow2_update_header(BlockDriverState *bs)
|
||||
}
|
||||
|
||||
/* Backing file format header extension */
|
||||
if (*bs->backing_format) {
|
||||
if (s->image_backing_format) {
|
||||
ret = header_ext_add(buf, QCOW2_EXT_MAGIC_BACKING_FORMAT,
|
||||
bs->backing_format, strlen(bs->backing_format),
|
||||
s->image_backing_format,
|
||||
strlen(s->image_backing_format),
|
||||
buflen);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
@@ -1682,8 +1688,8 @@ int qcow2_update_header(BlockDriverState *bs)
|
||||
buflen -= ret;
|
||||
|
||||
/* Backing file name */
|
||||
if (*bs->backing_file) {
|
||||
size_t backing_file_len = strlen(bs->backing_file);
|
||||
if (s->image_backing_file) {
|
||||
size_t backing_file_len = strlen(s->image_backing_file);
|
||||
|
||||
if (buflen < backing_file_len) {
|
||||
ret = -ENOSPC;
|
||||
@@ -1691,7 +1697,7 @@ int qcow2_update_header(BlockDriverState *bs)
|
||||
}
|
||||
|
||||
/* Using strncpy is ok here, since buf is not NUL-terminated. */
|
||||
strncpy(buf, bs->backing_file, buflen);
|
||||
strncpy(buf, s->image_backing_file, buflen);
|
||||
|
||||
header->backing_file_offset = cpu_to_be64(buf - ((char*) header));
|
||||
header->backing_file_size = cpu_to_be32(backing_file_len);
|
||||
@@ -1712,9 +1718,17 @@ fail:
|
||||
static int qcow2_change_backing_file(BlockDriverState *bs,
|
||||
const char *backing_file, const char *backing_fmt)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
|
||||
pstrcpy(bs->backing_file, sizeof(bs->backing_file), backing_file ?: "");
|
||||
pstrcpy(bs->backing_format, sizeof(bs->backing_format), backing_fmt ?: "");
|
||||
|
||||
g_free(s->image_backing_file);
|
||||
g_free(s->image_backing_format);
|
||||
|
||||
s->image_backing_file = backing_file ? g_strdup(bs->backing_file) : NULL;
|
||||
s->image_backing_format = backing_fmt ? g_strdup(bs->backing_format) : NULL;
|
||||
|
||||
return qcow2_update_header(bs);
|
||||
}
|
||||
|
||||
@@ -2751,8 +2765,9 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
|
||||
}
|
||||
|
||||
if (backing_file || backing_format) {
|
||||
ret = qcow2_change_backing_file(bs, backing_file ?: bs->backing_file,
|
||||
backing_format ?: bs->backing_format);
|
||||
ret = qcow2_change_backing_file(bs,
|
||||
backing_file ?: s->image_backing_file,
|
||||
backing_format ?: s->image_backing_format);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
+8
-1
@@ -62,7 +62,8 @@
|
||||
#define MIN_CLUSTER_BITS 9
|
||||
#define MAX_CLUSTER_BITS 21
|
||||
|
||||
#define MIN_L2_CACHE_SIZE 1 /* cluster */
|
||||
/* Must be at least 2 to cover COW */
|
||||
#define MIN_L2_CACHE_SIZE 2 /* clusters */
|
||||
|
||||
/* Must be at least 4 to cover all cases of refcount table growth */
|
||||
#define MIN_REFCOUNT_CACHE_SIZE 4 /* clusters */
|
||||
@@ -283,6 +284,12 @@ typedef struct BDRVQcowState {
|
||||
QLIST_HEAD(, Qcow2UnknownHeaderExtension) unknown_header_ext;
|
||||
QTAILQ_HEAD (, Qcow2DiscardRegion) discards;
|
||||
bool cache_discards;
|
||||
|
||||
/* Backing file path and format as stored in the image (this is not the
|
||||
* effective path/format, which may be the result of a runtime option
|
||||
* override) */
|
||||
char *image_backing_file;
|
||||
char *image_backing_format;
|
||||
} BDRVQcowState;
|
||||
|
||||
struct QCowAIOCB;
|
||||
|
||||
+26
-14
@@ -451,7 +451,8 @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent,
|
||||
Error **errp)
|
||||
{
|
||||
int ret;
|
||||
int l1_size, i;
|
||||
size_t l1_size;
|
||||
int i;
|
||||
|
||||
/* read the L1 table */
|
||||
l1_size = extent->l1_size * sizeof(uint32_t);
|
||||
@@ -1247,6 +1248,17 @@ static VmdkExtent *find_extent(BDRVVmdkState *s,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline uint64_t vmdk_find_index_in_cluster(VmdkExtent *extent,
|
||||
int64_t sector_num)
|
||||
{
|
||||
uint64_t index_in_cluster, extent_begin_sector, extent_relative_sector_num;
|
||||
|
||||
extent_begin_sector = extent->end_sector - extent->sectors;
|
||||
extent_relative_sector_num = sector_num - extent_begin_sector;
|
||||
index_in_cluster = extent_relative_sector_num % extent->cluster_sectors;
|
||||
return index_in_cluster;
|
||||
}
|
||||
|
||||
static int64_t coroutine_fn vmdk_co_get_block_status(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors, int *pnum)
|
||||
{
|
||||
@@ -1284,7 +1296,7 @@ static int64_t coroutine_fn vmdk_co_get_block_status(BlockDriverState *bs,
|
||||
break;
|
||||
}
|
||||
|
||||
index_in_cluster = sector_num % extent->cluster_sectors;
|
||||
index_in_cluster = vmdk_find_index_in_cluster(extent, sector_num);
|
||||
n = extent->cluster_sectors - index_in_cluster;
|
||||
if (n > nb_sectors) {
|
||||
n = nb_sectors;
|
||||
@@ -1302,6 +1314,8 @@ static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset,
|
||||
uLongf buf_len;
|
||||
const uint8_t *write_buf = buf;
|
||||
int write_len = nb_sectors * 512;
|
||||
int64_t write_offset;
|
||||
int64_t write_end_sector;
|
||||
|
||||
if (extent->compressed) {
|
||||
if (!extent->has_marker) {
|
||||
@@ -1320,10 +1334,14 @@ static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset,
|
||||
write_buf = (uint8_t *)data;
|
||||
write_len = buf_len + sizeof(VmdkGrainMarker);
|
||||
}
|
||||
ret = bdrv_pwrite(extent->file,
|
||||
cluster_offset + offset_in_cluster,
|
||||
write_buf,
|
||||
write_len);
|
||||
write_offset = cluster_offset + offset_in_cluster,
|
||||
ret = bdrv_pwrite(extent->file, write_offset, write_buf, write_len);
|
||||
|
||||
write_end_sector = DIV_ROUND_UP(write_offset + write_len, BDRV_SECTOR_SIZE);
|
||||
|
||||
extent->next_cluster_sector = MAX(extent->next_cluster_sector,
|
||||
write_end_sector);
|
||||
|
||||
if (ret != write_len) {
|
||||
ret = ret < 0 ? ret : -EIO;
|
||||
goto out;
|
||||
@@ -1406,7 +1424,6 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
int ret;
|
||||
uint64_t n, index_in_cluster;
|
||||
uint64_t extent_begin_sector, extent_relative_sector_num;
|
||||
VmdkExtent *extent = NULL;
|
||||
uint64_t cluster_offset;
|
||||
|
||||
@@ -1418,9 +1435,7 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
|
||||
ret = get_cluster_offset(bs, extent, NULL,
|
||||
sector_num << 9, false, &cluster_offset,
|
||||
0, 0);
|
||||
extent_begin_sector = extent->end_sector - extent->sectors;
|
||||
extent_relative_sector_num = sector_num - extent_begin_sector;
|
||||
index_in_cluster = extent_relative_sector_num % extent->cluster_sectors;
|
||||
index_in_cluster = vmdk_find_index_in_cluster(extent, sector_num);
|
||||
n = extent->cluster_sectors - index_in_cluster;
|
||||
if (n > nb_sectors) {
|
||||
n = nb_sectors;
|
||||
@@ -1482,7 +1497,6 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
|
||||
VmdkExtent *extent = NULL;
|
||||
int ret;
|
||||
int64_t index_in_cluster, n;
|
||||
uint64_t extent_begin_sector, extent_relative_sector_num;
|
||||
uint64_t cluster_offset;
|
||||
VmdkMetaData m_data;
|
||||
|
||||
@@ -1498,9 +1512,7 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
|
||||
if (!extent) {
|
||||
return -EIO;
|
||||
}
|
||||
extent_begin_sector = extent->end_sector - extent->sectors;
|
||||
extent_relative_sector_num = sector_num - extent_begin_sector;
|
||||
index_in_cluster = extent_relative_sector_num % extent->cluster_sectors;
|
||||
index_in_cluster = vmdk_find_index_in_cluster(extent, sector_num);
|
||||
n = extent->cluster_sectors - index_in_cluster;
|
||||
if (n > nb_sectors) {
|
||||
n = nb_sectors;
|
||||
|
||||
+14
-4
@@ -168,6 +168,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
uint8_t buf[HEADER_SIZE];
|
||||
uint32_t checksum;
|
||||
uint64_t computed_size;
|
||||
uint64_t pagetable_size;
|
||||
int disk_type = VHD_DYNAMIC;
|
||||
int ret;
|
||||
|
||||
@@ -269,7 +270,17 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
s->pagetable = qemu_try_blockalign(bs->file, s->max_table_entries * 4);
|
||||
if (s->max_table_entries > SIZE_MAX / 4 ||
|
||||
s->max_table_entries > (int) INT_MAX / 4) {
|
||||
error_setg(errp, "Max Table Entries too large (%" PRId32 ")",
|
||||
s->max_table_entries);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pagetable_size = (uint64_t) s->max_table_entries * 4;
|
||||
|
||||
s->pagetable = qemu_try_blockalign(bs->file, pagetable_size);
|
||||
if (s->pagetable == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
@@ -277,14 +288,13 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
|
||||
s->bat_offset = be64_to_cpu(dyndisk_header->table_offset);
|
||||
|
||||
ret = bdrv_pread(bs->file, s->bat_offset, s->pagetable,
|
||||
s->max_table_entries * 4);
|
||||
ret = bdrv_pread(bs->file, s->bat_offset, s->pagetable, pagetable_size);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
s->free_data_block_offset =
|
||||
(s->bat_offset + (s->max_table_entries * 4) + 511) & ~511;
|
||||
ROUND_UP(s->bat_offset + pagetable_size, 512);
|
||||
|
||||
for (i = 0; i < s->max_table_entries; i++) {
|
||||
be32_to_cpus(&s->pagetable[i]);
|
||||
|
||||
@@ -2461,6 +2461,7 @@ void qmp_drive_mirror(const char *device, const char *target,
|
||||
bool has_buf_size, int64_t buf_size,
|
||||
bool has_on_source_error, BlockdevOnError on_source_error,
|
||||
bool has_on_target_error, BlockdevOnError on_target_error,
|
||||
bool has_unmap, bool unmap,
|
||||
Error **errp)
|
||||
{
|
||||
BlockBackend *blk;
|
||||
@@ -2492,6 +2493,9 @@ void qmp_drive_mirror(const char *device, const char *target,
|
||||
if (!has_buf_size) {
|
||||
buf_size = DEFAULT_MIRROR_BUF_SIZE;
|
||||
}
|
||||
if (!has_unmap) {
|
||||
unmap = true;
|
||||
}
|
||||
|
||||
if (granularity != 0 && (granularity < 512 || granularity > 1048576 * 64)) {
|
||||
error_set(errp, QERR_INVALID_PARAMETER_VALUE, "granularity",
|
||||
@@ -2631,6 +2635,7 @@ void qmp_drive_mirror(const char *device, const char *target,
|
||||
has_replaces ? replaces : NULL,
|
||||
speed, granularity, buf_size, sync,
|
||||
on_source_error, on_target_error,
|
||||
unmap,
|
||||
block_job_cb, bs, &local_err);
|
||||
if (local_err != NULL) {
|
||||
bdrv_unref(target_bs);
|
||||
|
||||
@@ -327,7 +327,7 @@ seccomp=""
|
||||
glusterfs=""
|
||||
glusterfs_discard="no"
|
||||
glusterfs_zerofill="no"
|
||||
archipelago=""
|
||||
archipelago="no"
|
||||
gtk=""
|
||||
gtkabi=""
|
||||
vte=""
|
||||
@@ -1848,19 +1848,14 @@ fi
|
||||
# libseccomp check
|
||||
|
||||
if test "$seccomp" != "no" ; then
|
||||
if $pkg_config --atleast-version=2.2.0 libseccomp ||
|
||||
(test "$cpu" = "i386" || test "$cpu" = "x86_64" &&
|
||||
$pkg_config --atleast-version=2.1.1 libseccomp); then
|
||||
if test "$cpu" = "i386" || test "$cpu" = "x86_64" &&
|
||||
$pkg_config --atleast-version=2.1.1 libseccomp; 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
|
||||
if test "$cpu" = "i386" || test "$cpu" = "x86_64"; then
|
||||
feature_not_found "libseccomp" "Install libseccomp devel >= 2.1.1"
|
||||
else
|
||||
feature_not_found "libseccomp" "Install libseccomp devel >= 2.2.0"
|
||||
fi
|
||||
fi
|
||||
seccomp="no"
|
||||
fi
|
||||
@@ -3173,6 +3168,12 @@ EOF
|
||||
archipelago="yes"
|
||||
libs_tools="$archipelago_libs $libs_tools"
|
||||
libs_softmmu="$archipelago_libs $libs_softmmu"
|
||||
|
||||
echo "WARNING: Please check the licenses of QEMU and libxseg carefully."
|
||||
echo "GPLv3 versions of libxseg may not be compatible with QEMU's"
|
||||
echo "license and therefore prevent redistribution."
|
||||
echo
|
||||
echo "To disable Archipelago, use --disable-archipelago"
|
||||
else
|
||||
if test "$archipelago" = "yes" ; then
|
||||
feature_not_found "Archipelago backend support" "Install libxseg devel"
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
QEMU Firmware Configuration (fw_cfg) Device
|
||||
===========================================
|
||||
|
||||
= Guest-side Hardware Interface =
|
||||
|
||||
This hardware interface allows the guest to retrieve various data items
|
||||
(blobs) that can influence how the firmware configures itself, or may
|
||||
contain tables to be installed for the guest OS. Examples include device
|
||||
boot order, ACPI and SMBIOS tables, virtual machine UUID, SMP and NUMA
|
||||
information, kernel/initrd images for direct (Linux) kernel booting, etc.
|
||||
|
||||
== Selector (Control) Register ==
|
||||
|
||||
* Write only
|
||||
* Location: platform dependent (IOport or MMIO)
|
||||
* Width: 16-bit
|
||||
* Endianness: little-endian (if IOport), or big-endian (if MMIO)
|
||||
|
||||
A write to this register sets the index of a firmware configuration
|
||||
item which can subsequently be accessed via the data register.
|
||||
|
||||
Setting the selector register will cause the data offset to be set
|
||||
to zero. The data offset impacts which data is accessed via the data
|
||||
register, and is explained below.
|
||||
|
||||
Bit14 of the selector register indicates whether the configuration
|
||||
setting is being written. A value of 0 means the item is only being
|
||||
read, and all write access to the data port will be ignored. A value
|
||||
of 1 means the item's data can be overwritten by writes to the data
|
||||
register. In other words, configuration write mode is enabled when
|
||||
the selector value is between 0x4000-0x7fff or 0xc000-0xffff.
|
||||
|
||||
NOTE: As of QEMU v2.4, writes to the fw_cfg data register are no
|
||||
longer supported, and will be ignored (treated as no-ops)!
|
||||
|
||||
Bit15 of the selector register indicates whether the configuration
|
||||
setting is architecture specific. A value of 0 means the item is a
|
||||
generic configuration item. A value of 1 means the item is specific
|
||||
to a particular architecture. In other words, generic configuration
|
||||
items are accessed with a selector value between 0x0000-0x7fff, and
|
||||
architecture specific configuration items are accessed with a selector
|
||||
value between 0x8000-0xffff.
|
||||
|
||||
== Data Register ==
|
||||
|
||||
* Read/Write (writes ignored as of QEMU v2.4)
|
||||
* Location: platform dependent (IOport [*] or MMIO)
|
||||
* Width: 8-bit (if IOport), 8/16/32/64-bit (if MMIO)
|
||||
* Endianness: string-preserving
|
||||
|
||||
[*] On platforms where the data register is exposed as an IOport, its
|
||||
port number will always be one greater than the port number of the
|
||||
selector register. In other words, the two ports overlap, and can not
|
||||
be mapped separately.
|
||||
|
||||
The data register allows access to an array of bytes for each firmware
|
||||
configuration data item. The specific item is selected by writing to
|
||||
the selector register, as described above.
|
||||
|
||||
Initially following a write to the selector register, the data offset
|
||||
will be set to zero. Each successful access to the data register will
|
||||
increment the data offset by the appropriate access width.
|
||||
|
||||
Each firmware configuration item has a maximum length of data
|
||||
associated with the item. After the data offset has passed the
|
||||
end of this maximum data length, then any reads will return a data
|
||||
value of 0x00, and all writes will be ignored.
|
||||
|
||||
An N-byte wide read of the data register will return the next available
|
||||
N bytes of the selected firmware configuration item, as a substring, in
|
||||
increasing address order, similar to memcpy().
|
||||
|
||||
== Register Locations ==
|
||||
|
||||
=== x86, x86_64 Register Locations ===
|
||||
|
||||
Selector Register IOport: 0x510
|
||||
Data Register IOport: 0x511
|
||||
|
||||
== Firmware Configuration Items ==
|
||||
|
||||
=== Signature (Key 0x0000, FW_CFG_SIGNATURE) ===
|
||||
|
||||
The presence of the fw_cfg selector and data registers can be verified
|
||||
by selecting the "signature" item using key 0x0000 (FW_CFG_SIGNATURE),
|
||||
and reading four bytes from the data register. If the fw_cfg device is
|
||||
present, the four bytes read will contain the characters "QEMU".
|
||||
|
||||
=== Revision (Key 0x0001, FW_CFG_ID) ===
|
||||
|
||||
A 32-bit little-endian unsigned int, this item is used as an interface
|
||||
revision number, and is currently set to 1 by QEMU when fw_cfg is
|
||||
initialized.
|
||||
|
||||
=== File Directory (Key 0x0019, FW_CFG_FILE_DIR) ===
|
||||
|
||||
Firmware configuration items stored at selector keys 0x0020 or higher
|
||||
(FW_CFG_FILE_FIRST or higher) have an associated entry in a directory
|
||||
structure, which makes it easier for guest-side firmware to identify
|
||||
and retrieve them. The format of this file directory (from fw_cfg.h in
|
||||
the QEMU source tree) is shown here, slightly annotated for clarity:
|
||||
|
||||
struct FWCfgFiles { /* the entire file directory fw_cfg item */
|
||||
uint32_t count; /* number of entries, in big-endian format */
|
||||
struct FWCfgFile f[]; /* array of file entries, see below */
|
||||
};
|
||||
|
||||
struct FWCfgFile { /* an individual file entry, 64 bytes total */
|
||||
uint32_t size; /* size of referenced fw_cfg item, big-endian */
|
||||
uint16_t select; /* selector key of fw_cfg item, big-endian */
|
||||
uint16_t reserved;
|
||||
char name[56]; /* fw_cfg item name, NUL-terminated ascii */
|
||||
};
|
||||
|
||||
=== All Other Data Items ===
|
||||
|
||||
Please consult the QEMU source for the most up-to-date and authoritative
|
||||
list of selector keys and their respective items' purpose and format.
|
||||
|
||||
=== Ranges ===
|
||||
|
||||
Theoretically, there may be up to 0x4000 generic firmware configuration
|
||||
items, and up to 0x4000 architecturally specific ones.
|
||||
|
||||
Selector Reg. Range Usage
|
||||
--------------- -----------
|
||||
0x0000 - 0x3fff Generic (0x0000 - 0x3fff, RO)
|
||||
0x4000 - 0x7fff Generic (0x0000 - 0x3fff, RW, ignored in QEMU v2.4+)
|
||||
0x8000 - 0xbfff Arch. Specific (0x0000 - 0x3fff, RO)
|
||||
0xc000 - 0xffff Arch. Specific (0x0000 - 0x3fff, RW, ignored in v2.4+)
|
||||
|
||||
In practice, the number of allowed firmware configuration items is given
|
||||
by the value of FW_CFG_MAX_ENTRY (see fw_cfg.h).
|
||||
|
||||
= Host-side API =
|
||||
|
||||
The following functions are available to the QEMU programmer for adding
|
||||
data to a fw_cfg device during guest initialization (see fw_cfg.h for
|
||||
each function's complete prototype):
|
||||
|
||||
== fw_cfg_add_bytes() ==
|
||||
|
||||
Given a selector key value, starting pointer, and size, create an item
|
||||
as a raw "blob" of the given size, available by selecting the given key.
|
||||
The data referenced by the starting pointer is only linked, NOT copied,
|
||||
into the data structure of the fw_cfg device.
|
||||
|
||||
== fw_cfg_add_string() ==
|
||||
|
||||
Instead of a starting pointer and size, this function accepts a pointer
|
||||
to a NUL-terminated ascii string, and inserts a newly allocated copy of
|
||||
the string (including the NUL terminator) into the fw_cfg device data
|
||||
structure.
|
||||
|
||||
== fw_cfg_add_iXX() ==
|
||||
|
||||
Insert an XX-bit item, where XX may be 16, 32, or 64. These functions
|
||||
will convert a 16-, 32-, or 64-bit integer to little-endian, then add
|
||||
a dynamically allocated copy of the appropriately sized item to fw_cfg
|
||||
under the given selector key value.
|
||||
|
||||
== fw_cfg_add_file() ==
|
||||
|
||||
Given a filename (i.e., fw_cfg item name), starting pointer, and size,
|
||||
create an item as a raw "blob" of the given size. Unlike fw_cfg_add_bytes()
|
||||
above, the next available selector key (above 0x0020, FW_CFG_FILE_FIRST)
|
||||
will be used, and a new entry will be added to the file directory structure
|
||||
(at key 0x0019), containing the item name, blob size, and automatically
|
||||
assigned selector key value. The data referenced by the starting pointer
|
||||
is only linked, NOT copied, into the fw_cfg data structure.
|
||||
|
||||
== fw_cfg_add_file_callback() ==
|
||||
|
||||
Like fw_cfg_add_file(), but additionally sets pointers to a callback
|
||||
function (and opaque argument), which will be executed host-side by
|
||||
QEMU each time a byte is read by the guest from this particular item.
|
||||
|
||||
NOTE: The callback function is given the opaque argument set by
|
||||
fw_cfg_add_file_callback(), but also the current data offset,
|
||||
allowing it the option of only acting upon specific offset values
|
||||
(e.g., 0, before the first data byte of the selected item is
|
||||
returned to the guest).
|
||||
|
||||
== fw_cfg_modify_file() ==
|
||||
|
||||
Given a filename (i.e., fw_cfg item name), starting pointer, and size,
|
||||
completely replace the configuration item referenced by the given item
|
||||
name with the new given blob. If an existing blob is found, its
|
||||
callback information is removed, and a pointer to the old data is
|
||||
returned to allow the caller to free it, helping avoid memory leaks.
|
||||
If a configuration item does not already exist under the given item
|
||||
name, a new item will be created as with fw_cfg_add_file(), and NULL
|
||||
is returned to the caller. In any case, the data referenced by the
|
||||
starting pointer is only linked, NOT copied, into the fw_cfg data
|
||||
structure.
|
||||
|
||||
== fw_cfg_add_callback() ==
|
||||
|
||||
Like fw_cfg_add_bytes(), but additionally sets pointers to a callback
|
||||
function (and opaque argument), which will be executed host-side by
|
||||
QEMU each time a guest-side write operation to this particular item
|
||||
completes fully overwriting the item's data.
|
||||
|
||||
NOTE: This function is deprecated, and will be completely removed
|
||||
starting with QEMU v2.4.
|
||||
@@ -391,7 +391,8 @@ static void print_block_info(Monitor *mon, BlockInfo *info,
|
||||
inserted->iops_size);
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
/* TODO: inserted->image should never be null */
|
||||
if (verbose && inserted->image) {
|
||||
monitor_printf(mon, "\nImages:\n");
|
||||
image_info = inserted->image;
|
||||
while (1) {
|
||||
@@ -1033,7 +1034,7 @@ void hmp_drive_mirror(Monitor *mon, const QDict *qdict)
|
||||
false, NULL, false, NULL,
|
||||
full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP,
|
||||
true, mode, false, 0, false, 0, false, 0,
|
||||
false, 0, false, 0, &err);
|
||||
false, 0, false, 0, false, true, &err);
|
||||
hmp_handle_error(mon, &err);
|
||||
}
|
||||
|
||||
|
||||
@@ -304,6 +304,7 @@ static void aml_free(gpointer data, gpointer user_data)
|
||||
{
|
||||
Aml *var = data;
|
||||
build_free_array(var->buf);
|
||||
g_free(var);
|
||||
}
|
||||
|
||||
Aml *init_aml_allocator(void)
|
||||
|
||||
+2
-3
@@ -844,9 +844,8 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus,
|
||||
|
||||
/* Main memory region, 0x00.0000.0000. Real hardware supports 32GB,
|
||||
but the address space hole reserved at this point is 8TB. */
|
||||
memory_region_init_ram(&s->ram_region, OBJECT(s), "ram", ram_size,
|
||||
&error_abort);
|
||||
vmstate_register_ram_global(&s->ram_region);
|
||||
memory_region_allocate_system_memory(&s->ram_region, OBJECT(s), "ram",
|
||||
ram_size);
|
||||
memory_region_add_subregion(addr_space, 0, &s->ram_region);
|
||||
|
||||
/* TIGbus, 0x801.0000.0000, 1GB. */
|
||||
|
||||
+2
-3
@@ -63,9 +63,8 @@ static void cubieboard_init(MachineState *machine)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memory_region_init_ram(&s->sdram, NULL, "cubieboard.ram",
|
||||
machine->ram_size, &error_abort);
|
||||
vmstate_register_ram_global(&s->sdram);
|
||||
memory_region_allocate_system_memory(&s->sdram, NULL, "cubieboard.ram",
|
||||
machine->ram_size);
|
||||
memory_region_add_subregion(get_system_memory(), AW_A10_SDRAM_BASE,
|
||||
&s->sdram);
|
||||
|
||||
|
||||
@@ -51,9 +51,8 @@ typedef struct DigicBoard {
|
||||
|
||||
static void digic4_board_setup_ram(DigicBoardState *s, hwaddr ram_size)
|
||||
{
|
||||
memory_region_init_ram(&s->ram, NULL, "ram", ram_size, &error_abort);
|
||||
memory_region_allocate_system_memory(&s->ram, NULL, "ram", ram_size);
|
||||
memory_region_add_subregion(get_system_memory(), 0, &s->ram);
|
||||
vmstate_register_ram_global(&s->ram);
|
||||
}
|
||||
|
||||
static void digic4_board_init(DigicBoard *board)
|
||||
|
||||
+1
-1
@@ -267,7 +267,7 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
|
||||
|
||||
sysmem = get_system_memory();
|
||||
dram = g_new(MemoryRegion, 1);
|
||||
memory_region_init_ram(dram, NULL, "highbank.dram", ram_size, &error_abort);
|
||||
memory_region_allocate_system_memory(dram, NULL, "highbank.dram", ram_size);
|
||||
/* SDRAM at address zero. */
|
||||
memory_region_add_subregion(sysmem, 0, dram);
|
||||
|
||||
|
||||
@@ -567,8 +567,8 @@ static void integratorcp_init(MachineState *machine)
|
||||
|
||||
cpu = ARM_CPU(cpuobj);
|
||||
|
||||
memory_region_init_ram(ram, NULL, "integrator.ram", ram_size, &error_abort);
|
||||
vmstate_register_ram_global(ram);
|
||||
memory_region_allocate_system_memory(ram, NULL, "integrator.ram",
|
||||
ram_size);
|
||||
/* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash. */
|
||||
/* ??? RAM should repeat to fill physical memory space. */
|
||||
/* SDRAM at address zero*/
|
||||
|
||||
+1
-2
@@ -97,8 +97,7 @@ static void kzm_init(MachineState *machine)
|
||||
|
||||
/* On a real system, the first 16k is a `secure boot rom' */
|
||||
|
||||
memory_region_init_ram(ram, NULL, "kzm.ram", ram_size, &error_abort);
|
||||
vmstate_register_ram_global(ram);
|
||||
memory_region_allocate_system_memory(ram, NULL, "kzm.ram", ram_size);
|
||||
memory_region_add_subregion(address_space_mem, KZM_RAMADDRESS, ram);
|
||||
|
||||
memory_region_init_alias(ram_alias, NULL, "ram.alias", ram, 0, ram_size);
|
||||
|
||||
+2
-3
@@ -1600,9 +1600,8 @@ static void musicpal_init(MachineState *machine)
|
||||
}
|
||||
|
||||
/* For now we use a fixed - the original - RAM size */
|
||||
memory_region_init_ram(ram, NULL, "musicpal.ram", MP_RAM_DEFAULT_SIZE,
|
||||
&error_abort);
|
||||
vmstate_register_ram_global(ram);
|
||||
memory_region_allocate_system_memory(ram, NULL, "musicpal.ram",
|
||||
MP_RAM_DEFAULT_SIZE);
|
||||
memory_region_add_subregion(address_space_mem, 0, ram);
|
||||
|
||||
memory_region_init_ram(sram, NULL, "musicpal.sram", MP_SRAM_SIZE,
|
||||
|
||||
+4
-3
@@ -16,6 +16,8 @@
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "hw/boards.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/arm/arm.h"
|
||||
#include "hw/arm/omap.h"
|
||||
@@ -3878,9 +3880,8 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
|
||||
omap_clk_init(s);
|
||||
|
||||
/* Memory-mapped stuff */
|
||||
memory_region_init_ram(&s->emiff_ram, NULL, "omap1.dram", s->sdram_size,
|
||||
&error_abort);
|
||||
vmstate_register_ram_global(&s->emiff_ram);
|
||||
memory_region_allocate_system_memory(&s->emiff_ram, NULL, "omap1.dram",
|
||||
s->sdram_size);
|
||||
memory_region_add_subregion(system_memory, OMAP_EMIFF_BASE, &s->emiff_ram);
|
||||
memory_region_init_ram(&s->imif_ram, NULL, "omap1.sram", s->sram_size,
|
||||
&error_abort);
|
||||
|
||||
+3
-3
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/arm/arm.h"
|
||||
#include "hw/arm/omap.h"
|
||||
@@ -2271,9 +2272,8 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem,
|
||||
omap_clk_init(s);
|
||||
|
||||
/* Memory-mapped stuff */
|
||||
memory_region_init_ram(&s->sdram, NULL, "omap2.dram", s->sdram_size,
|
||||
&error_abort);
|
||||
vmstate_register_ram_global(&s->sdram);
|
||||
memory_region_allocate_system_memory(&s->sdram, NULL, "omap2.dram",
|
||||
s->sdram_size);
|
||||
memory_region_add_subregion(sysmem, OMAP2_Q2_BASE, &s->sdram);
|
||||
memory_region_init_ram(&s->sram, NULL, "omap2.sram", s->sram_size,
|
||||
&error_abort);
|
||||
|
||||
+4
-3
@@ -26,6 +26,8 @@
|
||||
* Contributions after 2012-01-13 are licensed under the terms of the
|
||||
* GNU GPL, version 2 or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include "hw/boards.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "strongarm.h"
|
||||
#include "qemu/error-report.h"
|
||||
@@ -1604,9 +1606,8 @@ StrongARMState *sa1110_init(MemoryRegion *sysmem,
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memory_region_init_ram(&s->sdram, NULL, "strongarm.sdram", sdram_size,
|
||||
&error_abort);
|
||||
vmstate_register_ram_global(&s->sdram);
|
||||
memory_region_allocate_system_memory(&s->sdram, NULL, "strongarm.sdram",
|
||||
sdram_size);
|
||||
memory_region_add_subregion(sysmem, SA_SDCS0, &s->sdram);
|
||||
|
||||
s->pic = sysbus_create_varargs("strongarm_pic", 0x90050000,
|
||||
|
||||
@@ -226,9 +226,8 @@ static void versatile_init(MachineState *machine, int board_id)
|
||||
|
||||
cpu = ARM_CPU(cpuobj);
|
||||
|
||||
memory_region_init_ram(ram, NULL, "versatile.ram", machine->ram_size,
|
||||
&error_abort);
|
||||
vmstate_register_ram_global(ram);
|
||||
memory_region_allocate_system_memory(ram, NULL, "versatile.ram",
|
||||
machine->ram_size);
|
||||
/* ??? RAM should repeat to fill physical memory space. */
|
||||
/* SDRAM at address zero. */
|
||||
memory_region_add_subregion(sysmem, 0, ram);
|
||||
|
||||
+4
-6
@@ -276,9 +276,8 @@ static void a9_daughterboard_init(const VexpressMachineState *vms,
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memory_region_init_ram(ram, NULL, "vexpress.highmem", ram_size,
|
||||
&error_abort);
|
||||
vmstate_register_ram_global(ram);
|
||||
memory_region_allocate_system_memory(ram, NULL, "vexpress.highmem",
|
||||
ram_size);
|
||||
low_ram_size = ram_size;
|
||||
if (low_ram_size > 0x4000000) {
|
||||
low_ram_size = 0x4000000;
|
||||
@@ -371,9 +370,8 @@ static void a15_daughterboard_init(const VexpressMachineState *vms,
|
||||
}
|
||||
}
|
||||
|
||||
memory_region_init_ram(ram, NULL, "vexpress.highmem", ram_size,
|
||||
&error_abort);
|
||||
vmstate_register_ram_global(ram);
|
||||
memory_region_allocate_system_memory(ram, NULL, "vexpress.highmem",
|
||||
ram_size);
|
||||
/* RAM is from 0x80000000 upwards; there is no low-memory alias for it. */
|
||||
memory_region_add_subregion(sysmem, 0x80000000, ram);
|
||||
|
||||
|
||||
+2
-3
@@ -805,9 +805,8 @@ static void machvirt_init(MachineState *machine)
|
||||
fdt_add_cpu_nodes(vbi);
|
||||
fdt_add_psci_node(vbi);
|
||||
|
||||
memory_region_init_ram(ram, NULL, "mach-virt.ram", machine->ram_size,
|
||||
&error_abort);
|
||||
vmstate_register_ram_global(ram);
|
||||
memory_region_allocate_system_memory(ram, NULL, "mach-virt.ram",
|
||||
machine->ram_size);
|
||||
memory_region_add_subregion(sysmem, vbi->memmap[VIRT_MEM].base, ram);
|
||||
|
||||
create_flash(vbi);
|
||||
|
||||
@@ -161,9 +161,8 @@ static void zynq_init(MachineState *machine)
|
||||
}
|
||||
|
||||
/* DDR remapped to address zero. */
|
||||
memory_region_init_ram(ext_ram, NULL, "zynq.ext_ram", ram_size,
|
||||
&error_abort);
|
||||
vmstate_register_ram_global(ext_ram);
|
||||
memory_region_allocate_system_memory(ext_ram, NULL, "zynq.ext_ram",
|
||||
ram_size);
|
||||
memory_region_add_subregion(address_space_mem, 0, ext_ram);
|
||||
|
||||
/* 256K of on-chip memory */
|
||||
|
||||
+1
-1
@@ -167,7 +167,7 @@ static void pcspk_initfn(Object *obj)
|
||||
{
|
||||
PCSpkState *s = PC_SPEAKER(obj);
|
||||
|
||||
memory_region_init_io(&s->ioport, OBJECT(s), &pcspk_io_ops, s, "elcr", 1);
|
||||
memory_region_init_io(&s->ioport, OBJECT(s), &pcspk_io_ops, s, "pcspk", 1);
|
||||
}
|
||||
|
||||
static void pcspk_realizefn(DeviceState *dev, Error **errp)
|
||||
|
||||
@@ -77,8 +77,7 @@ static void complete_request_vring(VirtIOBlockReq *req, unsigned char status)
|
||||
VirtIOBlockDataPlane *s = req->dev->dataplane;
|
||||
stb_p(&req->in->status, status);
|
||||
|
||||
vring_push(s->vdev, &req->dev->dataplane->vring, &req->elem,
|
||||
req->qiov.size + sizeof(*req->in));
|
||||
vring_push(s->vdev, &req->dev->dataplane->vring, &req->elem, req->in_len);
|
||||
|
||||
/* Suppress notification to guest by BH and its scheduled
|
||||
* flag because requests are completed as a batch after io
|
||||
|
||||
+11
-6
@@ -1512,7 +1512,7 @@ static uint32_t fdctrl_read_data(FDCtrl *fdctrl)
|
||||
{
|
||||
FDrive *cur_drv;
|
||||
uint32_t retval = 0;
|
||||
int pos;
|
||||
uint32_t pos;
|
||||
|
||||
cur_drv = get_cur_drv(fdctrl);
|
||||
fdctrl->dsr &= ~FD_DSR_PWRDOWN;
|
||||
@@ -1521,8 +1521,8 @@ static uint32_t fdctrl_read_data(FDCtrl *fdctrl)
|
||||
return 0;
|
||||
}
|
||||
pos = fdctrl->data_pos;
|
||||
pos %= FD_SECTOR_LEN;
|
||||
if (fdctrl->msr & FD_MSR_NONDMA) {
|
||||
pos %= FD_SECTOR_LEN;
|
||||
if (pos == 0) {
|
||||
if (fdctrl->data_pos != 0)
|
||||
if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv)) {
|
||||
@@ -1867,10 +1867,13 @@ static void fdctrl_handle_option(FDCtrl *fdctrl, int direction)
|
||||
static void fdctrl_handle_drive_specification_command(FDCtrl *fdctrl, int direction)
|
||||
{
|
||||
FDrive *cur_drv = get_cur_drv(fdctrl);
|
||||
uint32_t pos;
|
||||
|
||||
if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x80) {
|
||||
pos = fdctrl->data_pos - 1;
|
||||
pos %= FD_SECTOR_LEN;
|
||||
if (fdctrl->fifo[pos] & 0x80) {
|
||||
/* Command parameters done */
|
||||
if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x40) {
|
||||
if (fdctrl->fifo[pos] & 0x40) {
|
||||
fdctrl->fifo[0] = fdctrl->fifo[1];
|
||||
fdctrl->fifo[2] = 0;
|
||||
fdctrl->fifo[3] = 0;
|
||||
@@ -1970,7 +1973,7 @@ static uint8_t command_to_handler[256];
|
||||
static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value)
|
||||
{
|
||||
FDrive *cur_drv;
|
||||
int pos;
|
||||
uint32_t pos;
|
||||
|
||||
/* Reset mode */
|
||||
if (!(fdctrl->dor & FD_DOR_nRESET)) {
|
||||
@@ -2019,7 +2022,9 @@ static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value)
|
||||
}
|
||||
|
||||
FLOPPY_DPRINTF("%s: %02x\n", __func__, value);
|
||||
fdctrl->fifo[fdctrl->data_pos++] = value;
|
||||
pos = fdctrl->data_pos++;
|
||||
pos %= FD_SECTOR_LEN;
|
||||
fdctrl->fifo[pos] = value;
|
||||
if (fdctrl->data_pos == fdctrl->data_len) {
|
||||
/* We now have all parameters
|
||||
* and will be able to treat the command
|
||||
|
||||
+12
-1
@@ -33,6 +33,7 @@ VirtIOBlockReq *virtio_blk_alloc_request(VirtIOBlock *s)
|
||||
VirtIOBlockReq *req = g_slice_new(VirtIOBlockReq);
|
||||
req->dev = s;
|
||||
req->qiov.size = 0;
|
||||
req->in_len = 0;
|
||||
req->next = NULL;
|
||||
req->mr_next = NULL;
|
||||
return req;
|
||||
@@ -54,7 +55,7 @@ static void virtio_blk_complete_request(VirtIOBlockReq *req,
|
||||
trace_virtio_blk_req_complete(req, status);
|
||||
|
||||
stb_p(&req->in->status, status);
|
||||
virtqueue_push(s->vq, &req->elem, req->qiov.size + sizeof(*req->in));
|
||||
virtqueue_push(s->vq, &req->elem, req->in_len);
|
||||
virtio_notify(vdev, s->vq);
|
||||
}
|
||||
|
||||
@@ -102,6 +103,14 @@ static void virtio_blk_rw_complete(void *opaque, int ret)
|
||||
if (ret) {
|
||||
int p = virtio_ldl_p(VIRTIO_DEVICE(req->dev), &req->out.type);
|
||||
bool is_read = !(p & VIRTIO_BLK_T_OUT);
|
||||
/* Note that memory may be dirtied on read failure. If the
|
||||
* virtio request is not completed here, as is the case for
|
||||
* BLOCK_ERROR_ACTION_STOP, the memory may not be copied
|
||||
* correctly during live migration. While this is ugly,
|
||||
* it is acceptable because the device is free to write to
|
||||
* the memory until the request is completed (which will
|
||||
* happen on the other side of the migration).
|
||||
*/
|
||||
if (virtio_blk_handle_rw_error(req, -ret, is_read)) {
|
||||
continue;
|
||||
}
|
||||
@@ -496,6 +505,8 @@ void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* We always touch the last byte, so just see how big in_iov is. */
|
||||
req->in_len = iov_size(in_iov, in_num);
|
||||
req->in = (void *)in_iov[in_num - 1].iov_base
|
||||
+ in_iov[in_num - 1].iov_len
|
||||
- sizeof(struct virtio_blk_inhdr);
|
||||
|
||||
+1
-1
@@ -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 =
|
||||
|
||||
@@ -228,6 +228,10 @@ VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg)
|
||||
return spapr_vty_get_default(spapr->vio_bus);
|
||||
}
|
||||
|
||||
if (!object_dynamic_cast(OBJECT(sdev), TYPE_VIO_SPAPR_VTY_DEVICE)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return sdev;
|
||||
}
|
||||
|
||||
|
||||
+6
-10
@@ -281,19 +281,15 @@ static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent)
|
||||
static char *sysbus_get_fw_dev_path(DeviceState *dev)
|
||||
{
|
||||
SysBusDevice *s = SYS_BUS_DEVICE(dev);
|
||||
char path[40];
|
||||
int off;
|
||||
|
||||
off = snprintf(path, sizeof(path), "%s", qdev_fw_name(dev));
|
||||
|
||||
if (s->num_mmio) {
|
||||
snprintf(path + off, sizeof(path) - off, "@"TARGET_FMT_plx,
|
||||
s->mmio[0].addr);
|
||||
} else if (s->num_pio) {
|
||||
snprintf(path + off, sizeof(path) - off, "@i%04x", s->pio[0]);
|
||||
return g_strdup_printf("%s@" TARGET_FMT_plx, qdev_fw_name(dev),
|
||||
s->mmio[0].addr);
|
||||
}
|
||||
|
||||
return g_strdup(path);
|
||||
if (s->num_pio) {
|
||||
return g_strdup_printf("%s@i%04x", qdev_fw_name(dev), s->pio[0]);
|
||||
}
|
||||
return g_strdup(qdev_fw_name(dev));
|
||||
}
|
||||
|
||||
void sysbus_add_io(SysBusDevice *dev, hwaddr addr,
|
||||
|
||||
@@ -270,9 +270,8 @@ void axisdev88_init(MachineState *machine)
|
||||
env = &cpu->env;
|
||||
|
||||
/* allocate RAM */
|
||||
memory_region_init_ram(phys_ram, NULL, "axisdev88.ram", ram_size,
|
||||
&error_abort);
|
||||
vmstate_register_ram_global(phys_ram);
|
||||
memory_region_allocate_system_memory(phys_ram, NULL, "axisdev88.ram",
|
||||
ram_size);
|
||||
memory_region_add_subregion(address_space_mem, 0x40000000, phys_ram);
|
||||
|
||||
/* The ETRAX-FS has 128Kb on chip ram, the docs refer to it as the
|
||||
|
||||
@@ -983,6 +983,7 @@ static void cmd_start_stop_unit(IDEState *s, uint8_t* buf)
|
||||
|
||||
if (pwrcnd) {
|
||||
/* eject/load only happens for power condition == 0 */
|
||||
ide_atapi_cmd_ok(s);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+28
-4
@@ -2021,11 +2021,17 @@ void ide_data_writew(void *opaque, uint32_t addr, uint32_t val)
|
||||
}
|
||||
|
||||
p = s->data_ptr;
|
||||
if (p + 2 > s->data_end) {
|
||||
return;
|
||||
}
|
||||
|
||||
*(uint16_t *)p = le16_to_cpu(val);
|
||||
p += 2;
|
||||
s->data_ptr = p;
|
||||
if (p >= s->data_end)
|
||||
if (p >= s->data_end) {
|
||||
s->status &= ~DRQ_STAT;
|
||||
s->end_transfer_func(s);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ide_data_readw(void *opaque, uint32_t addr)
|
||||
@@ -2042,11 +2048,17 @@ uint32_t ide_data_readw(void *opaque, uint32_t addr)
|
||||
}
|
||||
|
||||
p = s->data_ptr;
|
||||
if (p + 2 > s->data_end) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = cpu_to_le16(*(uint16_t *)p);
|
||||
p += 2;
|
||||
s->data_ptr = p;
|
||||
if (p >= s->data_end)
|
||||
if (p >= s->data_end) {
|
||||
s->status &= ~DRQ_STAT;
|
||||
s->end_transfer_func(s);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2063,11 +2075,17 @@ void ide_data_writel(void *opaque, uint32_t addr, uint32_t val)
|
||||
}
|
||||
|
||||
p = s->data_ptr;
|
||||
if (p + 4 > s->data_end) {
|
||||
return;
|
||||
}
|
||||
|
||||
*(uint32_t *)p = le32_to_cpu(val);
|
||||
p += 4;
|
||||
s->data_ptr = p;
|
||||
if (p >= s->data_end)
|
||||
if (p >= s->data_end) {
|
||||
s->status &= ~DRQ_STAT;
|
||||
s->end_transfer_func(s);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ide_data_readl(void *opaque, uint32_t addr)
|
||||
@@ -2084,11 +2102,17 @@ uint32_t ide_data_readl(void *opaque, uint32_t addr)
|
||||
}
|
||||
|
||||
p = s->data_ptr;
|
||||
if (p + 4 > s->data_end) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = cpu_to_le32(*(uint32_t *)p);
|
||||
p += 4;
|
||||
s->data_ptr = p;
|
||||
if (p >= s->data_end)
|
||||
if (p >= s->data_end) {
|
||||
s->status &= ~DRQ_STAT;
|
||||
s->end_transfer_func(s);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -169,6 +169,7 @@ int pci_piix3_xen_ide_unplug(DeviceState *dev)
|
||||
PCIIDEState *pci_ide;
|
||||
DriveInfo *di;
|
||||
int i;
|
||||
IDEDevice *idedev;
|
||||
|
||||
pci_ide = PCI_IDE(dev);
|
||||
|
||||
@@ -181,6 +182,12 @@ int pci_piix3_xen_ide_unplug(DeviceState *dev)
|
||||
blk_detach_dev(blk, ds);
|
||||
}
|
||||
pci_ide->bus[di->bus].ifs[di->unit].blk = NULL;
|
||||
if (!(i % 2)) {
|
||||
idedev = pci_ide->bus[di->bus].master;
|
||||
} else {
|
||||
idedev = pci_ide->bus[di->bus].slave;
|
||||
}
|
||||
idedev->conf.blk = NULL;
|
||||
blk_unref(blk);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,9 +111,8 @@ static void lm32_evr_init(MachineState *machine)
|
||||
|
||||
reset_info->flash_base = flash_base;
|
||||
|
||||
memory_region_init_ram(phys_ram, NULL, "lm32_evr.sdram", ram_size,
|
||||
&error_abort);
|
||||
vmstate_register_ram_global(phys_ram);
|
||||
memory_region_allocate_system_memory(phys_ram, NULL, "lm32_evr.sdram",
|
||||
ram_size);
|
||||
memory_region_add_subregion(address_space_mem, ram_base, phys_ram);
|
||||
|
||||
dinfo = drive_get(IF_PFLASH, 0, 0);
|
||||
@@ -214,9 +213,8 @@ static void lm32_uclinux_init(MachineState *machine)
|
||||
|
||||
reset_info->flash_base = flash_base;
|
||||
|
||||
memory_region_init_ram(phys_ram, NULL, "lm32_uclinux.sdram", ram_size,
|
||||
&error_abort);
|
||||
vmstate_register_ram_global(phys_ram);
|
||||
memory_region_allocate_system_memory(phys_ram, NULL,
|
||||
"lm32_uclinux.sdram", ram_size);
|
||||
memory_region_add_subregion(address_space_mem, ram_base, phys_ram);
|
||||
|
||||
dinfo = drive_get(IF_PFLASH, 0, 0);
|
||||
|
||||
+2
-3
@@ -118,9 +118,8 @@ milkymist_init(MachineState *machine)
|
||||
|
||||
cpu_lm32_set_phys_msb_ignore(env, 1);
|
||||
|
||||
memory_region_init_ram(phys_sdram, NULL, "milkymist.sdram", sdram_size,
|
||||
&error_abort);
|
||||
vmstate_register_ram_global(phys_sdram);
|
||||
memory_region_allocate_system_memory(phys_sdram, NULL, "milkymist.sdram",
|
||||
sdram_size);
|
||||
memory_region_add_subregion(address_space_mem, sdram_base, phys_sdram);
|
||||
|
||||
dinfo = drive_get(IF_PFLASH, 0, 0);
|
||||
|
||||
+206
-189
@@ -2150,6 +2150,11 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
|
||||
{
|
||||
DPRINTF("+++ C+ mode offloaded task checksum\n");
|
||||
|
||||
/* Large enough for Ethernet and IP headers? */
|
||||
if (saved_size < ETH_HLEN + sizeof(ip_header)) {
|
||||
goto skip_offload;
|
||||
}
|
||||
|
||||
/* ip packet header */
|
||||
ip_header *ip = NULL;
|
||||
int hlen = 0;
|
||||
@@ -2160,223 +2165,235 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
|
||||
size_t eth_payload_len = 0;
|
||||
|
||||
int proto = be16_to_cpu(*(uint16_t *)(saved_buffer + 12));
|
||||
if (proto == ETH_P_IP)
|
||||
if (proto != ETH_P_IP)
|
||||
{
|
||||
DPRINTF("+++ C+ mode has IP packet\n");
|
||||
|
||||
/* not aligned */
|
||||
eth_payload_data = saved_buffer + ETH_HLEN;
|
||||
eth_payload_len = saved_size - ETH_HLEN;
|
||||
|
||||
ip = (ip_header*)eth_payload_data;
|
||||
|
||||
if (IP_HEADER_VERSION(ip) != IP_HEADER_VERSION_4) {
|
||||
DPRINTF("+++ C+ mode packet has bad IP version %d "
|
||||
"expected %d\n", IP_HEADER_VERSION(ip),
|
||||
IP_HEADER_VERSION_4);
|
||||
ip = NULL;
|
||||
} else {
|
||||
hlen = IP_HEADER_LENGTH(ip);
|
||||
ip_protocol = ip->ip_p;
|
||||
ip_data_len = be16_to_cpu(ip->ip_len) - hlen;
|
||||
}
|
||||
goto skip_offload;
|
||||
}
|
||||
|
||||
if (ip)
|
||||
DPRINTF("+++ C+ mode has IP packet\n");
|
||||
|
||||
/* not aligned */
|
||||
eth_payload_data = saved_buffer + ETH_HLEN;
|
||||
eth_payload_len = saved_size - ETH_HLEN;
|
||||
|
||||
ip = (ip_header*)eth_payload_data;
|
||||
|
||||
if (IP_HEADER_VERSION(ip) != IP_HEADER_VERSION_4) {
|
||||
DPRINTF("+++ C+ mode packet has bad IP version %d "
|
||||
"expected %d\n", IP_HEADER_VERSION(ip),
|
||||
IP_HEADER_VERSION_4);
|
||||
goto skip_offload;
|
||||
}
|
||||
|
||||
hlen = IP_HEADER_LENGTH(ip);
|
||||
if (hlen < sizeof(ip_header) || hlen > eth_payload_len) {
|
||||
goto skip_offload;
|
||||
}
|
||||
|
||||
ip_protocol = ip->ip_p;
|
||||
|
||||
ip_data_len = be16_to_cpu(ip->ip_len);
|
||||
if (ip_data_len < hlen || ip_data_len > eth_payload_len) {
|
||||
goto skip_offload;
|
||||
}
|
||||
ip_data_len -= hlen;
|
||||
|
||||
if (txdw0 & CP_TX_IPCS)
|
||||
{
|
||||
if (txdw0 & CP_TX_IPCS)
|
||||
{
|
||||
DPRINTF("+++ C+ mode need IP checksum\n");
|
||||
DPRINTF("+++ C+ mode need IP checksum\n");
|
||||
|
||||
if (hlen<sizeof(ip_header) || hlen>eth_payload_len) {/* min header length */
|
||||
/* bad packet header len */
|
||||
/* or packet too short */
|
||||
}
|
||||
else
|
||||
{
|
||||
ip->ip_sum = 0;
|
||||
ip->ip_sum = ip_checksum(ip, hlen);
|
||||
DPRINTF("+++ C+ mode IP header len=%d checksum=%04x\n",
|
||||
hlen, ip->ip_sum);
|
||||
}
|
||||
ip->ip_sum = 0;
|
||||
ip->ip_sum = ip_checksum(ip, hlen);
|
||||
DPRINTF("+++ C+ mode IP header len=%d checksum=%04x\n",
|
||||
hlen, ip->ip_sum);
|
||||
}
|
||||
|
||||
if ((txdw0 & CP_TX_LGSEN) && ip_protocol == IP_PROTO_TCP)
|
||||
{
|
||||
/* Large enough for the TCP header? */
|
||||
if (ip_data_len < sizeof(tcp_header)) {
|
||||
goto skip_offload;
|
||||
}
|
||||
|
||||
if ((txdw0 & CP_TX_LGSEN) && ip_protocol == IP_PROTO_TCP)
|
||||
int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK;
|
||||
|
||||
DPRINTF("+++ C+ mode offloaded task TSO MTU=%d IP data %d "
|
||||
"frame data %d specified MSS=%d\n", ETH_MTU,
|
||||
ip_data_len, saved_size - ETH_HLEN, large_send_mss);
|
||||
|
||||
int tcp_send_offset = 0;
|
||||
int send_count = 0;
|
||||
|
||||
/* maximum IP header length is 60 bytes */
|
||||
uint8_t saved_ip_header[60];
|
||||
|
||||
/* save IP header template; data area is used in tcp checksum calculation */
|
||||
memcpy(saved_ip_header, eth_payload_data, hlen);
|
||||
|
||||
/* a placeholder for checksum calculation routine in tcp case */
|
||||
uint8_t *data_to_checksum = eth_payload_data + hlen - 12;
|
||||
// size_t data_to_checksum_len = eth_payload_len - hlen + 12;
|
||||
|
||||
/* pointer to TCP header */
|
||||
tcp_header *p_tcp_hdr = (tcp_header*)(eth_payload_data + hlen);
|
||||
|
||||
int tcp_hlen = TCP_HEADER_DATA_OFFSET(p_tcp_hdr);
|
||||
|
||||
/* Invalid TCP data offset? */
|
||||
if (tcp_hlen < sizeof(tcp_header) || tcp_hlen > ip_data_len) {
|
||||
goto skip_offload;
|
||||
}
|
||||
|
||||
/* ETH_MTU = ip header len + tcp header len + payload */
|
||||
int tcp_data_len = ip_data_len - tcp_hlen;
|
||||
int tcp_chunk_size = ETH_MTU - hlen - tcp_hlen;
|
||||
|
||||
DPRINTF("+++ C+ mode TSO IP data len %d TCP hlen %d TCP "
|
||||
"data len %d TCP chunk size %d\n", ip_data_len,
|
||||
tcp_hlen, tcp_data_len, tcp_chunk_size);
|
||||
|
||||
/* note the cycle below overwrites IP header data,
|
||||
but restores it from saved_ip_header before sending packet */
|
||||
|
||||
int is_last_frame = 0;
|
||||
|
||||
for (tcp_send_offset = 0; tcp_send_offset < tcp_data_len; tcp_send_offset += tcp_chunk_size)
|
||||
{
|
||||
int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK;
|
||||
uint16_t chunk_size = tcp_chunk_size;
|
||||
|
||||
DPRINTF("+++ C+ mode offloaded task TSO MTU=%d IP data %d "
|
||||
"frame data %d specified MSS=%d\n", ETH_MTU,
|
||||
ip_data_len, saved_size - ETH_HLEN, large_send_mss);
|
||||
|
||||
int tcp_send_offset = 0;
|
||||
int send_count = 0;
|
||||
|
||||
/* maximum IP header length is 60 bytes */
|
||||
uint8_t saved_ip_header[60];
|
||||
|
||||
/* save IP header template; data area is used in tcp checksum calculation */
|
||||
memcpy(saved_ip_header, eth_payload_data, hlen);
|
||||
|
||||
/* a placeholder for checksum calculation routine in tcp case */
|
||||
uint8_t *data_to_checksum = eth_payload_data + hlen - 12;
|
||||
// size_t data_to_checksum_len = eth_payload_len - hlen + 12;
|
||||
|
||||
/* pointer to TCP header */
|
||||
tcp_header *p_tcp_hdr = (tcp_header*)(eth_payload_data + hlen);
|
||||
|
||||
int tcp_hlen = TCP_HEADER_DATA_OFFSET(p_tcp_hdr);
|
||||
|
||||
/* ETH_MTU = ip header len + tcp header len + payload */
|
||||
int tcp_data_len = ip_data_len - tcp_hlen;
|
||||
int tcp_chunk_size = ETH_MTU - hlen - tcp_hlen;
|
||||
|
||||
DPRINTF("+++ C+ mode TSO IP data len %d TCP hlen %d TCP "
|
||||
"data len %d TCP chunk size %d\n", ip_data_len,
|
||||
tcp_hlen, tcp_data_len, tcp_chunk_size);
|
||||
|
||||
/* note the cycle below overwrites IP header data,
|
||||
but restores it from saved_ip_header before sending packet */
|
||||
|
||||
int is_last_frame = 0;
|
||||
|
||||
for (tcp_send_offset = 0; tcp_send_offset < tcp_data_len; tcp_send_offset += tcp_chunk_size)
|
||||
/* check if this is the last frame */
|
||||
if (tcp_send_offset + tcp_chunk_size >= tcp_data_len)
|
||||
{
|
||||
uint16_t chunk_size = tcp_chunk_size;
|
||||
|
||||
/* check if this is the last frame */
|
||||
if (tcp_send_offset + tcp_chunk_size >= tcp_data_len)
|
||||
{
|
||||
is_last_frame = 1;
|
||||
chunk_size = tcp_data_len - tcp_send_offset;
|
||||
}
|
||||
|
||||
DPRINTF("+++ C+ mode TSO TCP seqno %08x\n",
|
||||
be32_to_cpu(p_tcp_hdr->th_seq));
|
||||
|
||||
/* add 4 TCP pseudoheader fields */
|
||||
/* copy IP source and destination fields */
|
||||
memcpy(data_to_checksum, saved_ip_header + 12, 8);
|
||||
|
||||
DPRINTF("+++ C+ mode TSO calculating TCP checksum for "
|
||||
"packet with %d bytes data\n", tcp_hlen +
|
||||
chunk_size);
|
||||
|
||||
if (tcp_send_offset)
|
||||
{
|
||||
memcpy((uint8_t*)p_tcp_hdr + tcp_hlen, (uint8_t*)p_tcp_hdr + tcp_hlen + tcp_send_offset, chunk_size);
|
||||
}
|
||||
|
||||
/* keep PUSH and FIN flags only for the last frame */
|
||||
if (!is_last_frame)
|
||||
{
|
||||
TCP_HEADER_CLEAR_FLAGS(p_tcp_hdr, TCP_FLAG_PUSH|TCP_FLAG_FIN);
|
||||
}
|
||||
|
||||
/* recalculate TCP checksum */
|
||||
ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum;
|
||||
p_tcpip_hdr->zeros = 0;
|
||||
p_tcpip_hdr->ip_proto = IP_PROTO_TCP;
|
||||
p_tcpip_hdr->ip_payload = cpu_to_be16(tcp_hlen + chunk_size);
|
||||
|
||||
p_tcp_hdr->th_sum = 0;
|
||||
|
||||
int tcp_checksum = ip_checksum(data_to_checksum, tcp_hlen + chunk_size + 12);
|
||||
DPRINTF("+++ C+ mode TSO TCP checksum %04x\n",
|
||||
tcp_checksum);
|
||||
|
||||
p_tcp_hdr->th_sum = tcp_checksum;
|
||||
|
||||
/* restore IP header */
|
||||
memcpy(eth_payload_data, saved_ip_header, hlen);
|
||||
|
||||
/* set IP data length and recalculate IP checksum */
|
||||
ip->ip_len = cpu_to_be16(hlen + tcp_hlen + chunk_size);
|
||||
|
||||
/* increment IP id for subsequent frames */
|
||||
ip->ip_id = cpu_to_be16(tcp_send_offset/tcp_chunk_size + be16_to_cpu(ip->ip_id));
|
||||
|
||||
ip->ip_sum = 0;
|
||||
ip->ip_sum = ip_checksum(eth_payload_data, hlen);
|
||||
DPRINTF("+++ C+ mode TSO IP header len=%d "
|
||||
"checksum=%04x\n", hlen, ip->ip_sum);
|
||||
|
||||
int tso_send_size = ETH_HLEN + hlen + tcp_hlen + chunk_size;
|
||||
DPRINTF("+++ C+ mode TSO transferring packet size "
|
||||
"%d\n", tso_send_size);
|
||||
rtl8139_transfer_frame(s, saved_buffer, tso_send_size,
|
||||
0, (uint8_t *) dot1q_buffer);
|
||||
|
||||
/* add transferred count to TCP sequence number */
|
||||
p_tcp_hdr->th_seq = cpu_to_be32(chunk_size + be32_to_cpu(p_tcp_hdr->th_seq));
|
||||
++send_count;
|
||||
is_last_frame = 1;
|
||||
chunk_size = tcp_data_len - tcp_send_offset;
|
||||
}
|
||||
|
||||
/* Stop sending this frame */
|
||||
saved_size = 0;
|
||||
}
|
||||
else if (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS))
|
||||
{
|
||||
DPRINTF("+++ C+ mode need TCP or UDP checksum\n");
|
||||
|
||||
/* maximum IP header length is 60 bytes */
|
||||
uint8_t saved_ip_header[60];
|
||||
memcpy(saved_ip_header, eth_payload_data, hlen);
|
||||
|
||||
uint8_t *data_to_checksum = eth_payload_data + hlen - 12;
|
||||
// size_t data_to_checksum_len = eth_payload_len - hlen + 12;
|
||||
DPRINTF("+++ C+ mode TSO TCP seqno %08x\n",
|
||||
be32_to_cpu(p_tcp_hdr->th_seq));
|
||||
|
||||
/* add 4 TCP pseudoheader fields */
|
||||
/* copy IP source and destination fields */
|
||||
memcpy(data_to_checksum, saved_ip_header + 12, 8);
|
||||
|
||||
if ((txdw0 & CP_TX_TCPCS) && ip_protocol == IP_PROTO_TCP)
|
||||
DPRINTF("+++ C+ mode TSO calculating TCP checksum for "
|
||||
"packet with %d bytes data\n", tcp_hlen +
|
||||
chunk_size);
|
||||
|
||||
if (tcp_send_offset)
|
||||
{
|
||||
DPRINTF("+++ C+ mode calculating TCP checksum for "
|
||||
"packet with %d bytes data\n", ip_data_len);
|
||||
|
||||
ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum;
|
||||
p_tcpip_hdr->zeros = 0;
|
||||
p_tcpip_hdr->ip_proto = IP_PROTO_TCP;
|
||||
p_tcpip_hdr->ip_payload = cpu_to_be16(ip_data_len);
|
||||
|
||||
tcp_header* p_tcp_hdr = (tcp_header *) (data_to_checksum+12);
|
||||
|
||||
p_tcp_hdr->th_sum = 0;
|
||||
|
||||
int tcp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12);
|
||||
DPRINTF("+++ C+ mode TCP checksum %04x\n",
|
||||
tcp_checksum);
|
||||
|
||||
p_tcp_hdr->th_sum = tcp_checksum;
|
||||
memcpy((uint8_t*)p_tcp_hdr + tcp_hlen, (uint8_t*)p_tcp_hdr + tcp_hlen + tcp_send_offset, chunk_size);
|
||||
}
|
||||
else if ((txdw0 & CP_TX_UDPCS) && ip_protocol == IP_PROTO_UDP)
|
||||
|
||||
/* keep PUSH and FIN flags only for the last frame */
|
||||
if (!is_last_frame)
|
||||
{
|
||||
DPRINTF("+++ C+ mode calculating UDP checksum for "
|
||||
"packet with %d bytes data\n", ip_data_len);
|
||||
|
||||
ip_pseudo_header *p_udpip_hdr = (ip_pseudo_header *)data_to_checksum;
|
||||
p_udpip_hdr->zeros = 0;
|
||||
p_udpip_hdr->ip_proto = IP_PROTO_UDP;
|
||||
p_udpip_hdr->ip_payload = cpu_to_be16(ip_data_len);
|
||||
|
||||
udp_header *p_udp_hdr = (udp_header *) (data_to_checksum+12);
|
||||
|
||||
p_udp_hdr->uh_sum = 0;
|
||||
|
||||
int udp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12);
|
||||
DPRINTF("+++ C+ mode UDP checksum %04x\n",
|
||||
udp_checksum);
|
||||
|
||||
p_udp_hdr->uh_sum = udp_checksum;
|
||||
TCP_HEADER_CLEAR_FLAGS(p_tcp_hdr, TCP_FLAG_PUSH|TCP_FLAG_FIN);
|
||||
}
|
||||
|
||||
/* recalculate TCP checksum */
|
||||
ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum;
|
||||
p_tcpip_hdr->zeros = 0;
|
||||
p_tcpip_hdr->ip_proto = IP_PROTO_TCP;
|
||||
p_tcpip_hdr->ip_payload = cpu_to_be16(tcp_hlen + chunk_size);
|
||||
|
||||
p_tcp_hdr->th_sum = 0;
|
||||
|
||||
int tcp_checksum = ip_checksum(data_to_checksum, tcp_hlen + chunk_size + 12);
|
||||
DPRINTF("+++ C+ mode TSO TCP checksum %04x\n",
|
||||
tcp_checksum);
|
||||
|
||||
p_tcp_hdr->th_sum = tcp_checksum;
|
||||
|
||||
/* restore IP header */
|
||||
memcpy(eth_payload_data, saved_ip_header, hlen);
|
||||
|
||||
/* set IP data length and recalculate IP checksum */
|
||||
ip->ip_len = cpu_to_be16(hlen + tcp_hlen + chunk_size);
|
||||
|
||||
/* increment IP id for subsequent frames */
|
||||
ip->ip_id = cpu_to_be16(tcp_send_offset/tcp_chunk_size + be16_to_cpu(ip->ip_id));
|
||||
|
||||
ip->ip_sum = 0;
|
||||
ip->ip_sum = ip_checksum(eth_payload_data, hlen);
|
||||
DPRINTF("+++ C+ mode TSO IP header len=%d "
|
||||
"checksum=%04x\n", hlen, ip->ip_sum);
|
||||
|
||||
int tso_send_size = ETH_HLEN + hlen + tcp_hlen + chunk_size;
|
||||
DPRINTF("+++ C+ mode TSO transferring packet size "
|
||||
"%d\n", tso_send_size);
|
||||
rtl8139_transfer_frame(s, saved_buffer, tso_send_size,
|
||||
0, (uint8_t *) dot1q_buffer);
|
||||
|
||||
/* add transferred count to TCP sequence number */
|
||||
p_tcp_hdr->th_seq = cpu_to_be32(chunk_size + be32_to_cpu(p_tcp_hdr->th_seq));
|
||||
++send_count;
|
||||
}
|
||||
|
||||
/* Stop sending this frame */
|
||||
saved_size = 0;
|
||||
}
|
||||
else if (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS))
|
||||
{
|
||||
DPRINTF("+++ C+ mode need TCP or UDP checksum\n");
|
||||
|
||||
/* maximum IP header length is 60 bytes */
|
||||
uint8_t saved_ip_header[60];
|
||||
memcpy(saved_ip_header, eth_payload_data, hlen);
|
||||
|
||||
uint8_t *data_to_checksum = eth_payload_data + hlen - 12;
|
||||
// size_t data_to_checksum_len = eth_payload_len - hlen + 12;
|
||||
|
||||
/* add 4 TCP pseudoheader fields */
|
||||
/* copy IP source and destination fields */
|
||||
memcpy(data_to_checksum, saved_ip_header + 12, 8);
|
||||
|
||||
if ((txdw0 & CP_TX_TCPCS) && ip_protocol == IP_PROTO_TCP)
|
||||
{
|
||||
DPRINTF("+++ C+ mode calculating TCP checksum for "
|
||||
"packet with %d bytes data\n", ip_data_len);
|
||||
|
||||
ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum;
|
||||
p_tcpip_hdr->zeros = 0;
|
||||
p_tcpip_hdr->ip_proto = IP_PROTO_TCP;
|
||||
p_tcpip_hdr->ip_payload = cpu_to_be16(ip_data_len);
|
||||
|
||||
tcp_header* p_tcp_hdr = (tcp_header *) (data_to_checksum+12);
|
||||
|
||||
p_tcp_hdr->th_sum = 0;
|
||||
|
||||
int tcp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12);
|
||||
DPRINTF("+++ C+ mode TCP checksum %04x\n",
|
||||
tcp_checksum);
|
||||
|
||||
p_tcp_hdr->th_sum = tcp_checksum;
|
||||
}
|
||||
else if ((txdw0 & CP_TX_UDPCS) && ip_protocol == IP_PROTO_UDP)
|
||||
{
|
||||
DPRINTF("+++ C+ mode calculating UDP checksum for "
|
||||
"packet with %d bytes data\n", ip_data_len);
|
||||
|
||||
ip_pseudo_header *p_udpip_hdr = (ip_pseudo_header *)data_to_checksum;
|
||||
p_udpip_hdr->zeros = 0;
|
||||
p_udpip_hdr->ip_proto = IP_PROTO_UDP;
|
||||
p_udpip_hdr->ip_payload = cpu_to_be16(ip_data_len);
|
||||
|
||||
udp_header *p_udp_hdr = (udp_header *) (data_to_checksum+12);
|
||||
|
||||
p_udp_hdr->uh_sum = 0;
|
||||
|
||||
int udp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12);
|
||||
DPRINTF("+++ C+ mode UDP checksum %04x\n",
|
||||
udp_checksum);
|
||||
|
||||
p_udp_hdr->uh_sum = udp_checksum;
|
||||
}
|
||||
|
||||
/* restore IP header */
|
||||
memcpy(eth_payload_data, saved_ip_header, hlen);
|
||||
}
|
||||
}
|
||||
|
||||
skip_offload:
|
||||
/* update tally counter */
|
||||
++s->tally_counters.TxOk;
|
||||
|
||||
|
||||
+19
-6
@@ -1138,7 +1138,8 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
|
||||
ssize_t ret, len;
|
||||
unsigned int out_num = elem.out_num;
|
||||
struct iovec *out_sg = &elem.out_sg[0];
|
||||
struct iovec sg[VIRTQUEUE_MAX_SIZE];
|
||||
struct iovec sg[VIRTQUEUE_MAX_SIZE], sg2[VIRTQUEUE_MAX_SIZE + 1];
|
||||
struct virtio_net_hdr_mrg_rxbuf mhdr;
|
||||
|
||||
if (out_num < 1) {
|
||||
error_report("virtio-net header not in first element");
|
||||
@@ -1146,13 +1147,25 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
|
||||
}
|
||||
|
||||
if (n->has_vnet_hdr) {
|
||||
if (out_sg[0].iov_len < n->guest_hdr_len) {
|
||||
if (iov_to_buf(out_sg, out_num, 0, &mhdr, n->guest_hdr_len) <
|
||||
n->guest_hdr_len) {
|
||||
error_report("virtio-net header incorrect");
|
||||
exit(1);
|
||||
}
|
||||
virtio_net_hdr_swap(vdev, (void *) out_sg[0].iov_base);
|
||||
if (virtio_needs_swap(vdev)) {
|
||||
virtio_net_hdr_swap(vdev, (void *) &mhdr);
|
||||
sg2[0].iov_base = &mhdr;
|
||||
sg2[0].iov_len = n->guest_hdr_len;
|
||||
out_num = iov_copy(&sg2[1], ARRAY_SIZE(sg2) - 1,
|
||||
out_sg, out_num,
|
||||
n->guest_hdr_len, -1);
|
||||
if (out_num == VIRTQUEUE_MAX_SIZE) {
|
||||
goto drop;
|
||||
}
|
||||
out_num += 1;
|
||||
out_sg = sg2;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If host wants to see the guest header as is, we can
|
||||
* pass it on unchanged. Otherwise, copy just the parts
|
||||
@@ -1182,7 +1195,7 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
|
||||
}
|
||||
|
||||
len += ret;
|
||||
|
||||
drop:
|
||||
virtqueue_push(q->tx_vq, &elem, 0);
|
||||
virtio_notify(vdev, q->tx_vq);
|
||||
|
||||
@@ -1309,7 +1322,7 @@ static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue)
|
||||
|
||||
n->multiqueue = multiqueue;
|
||||
|
||||
for (i = 2; i <= n->max_queues * 2 + 1; i++) {
|
||||
for (i = 2; i < n->max_queues * 2 + 1; i++) {
|
||||
virtio_del_queue(vdev, i);
|
||||
}
|
||||
|
||||
|
||||
@@ -233,7 +233,7 @@ static void bonito_writel(void *opaque, hwaddr addr,
|
||||
uint32_t saddr;
|
||||
int reset = 0;
|
||||
|
||||
saddr = (addr - BONITO_REGBASE) >> 2;
|
||||
saddr = addr >> 2;
|
||||
|
||||
DPRINTF("bonito_writel "TARGET_FMT_plx" val %x saddr %x\n", addr, val, saddr);
|
||||
switch (saddr) {
|
||||
@@ -295,7 +295,7 @@ static uint64_t bonito_readl(void *opaque, hwaddr addr,
|
||||
PCIBonitoState *s = opaque;
|
||||
uint32_t saddr;
|
||||
|
||||
saddr = (addr - BONITO_REGBASE) >> 2;
|
||||
saddr = addr >> 2;
|
||||
|
||||
DPRINTF("bonito_readl "TARGET_FMT_plx"\n", addr);
|
||||
switch (saddr) {
|
||||
|
||||
+3
-1
@@ -1660,7 +1660,9 @@ PCIDevice *pci_nic_init_nofail(NICInfo *nd, PCIBus *rootbus,
|
||||
|
||||
res = pci_nic_init(nd, rootbus, default_model, default_devaddr, &err);
|
||||
if (!res) {
|
||||
error_report_err(err);
|
||||
if (err) {
|
||||
error_report_err(err);
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
return res;
|
||||
|
||||
+2
-2
@@ -218,7 +218,7 @@ static Property s390_ipl_properties[] = {
|
||||
* - -1 if no valid boot device was found
|
||||
* - ccw id of the boot device otherwise
|
||||
*/
|
||||
static uint32_t s390_update_iplstate(CPUS390XState *env, S390IPLState *ipl)
|
||||
static uint64_t s390_update_iplstate(CPUS390XState *env, S390IPLState *ipl)
|
||||
{
|
||||
DeviceState *dev_st;
|
||||
|
||||
@@ -248,7 +248,7 @@ static uint32_t s390_update_iplstate(CPUS390XState *env, S390IPLState *ipl)
|
||||
|
||||
return -1;
|
||||
out:
|
||||
return ipl->cssid << 24 | ipl->ssid << 16 | ipl->devno;
|
||||
return (uint32_t) (ipl->cssid << 24 | ipl->ssid << 16 | ipl->devno);
|
||||
}
|
||||
|
||||
int s390_ipl_update_diag308(IplParameterBlock *iplb)
|
||||
|
||||
+22
-17
@@ -295,6 +295,25 @@ static int virtio_ccw_set_vqs(SubchDev *sch, uint64_t addr, uint32_t align,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void virtio_ccw_reset_virtio(VirtioCcwDevice *dev, VirtIODevice *vdev)
|
||||
{
|
||||
virtio_ccw_stop_ioeventfd(dev);
|
||||
virtio_reset(vdev);
|
||||
if (dev->indicators) {
|
||||
release_indicator(&dev->routes.adapter, dev->indicators);
|
||||
dev->indicators = NULL;
|
||||
}
|
||||
if (dev->indicators2) {
|
||||
release_indicator(&dev->routes.adapter, dev->indicators2);
|
||||
dev->indicators2 = NULL;
|
||||
}
|
||||
if (dev->summary_indicator) {
|
||||
release_indicator(&dev->routes.adapter, dev->summary_indicator);
|
||||
dev->summary_indicator = NULL;
|
||||
}
|
||||
dev->sch->thinint_active = false;
|
||||
}
|
||||
|
||||
static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
|
||||
{
|
||||
int ret;
|
||||
@@ -351,8 +370,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
|
||||
}
|
||||
break;
|
||||
case CCW_CMD_VDEV_RESET:
|
||||
virtio_ccw_stop_ioeventfd(dev);
|
||||
virtio_reset(vdev);
|
||||
virtio_ccw_reset_virtio(dev, vdev);
|
||||
ret = 0;
|
||||
break;
|
||||
case CCW_CMD_READ_FEAT:
|
||||
@@ -480,7 +498,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
|
||||
}
|
||||
virtio_set_status(vdev, status);
|
||||
if (vdev->status == 0) {
|
||||
virtio_reset(vdev);
|
||||
virtio_ccw_reset_virtio(dev, vdev);
|
||||
}
|
||||
if (status & VIRTIO_CONFIG_S_DRIVER_OK) {
|
||||
virtio_ccw_start_ioeventfd(dev);
|
||||
@@ -1098,21 +1116,8 @@ static void virtio_ccw_reset(DeviceState *d)
|
||||
VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
|
||||
|
||||
virtio_ccw_stop_ioeventfd(dev);
|
||||
virtio_reset(vdev);
|
||||
virtio_ccw_reset_virtio(dev, vdev);
|
||||
css_reset_sch(dev->sch);
|
||||
if (dev->indicators) {
|
||||
release_indicator(&dev->routes.adapter, dev->indicators);
|
||||
dev->indicators = NULL;
|
||||
}
|
||||
if (dev->indicators2) {
|
||||
release_indicator(&dev->routes.adapter, dev->indicators2);
|
||||
dev->indicators2 = NULL;
|
||||
}
|
||||
if (dev->summary_indicator) {
|
||||
release_indicator(&dev->routes.adapter, dev->summary_indicator);
|
||||
dev->summary_indicator = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void virtio_ccw_vmstate_change(DeviceState *d, bool running)
|
||||
|
||||
+6
-1
@@ -1239,10 +1239,15 @@ int scsi_cdb_length(uint8_t *buf) {
|
||||
int scsi_req_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf)
|
||||
{
|
||||
int rc;
|
||||
int len;
|
||||
|
||||
cmd->lba = -1;
|
||||
cmd->len = scsi_cdb_length(buf);
|
||||
len = scsi_cdb_length(buf);
|
||||
if (len < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
cmd->len = len;
|
||||
switch (dev->type) {
|
||||
case TYPE_TAPE:
|
||||
rc = scsi_req_stream_xfer(cmd, dev, buf);
|
||||
|
||||
@@ -196,6 +196,12 @@ static uint64_t pit_ioport_read(void *opaque, hwaddr addr,
|
||||
PITChannelState *s;
|
||||
|
||||
addr &= 3;
|
||||
|
||||
if (addr == 3) {
|
||||
/* Mode/Command register is write only, read is ignored */
|
||||
return 0;
|
||||
}
|
||||
|
||||
s = &pit->channels[addr];
|
||||
if (s->status_latched) {
|
||||
s->status_latched = 0;
|
||||
|
||||
@@ -1310,6 +1310,10 @@ static int usbnet_can_receive(NetClientState *nc)
|
||||
{
|
||||
USBNetState *s = qemu_get_nic_opaque(nc);
|
||||
|
||||
if (!s->dev.config) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (is_rndis(s) && s->rndis_state != RNDIS_DATA_INITIALIZED) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
+5
-5
@@ -1516,7 +1516,7 @@ static uint64_t vfio_rtl8168_window_quirk_read(void *opaque,
|
||||
memory_region_name(&quirk->mem),
|
||||
vdev->vbasedev.name);
|
||||
|
||||
return quirk->data.address_match ^ 0x10000000U;
|
||||
return quirk->data.address_match ^ 0x80000000U;
|
||||
}
|
||||
break;
|
||||
case 0: /* data */
|
||||
@@ -1554,7 +1554,7 @@ static void vfio_rtl8168_window_quirk_write(void *opaque, hwaddr addr,
|
||||
switch (addr) {
|
||||
case 4: /* address */
|
||||
if ((data & 0x7fff0000) == 0x10000) {
|
||||
if (data & 0x10000000U &&
|
||||
if (data & 0x80000000U &&
|
||||
vdev->pdev.cap_present & QEMU_PCI_CAP_MSIX) {
|
||||
|
||||
trace_vfio_rtl8168_window_quirk_write_table(
|
||||
@@ -1562,8 +1562,9 @@ static void vfio_rtl8168_window_quirk_write(void *opaque, hwaddr addr,
|
||||
vdev->vbasedev.name);
|
||||
|
||||
io_mem_write(&vdev->pdev.msix_table_mmio,
|
||||
(hwaddr)(quirk->data.address_match & 0xfff),
|
||||
data, size);
|
||||
(hwaddr)(data & 0xfff),
|
||||
(uint64_t)quirk->data.address_mask,
|
||||
size);
|
||||
}
|
||||
|
||||
quirk->data.flags = 1;
|
||||
@@ -3555,7 +3556,6 @@ static Property vfio_pci_dev_properties[] = {
|
||||
VFIO_FEATURE_ENABLE_VGA_BIT, false),
|
||||
DEFINE_PROP_BIT("x-req", VFIOPCIDevice, features,
|
||||
VFIO_FEATURE_ENABLE_REQ_BIT, true),
|
||||
DEFINE_PROP_INT32("bootindex", VFIOPCIDevice, bootindex, -1),
|
||||
DEFINE_PROP_BOOL("x-mmap", VFIOPCIDevice, vbasedev.allow_mmap, true),
|
||||
/*
|
||||
* TODO - support passed fds... is this necessary?
|
||||
|
||||
+9
-6
@@ -288,7 +288,7 @@ static inline void vhost_dev_log_resize(struct vhost_dev* dev, uint64_t size)
|
||||
int r;
|
||||
|
||||
log = g_malloc0(size * sizeof *log);
|
||||
log_base = (uint64_t)(unsigned long)log;
|
||||
log_base = (uintptr_t)log;
|
||||
r = dev->vhost_ops->vhost_call(dev, VHOST_SET_LOG_BASE, &log_base);
|
||||
assert(r >= 0);
|
||||
/* Sync only the range covered by the old log */
|
||||
@@ -921,7 +921,7 @@ int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev)
|
||||
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
|
||||
VirtioBusState *vbus = VIRTIO_BUS(qbus);
|
||||
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
|
||||
int i, r;
|
||||
int i, r, e;
|
||||
if (!k->set_host_notifier) {
|
||||
fprintf(stderr, "binding does not support host notifiers\n");
|
||||
r = -ENOSYS;
|
||||
@@ -939,12 +939,12 @@ int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev)
|
||||
return 0;
|
||||
fail_vq:
|
||||
while (--i >= 0) {
|
||||
r = k->set_host_notifier(qbus->parent, hdev->vq_index + i, false);
|
||||
if (r < 0) {
|
||||
e = k->set_host_notifier(qbus->parent, hdev->vq_index + i, false);
|
||||
if (e < 0) {
|
||||
fprintf(stderr, "vhost VQ %d notifier cleanup error: %d\n", i, -r);
|
||||
fflush(stderr);
|
||||
}
|
||||
assert (r >= 0);
|
||||
assert (e >= 0);
|
||||
}
|
||||
fail:
|
||||
return r;
|
||||
@@ -1057,10 +1057,13 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
|
||||
}
|
||||
|
||||
if (hdev->log_enabled) {
|
||||
uint64_t log_base;
|
||||
|
||||
hdev->log_size = vhost_get_log_size(hdev);
|
||||
hdev->log = hdev->log_size ?
|
||||
g_malloc0(hdev->log_size * sizeof *hdev->log) : NULL;
|
||||
r = hdev->vhost_ops->vhost_call(hdev, VHOST_SET_LOG_BASE, hdev->log);
|
||||
log_base = (uintptr_t)hdev->log;
|
||||
r = hdev->vhost_ops->vhost_call(hdev, VHOST_SET_LOG_BASE, &log_base);
|
||||
if (r < 0) {
|
||||
r = -errno;
|
||||
goto fail_log;
|
||||
|
||||
+10
-2
@@ -388,7 +388,7 @@ static const MemoryRegionOps ops = {
|
||||
.write = xen_pt_bar_write,
|
||||
};
|
||||
|
||||
static int xen_pt_register_regions(XenPCIPassthroughState *s)
|
||||
static int xen_pt_register_regions(XenPCIPassthroughState *s, uint16_t *cmd)
|
||||
{
|
||||
int i = 0;
|
||||
XenHostPCIDevice *d = &s->real_device;
|
||||
@@ -406,6 +406,7 @@ static int xen_pt_register_regions(XenPCIPassthroughState *s)
|
||||
|
||||
if (r->type & XEN_HOST_PCI_REGION_TYPE_IO) {
|
||||
type = PCI_BASE_ADDRESS_SPACE_IO;
|
||||
*cmd |= PCI_COMMAND_IO;
|
||||
} else {
|
||||
type = PCI_BASE_ADDRESS_SPACE_MEMORY;
|
||||
if (r->type & XEN_HOST_PCI_REGION_TYPE_PREFETCH) {
|
||||
@@ -414,6 +415,7 @@ static int xen_pt_register_regions(XenPCIPassthroughState *s)
|
||||
if (r->type & XEN_HOST_PCI_REGION_TYPE_MEM_64) {
|
||||
type |= PCI_BASE_ADDRESS_MEM_TYPE_64;
|
||||
}
|
||||
*cmd |= PCI_COMMAND_MEMORY;
|
||||
}
|
||||
|
||||
memory_region_init_io(&s->bar[i], OBJECT(s), &ops, &s->dev,
|
||||
@@ -638,6 +640,7 @@ static int xen_pt_initfn(PCIDevice *d)
|
||||
XenPCIPassthroughState *s = DO_UPCAST(XenPCIPassthroughState, dev, d);
|
||||
int rc = 0;
|
||||
uint8_t machine_irq = 0;
|
||||
uint16_t cmd = 0;
|
||||
int pirq = XEN_PT_UNASSIGNED_PIRQ;
|
||||
|
||||
/* register real device */
|
||||
@@ -672,7 +675,7 @@ static int xen_pt_initfn(PCIDevice *d)
|
||||
s->io_listener = xen_pt_io_listener;
|
||||
|
||||
/* Handle real device's MMIO/PIO BARs */
|
||||
xen_pt_register_regions(s);
|
||||
xen_pt_register_regions(s, &cmd);
|
||||
|
||||
/* reinitialize each config register to be emulated */
|
||||
if (xen_pt_config_init(s)) {
|
||||
@@ -736,6 +739,11 @@ static int xen_pt_initfn(PCIDevice *d)
|
||||
}
|
||||
|
||||
out:
|
||||
if (cmd) {
|
||||
xen_host_pci_set_word(&s->real_device, PCI_COMMAND,
|
||||
pci_get_word(d->config + PCI_COMMAND) | cmd);
|
||||
}
|
||||
|
||||
memory_listener_register(&s->memory_listener, &s->dev.bus_master_as);
|
||||
memory_listener_register(&s->io_listener, &address_space_io);
|
||||
XEN_PT_LOG(d,
|
||||
|
||||
@@ -286,23 +286,6 @@ static int xen_pt_irqpin_reg_init(XenPCIPassthroughState *s,
|
||||
}
|
||||
|
||||
/* Command register */
|
||||
static int xen_pt_cmd_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
|
||||
uint16_t *value, uint16_t valid_mask)
|
||||
{
|
||||
XenPTRegInfo *reg = cfg_entry->reg;
|
||||
uint16_t valid_emu_mask = 0;
|
||||
uint16_t emu_mask = reg->emu_mask;
|
||||
|
||||
if (s->is_virtfn) {
|
||||
emu_mask |= PCI_COMMAND_MEMORY;
|
||||
}
|
||||
|
||||
/* emulate word register */
|
||||
valid_emu_mask = emu_mask & valid_mask;
|
||||
*value = XEN_PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
static int xen_pt_cmd_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
|
||||
uint16_t *val, uint16_t dev_value,
|
||||
uint16_t valid_mask)
|
||||
@@ -310,18 +293,13 @@ static int xen_pt_cmd_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
|
||||
XenPTRegInfo *reg = cfg_entry->reg;
|
||||
uint16_t writable_mask = 0;
|
||||
uint16_t throughable_mask = 0;
|
||||
uint16_t emu_mask = reg->emu_mask;
|
||||
|
||||
if (s->is_virtfn) {
|
||||
emu_mask |= PCI_COMMAND_MEMORY;
|
||||
}
|
||||
|
||||
/* modify emulate register */
|
||||
writable_mask = ~reg->ro_mask & valid_mask;
|
||||
cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
|
||||
|
||||
/* create value for writing to I/O device register */
|
||||
throughable_mask = ~emu_mask & valid_mask;
|
||||
throughable_mask = ~reg->emu_mask & valid_mask;
|
||||
|
||||
if (*val & PCI_COMMAND_INTX_DISABLE) {
|
||||
throughable_mask |= PCI_COMMAND_INTX_DISABLE;
|
||||
@@ -603,9 +581,9 @@ static XenPTRegInfo xen_pt_emu_reg_header0[] = {
|
||||
.size = 2,
|
||||
.init_val = 0x0000,
|
||||
.ro_mask = 0xF880,
|
||||
.emu_mask = 0x0740,
|
||||
.emu_mask = 0x0743,
|
||||
.init = xen_pt_common_reg_init,
|
||||
.u.w.read = xen_pt_cmd_reg_read,
|
||||
.u.w.read = xen_pt_word_reg_read,
|
||||
.u.w.write = xen_pt_cmd_reg_write,
|
||||
},
|
||||
/* Capabilities Pointer reg */
|
||||
|
||||
@@ -361,6 +361,10 @@ bool bdrv_unallocated_blocks_are_zero(BlockDriverState *bs);
|
||||
bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs);
|
||||
int64_t bdrv_get_block_status(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors, int *pnum);
|
||||
int64_t bdrv_get_block_status_above(BlockDriverState *bs,
|
||||
BlockDriverState *base,
|
||||
int64_t sector_num,
|
||||
int nb_sectors, int *pnum);
|
||||
int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
|
||||
int *pnum);
|
||||
int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base,
|
||||
|
||||
@@ -579,6 +579,7 @@ void commit_active_start(BlockDriverState *bs, BlockDriverState *base,
|
||||
* @mode: Whether to collapse all images in the chain to the target.
|
||||
* @on_source_error: The action to take upon error reading from the source.
|
||||
* @on_target_error: The action to take upon error writing to the target.
|
||||
* @unmap: Whether to unmap target where source sectors only contain zeroes.
|
||||
* @cb: Completion function for the job.
|
||||
* @opaque: Opaque pointer value passed to @cb.
|
||||
* @errp: Error object.
|
||||
@@ -593,6 +594,7 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target,
|
||||
int64_t speed, int64_t granularity, int64_t buf_size,
|
||||
MirrorSyncMode mode, BlockdevOnError on_source_error,
|
||||
BlockdevOnError on_target_error,
|
||||
bool unmap,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque, Error **errp);
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include "hw/timer/stm32f2xx_timer.h"
|
||||
#include "hw/char/stm32f2xx_usart.h"
|
||||
|
||||
#define TYPE_STM32F205_SOC "stm32f205_soc"
|
||||
#define TYPE_STM32F205_SOC "stm32f205-soc"
|
||||
#define STM32F205_SOC(obj) \
|
||||
OBJECT_CHECK(STM32F205State, (obj), TYPE_STM32F205_SOC)
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ struct vhost_dev {
|
||||
MemoryRegionSection *mem_sections;
|
||||
struct vhost_virtqueue *vqs;
|
||||
int nvqs;
|
||||
/* the first virtuque which would be used by this vhost dev */
|
||||
/* the first virtqueue which would be used by this vhost dev */
|
||||
int vq_index;
|
||||
unsigned long long features;
|
||||
unsigned long long acked_features;
|
||||
|
||||
@@ -126,6 +126,15 @@ static inline uint64_t virtio_ldq_p(VirtIODevice *vdev, const void *ptr)
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool virtio_needs_swap(VirtIODevice *vdev)
|
||||
{
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
return virtio_access_is_big_endian(vdev) ? false : true;
|
||||
#else
|
||||
return virtio_access_is_big_endian(vdev) ? true : false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint16_t virtio_tswap16(VirtIODevice *vdev, uint16_t s)
|
||||
{
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
|
||||
@@ -67,6 +67,7 @@ typedef struct VirtIOBlockReq {
|
||||
struct virtio_blk_inhdr *in;
|
||||
struct virtio_blk_outhdr out;
|
||||
QEMUIOVector qiov;
|
||||
size_t in_len;
|
||||
struct VirtIOBlockReq *next;
|
||||
struct VirtIOBlockReq *mr_next;
|
||||
BlockAcctCookie acct;
|
||||
|
||||
@@ -1142,9 +1142,17 @@ static int kvm_irqchip_get_virq(KVMState *s)
|
||||
uint32_t *word = s->used_gsi_bitmap;
|
||||
int max_words = ALIGN(s->gsi_count, 32) / 32;
|
||||
int i, bit;
|
||||
bool retry = true;
|
||||
|
||||
again:
|
||||
/*
|
||||
* PIC and IOAPIC share the first 16 GSI numbers, thus the available
|
||||
* GSI numbers are more than the number of IRQ route. Allocating a GSI
|
||||
* number can succeed even though a new route entry cannot be added.
|
||||
* When this happens, flush dynamic MSI entries to free IRQ route entries.
|
||||
*/
|
||||
if (!s->direct_msi && s->irq_routes->nr == s->gsi_count) {
|
||||
kvm_flush_dynamic_msi_routes(s);
|
||||
}
|
||||
|
||||
/* Return the lowest unused GSI in the bitmap */
|
||||
for (i = 0; i < max_words; i++) {
|
||||
bit = ffs(~word[i]);
|
||||
@@ -1154,11 +1162,6 @@ again:
|
||||
|
||||
return bit - 1 + i * 32;
|
||||
}
|
||||
if (!s->direct_msi && retry) {
|
||||
retry = false;
|
||||
kvm_flush_dynamic_msi_routes(s);
|
||||
goto again;
|
||||
}
|
||||
return -ENOSPC;
|
||||
|
||||
}
|
||||
|
||||
@@ -681,7 +681,7 @@ int nbd_init(int fd, int csock, uint32_t flags, off_t size)
|
||||
|
||||
TRACE("Setting size to %zd block(s)", (size_t)(size / BDRV_SECTOR_SIZE));
|
||||
|
||||
if (ioctl(fd, NBD_SET_SIZE_BLOCKS, size / (size_t)BDRV_SECTOR_SIZE) < 0) {
|
||||
if (ioctl(fd, NBD_SET_SIZE_BLOCKS, (size_t)(size / BDRV_SECTOR_SIZE)) < 0) {
|
||||
int serrno = errno;
|
||||
LOG("Failed setting size (in blocks)");
|
||||
return -serrno;
|
||||
|
||||
+3
-1
@@ -2669,6 +2669,7 @@
|
||||
# Since: 1.3.0
|
||||
#
|
||||
# 'unmapped' and 'pause' since 2.0
|
||||
# 'ro' and 'kp_comma' since 2.4
|
||||
##
|
||||
{ 'enum': 'QKeyCode',
|
||||
'data': [ 'unmapped',
|
||||
@@ -2686,7 +2687,8 @@
|
||||
'kp_9', 'less', 'f11', 'f12', 'print', 'home', 'pgup', 'pgdn', 'end',
|
||||
'left', 'up', 'down', 'right', 'insert', 'delete', 'stop', 'again',
|
||||
'props', 'undo', 'front', 'copy', 'open', 'paste', 'find', 'cut',
|
||||
'lf', 'help', 'meta_l', 'meta_r', 'compose', 'pause' ] }
|
||||
'lf', 'help', 'meta_l', 'meta_r', 'compose', 'pause', 'ro',
|
||||
'kp_comma' ] }
|
||||
|
||||
##
|
||||
# @KeyValue
|
||||
|
||||
@@ -943,6 +943,11 @@
|
||||
# @on-target-error: #optional the action to take on an error on the target,
|
||||
# default 'report' (no limitations, since this applies to
|
||||
# a different block device than @device).
|
||||
# @unmap: #optional Whether to try to unmap target sectors where source has
|
||||
# only zero. If true, and target unallocated sectors will read as zero,
|
||||
# target image sectors will be unmapped; otherwise, zeroes will be
|
||||
# written. Both will result in identical contents.
|
||||
# Default is true. (Since 2.4)
|
||||
#
|
||||
# Returns: nothing on success
|
||||
# If @device is not a valid block device, DeviceNotFound
|
||||
@@ -955,7 +960,8 @@
|
||||
'sync': 'MirrorSyncMode', '*mode': 'NewImageMode',
|
||||
'*speed': 'int', '*granularity': 'uint32',
|
||||
'*buf-size': 'int', '*on-source-error': 'BlockdevOnError',
|
||||
'*on-target-error': 'BlockdevOnError' } }
|
||||
'*on-target-error': 'BlockdevOnError',
|
||||
'*unmap': 'bool' } }
|
||||
|
||||
##
|
||||
# @block_set_io_throttle:
|
||||
|
||||
+11
-2
@@ -2797,7 +2797,10 @@ static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len)
|
||||
#ifdef MSG_CMSG_CLOEXEC
|
||||
flags |= MSG_CMSG_CLOEXEC;
|
||||
#endif
|
||||
ret = recvmsg(s->fd, &msg, flags);
|
||||
do {
|
||||
ret = recvmsg(s->fd, &msg, flags);
|
||||
} while (ret == -1 && errno == EINTR);
|
||||
|
||||
if (ret > 0 && s->is_unix) {
|
||||
unix_process_msgfd(chr, &msg);
|
||||
}
|
||||
@@ -2808,7 +2811,13 @@ static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len)
|
||||
static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len)
|
||||
{
|
||||
TCPCharDriver *s = chr->opaque;
|
||||
return qemu_recv(s->fd, buf, len, 0);
|
||||
ssize_t ret;
|
||||
|
||||
do {
|
||||
ret = qemu_recv(s->fd, buf, len, 0);
|
||||
} while (ret == -1 && socket_error() == EINTR);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1332,11 +1332,7 @@ void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
|
||||
struct FsMount *mount;
|
||||
int fd;
|
||||
Error *local_err = NULL;
|
||||
struct fstrim_range r = {
|
||||
.start = 0,
|
||||
.len = -1,
|
||||
.minlen = has_minimum ? minimum : 0,
|
||||
};
|
||||
struct fstrim_range r;
|
||||
|
||||
slog("guest-fstrim called");
|
||||
|
||||
@@ -1360,6 +1356,9 @@ void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
|
||||
* error means an unexpected error, so return it in those cases. In
|
||||
* some other cases ENOTTY will be reported (e.g. CD-ROMs).
|
||||
*/
|
||||
r.start = 0;
|
||||
r.len = -1;
|
||||
r.minlen = has_minimum ? minimum : 0;
|
||||
ret = ioctl(fd, FITRIM, &r);
|
||||
if (ret == -1) {
|
||||
if (errno != ENOTTY && errno != EOPNOTSUPP) {
|
||||
|
||||
@@ -1380,6 +1380,7 @@ EQMP
|
||||
.args_type = "sync:s,device:B,target:s,speed:i?,mode:s?,format:s?,"
|
||||
"node-name:s?,replaces:s?,"
|
||||
"on-source-error:s?,on-target-error:s?,"
|
||||
"unmap:b?,"
|
||||
"granularity:i?,buf-size:i?",
|
||||
.mhandler.cmd_new = qmp_marshal_input_drive_mirror,
|
||||
},
|
||||
@@ -1419,6 +1420,8 @@ Arguments:
|
||||
(BlockdevOnError, default 'report')
|
||||
- "on-target-error": the action to take on an error on the target
|
||||
(BlockdevOnError, default 'report')
|
||||
- "unmap": whether the target sectors should be discarded where source has only
|
||||
zeroes. (json-bool, optional, default true)
|
||||
|
||||
The default value of the granularity is the image cluster size clamped
|
||||
between 4096 and 65536, if the image format defines one. If the format
|
||||
|
||||
+65
-30
@@ -21,6 +21,9 @@ class QMPConnectError(QMPError):
|
||||
class QMPCapabilitiesError(QMPError):
|
||||
pass
|
||||
|
||||
class QMPTimeoutError(QMPError):
|
||||
pass
|
||||
|
||||
class QEMUMonitorProtocol:
|
||||
def __init__(self, address, server=False):
|
||||
"""
|
||||
@@ -72,6 +75,44 @@ class QEMUMonitorProtocol:
|
||||
|
||||
error = socket.error
|
||||
|
||||
def __get_events(self, wait=False):
|
||||
"""
|
||||
Check for new events in the stream and cache them in __events.
|
||||
|
||||
@param wait (bool): block until an event is available.
|
||||
@param wait (float): If wait is a float, treat it as a timeout value.
|
||||
|
||||
@raise QMPTimeoutError: If a timeout float is provided and the timeout
|
||||
period elapses.
|
||||
@raise QMPConnectError: If wait is True but no events could be retrieved
|
||||
or if some other error occurred.
|
||||
"""
|
||||
|
||||
# Check for new events regardless and pull them into the cache:
|
||||
self.__sock.setblocking(0)
|
||||
try:
|
||||
self.__json_read()
|
||||
except socket.error, err:
|
||||
if err[0] == errno.EAGAIN:
|
||||
# No data available
|
||||
pass
|
||||
self.__sock.setblocking(1)
|
||||
|
||||
# Wait for new events, if needed.
|
||||
# if wait is 0.0, this means "no wait" and is also implicitly false.
|
||||
if not self.__events and wait:
|
||||
if isinstance(wait, float):
|
||||
self.__sock.settimeout(wait)
|
||||
try:
|
||||
ret = self.__json_read(only_event=True)
|
||||
except socket.timeout:
|
||||
raise QMPTimeoutError("Timeout waiting for event")
|
||||
except:
|
||||
raise QMPConnectError("Error while reading from socket")
|
||||
if ret is None:
|
||||
raise QMPConnectError("Error while reading from socket")
|
||||
self.__sock.settimeout(None)
|
||||
|
||||
def connect(self, negotiate=True):
|
||||
"""
|
||||
Connect to the QMP Monitor and perform capabilities negotiation.
|
||||
@@ -140,43 +181,37 @@ class QEMUMonitorProtocol:
|
||||
"""
|
||||
Get and delete the first available QMP event.
|
||||
|
||||
@param wait: block until an event is available (bool)
|
||||
@param wait (bool): block until an event is available.
|
||||
@param wait (float): If wait is a float, treat it as a timeout value.
|
||||
|
||||
@raise QMPTimeoutError: If a timeout float is provided and the timeout
|
||||
period elapses.
|
||||
@raise QMPConnectError: If wait is True but no events could be retrieved
|
||||
or if some other error occurred.
|
||||
|
||||
@return The first available QMP event, or None.
|
||||
"""
|
||||
self.__sock.setblocking(0)
|
||||
try:
|
||||
self.__json_read()
|
||||
except socket.error, err:
|
||||
if err[0] == errno.EAGAIN:
|
||||
# No data available
|
||||
pass
|
||||
self.__sock.setblocking(1)
|
||||
if not self.__events and wait:
|
||||
self.__json_read(only_event=True)
|
||||
event = self.__events[0]
|
||||
del self.__events[0]
|
||||
return event
|
||||
self.__get_events(wait)
|
||||
|
||||
if self.__events:
|
||||
return self.__events.pop(0)
|
||||
return None
|
||||
|
||||
def get_events(self, wait=False):
|
||||
"""
|
||||
Get a list of available QMP events.
|
||||
|
||||
@param wait: block until an event is available (bool)
|
||||
"""
|
||||
self.__sock.setblocking(0)
|
||||
try:
|
||||
self.__json_read()
|
||||
except socket.error, err:
|
||||
if err[0] == errno.EAGAIN:
|
||||
# No data available
|
||||
pass
|
||||
self.__sock.setblocking(1)
|
||||
if not self.__events and wait:
|
||||
ret = self.__json_read(only_event=True)
|
||||
if ret == None:
|
||||
# We are in blocking mode, if don't get anything, something
|
||||
# went wrong
|
||||
raise QMPConnectError("Error while reading from socket")
|
||||
@param wait (bool): block until an event is available.
|
||||
@param wait (float): If wait is a float, treat it as a timeout value.
|
||||
|
||||
@raise QMPTimeoutError: If a timeout float is provided and the timeout
|
||||
period elapses.
|
||||
@raise QMPConnectError: If wait is True but no events could be retrieved
|
||||
or if some other error occurred.
|
||||
|
||||
@return The list of available QMP events.
|
||||
"""
|
||||
self.__get_events(wait)
|
||||
return self.__events
|
||||
|
||||
def clear_events(self):
|
||||
|
||||
+38
-30
@@ -8423,18 +8423,53 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
|
||||
}
|
||||
} else {
|
||||
int address_offset;
|
||||
int load;
|
||||
bool load = insn & (1 << 20);
|
||||
bool doubleword = false;
|
||||
/* Misc load/store */
|
||||
rn = (insn >> 16) & 0xf;
|
||||
rd = (insn >> 12) & 0xf;
|
||||
|
||||
if (!load && (sh & 2)) {
|
||||
/* doubleword */
|
||||
ARCH(5TE);
|
||||
if (rd & 1) {
|
||||
/* UNPREDICTABLE; we choose to UNDEF */
|
||||
goto illegal_op;
|
||||
}
|
||||
load = (sh & 1) == 0;
|
||||
doubleword = true;
|
||||
}
|
||||
|
||||
addr = load_reg(s, rn);
|
||||
if (insn & (1 << 24))
|
||||
gen_add_datah_offset(s, insn, 0, addr);
|
||||
address_offset = 0;
|
||||
if (insn & (1 << 20)) {
|
||||
|
||||
if (doubleword) {
|
||||
if (!load) {
|
||||
/* store */
|
||||
tmp = load_reg(s, rd);
|
||||
gen_aa32_st32(tmp, addr, get_mem_index(s));
|
||||
tcg_temp_free_i32(tmp);
|
||||
tcg_gen_addi_i32(addr, addr, 4);
|
||||
tmp = load_reg(s, rd + 1);
|
||||
gen_aa32_st32(tmp, addr, get_mem_index(s));
|
||||
tcg_temp_free_i32(tmp);
|
||||
} else {
|
||||
/* load */
|
||||
tmp = tcg_temp_new_i32();
|
||||
gen_aa32_ld32u(tmp, addr, get_mem_index(s));
|
||||
store_reg(s, rd, tmp);
|
||||
tcg_gen_addi_i32(addr, addr, 4);
|
||||
tmp = tcg_temp_new_i32();
|
||||
gen_aa32_ld32u(tmp, addr, get_mem_index(s));
|
||||
rd++;
|
||||
}
|
||||
address_offset = -4;
|
||||
} else if (load) {
|
||||
/* load */
|
||||
tmp = tcg_temp_new_i32();
|
||||
switch(sh) {
|
||||
switch (sh) {
|
||||
case 1:
|
||||
gen_aa32_ld16u(tmp, addr, get_mem_index(s));
|
||||
break;
|
||||
@@ -8446,38 +8481,11 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
|
||||
gen_aa32_ld16s(tmp, addr, get_mem_index(s));
|
||||
break;
|
||||
}
|
||||
load = 1;
|
||||
} else if (sh & 2) {
|
||||
ARCH(5TE);
|
||||
/* doubleword */
|
||||
if (sh & 1) {
|
||||
/* store */
|
||||
tmp = load_reg(s, rd);
|
||||
gen_aa32_st32(tmp, addr, get_mem_index(s));
|
||||
tcg_temp_free_i32(tmp);
|
||||
tcg_gen_addi_i32(addr, addr, 4);
|
||||
tmp = load_reg(s, rd + 1);
|
||||
gen_aa32_st32(tmp, addr, get_mem_index(s));
|
||||
tcg_temp_free_i32(tmp);
|
||||
load = 0;
|
||||
} else {
|
||||
/* load */
|
||||
tmp = tcg_temp_new_i32();
|
||||
gen_aa32_ld32u(tmp, addr, get_mem_index(s));
|
||||
store_reg(s, rd, tmp);
|
||||
tcg_gen_addi_i32(addr, addr, 4);
|
||||
tmp = tcg_temp_new_i32();
|
||||
gen_aa32_ld32u(tmp, addr, get_mem_index(s));
|
||||
rd++;
|
||||
load = 1;
|
||||
}
|
||||
address_offset = -4;
|
||||
} else {
|
||||
/* store */
|
||||
tmp = load_reg(s, rd);
|
||||
gen_aa32_st16(tmp, addr, get_mem_index(s));
|
||||
tcg_temp_free_i32(tmp);
|
||||
load = 0;
|
||||
}
|
||||
/* Perform base writeback before the loaded value to
|
||||
ensure correct behavior with overlapping index registers.
|
||||
|
||||
@@ -31,8 +31,6 @@
|
||||
/* Maximum instruction code size */
|
||||
#define TARGET_MAX_INSN_SIZE 16
|
||||
|
||||
/* target supports implicit self modifying code */
|
||||
#define TARGET_HAS_SMC
|
||||
/* support for self modifying code even if the modified instruction is
|
||||
close to the modifying instruction */
|
||||
#define TARGET_HAS_PRECISE_SMC
|
||||
|
||||
+7
-14
@@ -240,10 +240,9 @@ int kvm_mips_set_ipi_interrupt(MIPSCPU *cpu, int irq, int level)
|
||||
static inline int kvm_mips_put_one_reg(CPUState *cs, uint64_t reg_id,
|
||||
int32_t *addr)
|
||||
{
|
||||
uint64_t val64 = *addr;
|
||||
struct kvm_one_reg cp0reg = {
|
||||
.id = reg_id,
|
||||
.addr = (uintptr_t)&val64
|
||||
.addr = (uintptr_t)addr
|
||||
};
|
||||
|
||||
return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &cp0reg);
|
||||
@@ -275,18 +274,12 @@ static inline int kvm_mips_put_one_reg64(CPUState *cs, uint64_t reg_id,
|
||||
static inline int kvm_mips_get_one_reg(CPUState *cs, uint64_t reg_id,
|
||||
int32_t *addr)
|
||||
{
|
||||
int ret;
|
||||
uint64_t val64 = 0;
|
||||
struct kvm_one_reg cp0reg = {
|
||||
.id = reg_id,
|
||||
.addr = (uintptr_t)&val64
|
||||
.addr = (uintptr_t)addr
|
||||
};
|
||||
|
||||
ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &cp0reg);
|
||||
if (ret >= 0) {
|
||||
*addr = val64;
|
||||
}
|
||||
return ret;
|
||||
return kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &cp0reg);
|
||||
}
|
||||
|
||||
static inline int kvm_mips_get_one_ulreg(CPUState *cs, uint64 reg_id,
|
||||
@@ -640,12 +633,12 @@ int kvm_arch_put_registers(CPUState *cs, int level)
|
||||
|
||||
/* Set the registers based on QEMU's view of things */
|
||||
for (i = 0; i < 32; i++) {
|
||||
regs.gpr[i] = env->active_tc.gpr[i];
|
||||
regs.gpr[i] = (int64_t)(target_long)env->active_tc.gpr[i];
|
||||
}
|
||||
|
||||
regs.hi = env->active_tc.HI[0];
|
||||
regs.lo = env->active_tc.LO[0];
|
||||
regs.pc = env->active_tc.PC;
|
||||
regs.hi = (int64_t)(target_long)env->active_tc.HI[0];
|
||||
regs.lo = (int64_t)(target_long)env->active_tc.LO[0];
|
||||
regs.pc = (int64_t)(target_long)env->active_tc.PC;
|
||||
|
||||
ret = kvm_vcpu_ioctl(cs, KVM_SET_REGS, ®s);
|
||||
|
||||
|
||||
+51
-6
@@ -39,6 +39,7 @@
|
||||
#include "sysemu/watchdog.h"
|
||||
#include "trace.h"
|
||||
#include "exec/gdbstub.h"
|
||||
#include "sysemu/hostmem.h"
|
||||
|
||||
//#define DEBUG_KVM
|
||||
|
||||
@@ -302,16 +303,11 @@ static void kvm_get_smmu_info(PowerPCCPU *cpu, struct kvm_ppc_smmu_info *info)
|
||||
kvm_get_fallback_smmu_info(cpu, info);
|
||||
}
|
||||
|
||||
static long getrampagesize(void)
|
||||
static long gethugepagesize(const char *mem_path)
|
||||
{
|
||||
struct statfs fs;
|
||||
int ret;
|
||||
|
||||
if (!mem_path) {
|
||||
/* guest RAM is backed by normal anonymous pages */
|
||||
return getpagesize();
|
||||
}
|
||||
|
||||
do {
|
||||
ret = statfs(mem_path, &fs);
|
||||
} while (ret != 0 && errno == EINTR);
|
||||
@@ -333,6 +329,55 @@ static long getrampagesize(void)
|
||||
return fs.f_bsize;
|
||||
}
|
||||
|
||||
static int find_max_supported_pagesize(Object *obj, void *opaque)
|
||||
{
|
||||
char *mem_path;
|
||||
long *hpsize_min = opaque;
|
||||
|
||||
if (object_dynamic_cast(obj, TYPE_MEMORY_BACKEND)) {
|
||||
mem_path = object_property_get_str(obj, "mem-path", NULL);
|
||||
if (mem_path) {
|
||||
long hpsize = gethugepagesize(mem_path);
|
||||
if (hpsize < *hpsize_min) {
|
||||
*hpsize_min = hpsize;
|
||||
}
|
||||
} else {
|
||||
*hpsize_min = getpagesize();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long getrampagesize(void)
|
||||
{
|
||||
long hpsize = LONG_MAX;
|
||||
Object *memdev_root;
|
||||
|
||||
if (mem_path) {
|
||||
return gethugepagesize(mem_path);
|
||||
}
|
||||
|
||||
/* it's possible we have memory-backend objects with
|
||||
* hugepage-backed RAM. these may get mapped into system
|
||||
* address space via -numa parameters or memory hotplug
|
||||
* hooks. we want to take these into account, but we
|
||||
* also want to make sure these supported hugepage
|
||||
* sizes are applicable across the entire range of memory
|
||||
* we may boot from, so we take the min across all
|
||||
* backends, and assume normal pages in cases where a
|
||||
* backend isn't backed by hugepages.
|
||||
*/
|
||||
memdev_root = object_resolve_path("/objects", NULL);
|
||||
if (!memdev_root) {
|
||||
return getpagesize();
|
||||
}
|
||||
|
||||
object_child_foreach(memdev_root, find_max_supported_pagesize, &hpsize);
|
||||
|
||||
return (hpsize == LONG_MAX) ? getpagesize() : hpsize;
|
||||
}
|
||||
|
||||
static bool kvm_valid_page_size(uint32_t flags, long rampgsize, uint32_t shift)
|
||||
{
|
||||
if (!(flags & KVM_PPC_PAGE_SIZES_REAL)) {
|
||||
|
||||
@@ -192,9 +192,9 @@ static int cpu_post_load(void *opaque, int version_id)
|
||||
ppc_store_sdr1(env, env->spr[SPR_SDR1]);
|
||||
}
|
||||
|
||||
/* Mark msr bits except MSR_TGPR invalid before restoring */
|
||||
/* Invalidate all msr bits except MSR_TGPR/MSR_HVB before restoring */
|
||||
msr = env->msr;
|
||||
env->msr ^= ~(1ULL << MSR_TGPR);
|
||||
env->msr ^= ~((1ULL << MSR_TGPR) | MSR_HVB);
|
||||
ppc_store_msr(env, msr);
|
||||
|
||||
hreg_compute_mem_idx(env);
|
||||
|
||||
@@ -2573,7 +2573,7 @@ void helper_rslcx(CPUTriCoreState *env)
|
||||
/* CSU trap */
|
||||
}
|
||||
/* if (PCXI.UL == 1) then trap(CTYP); */
|
||||
if ((env->PCXI & MASK_PCXI_UL) == 1) {
|
||||
if ((env->PCXI & MASK_PCXI_UL) != 0) {
|
||||
/* CTYP trap */
|
||||
}
|
||||
/* EA = {PCXI.PCXS, 6'b0, PCXI.PCXO, 6'b0}; */
|
||||
|
||||
@@ -963,9 +963,11 @@ static void tcg_out_tlb_load(TCGContext *s, TCGReg base, TCGReg addrl,
|
||||
}
|
||||
|
||||
/* Load the tlb comparator. */
|
||||
tcg_out_opc_imm(s, OPC_LW, TCG_TMP0, TCG_REG_A0, cmp_off + LO_OFF);
|
||||
if (TARGET_LONG_BITS == 64) {
|
||||
tcg_out_opc_imm(s, OPC_LW, TCG_TMP0, TCG_REG_A0, cmp_off + LO_OFF);
|
||||
tcg_out_opc_imm(s, OPC_LW, base, TCG_REG_A0, cmp_off + HI_OFF);
|
||||
} else {
|
||||
tcg_out_opc_imm(s, OPC_LW, TCG_TMP0, TCG_REG_A0, cmp_off);
|
||||
}
|
||||
|
||||
/* Mask the page bits, keeping the alignment bits to compare against.
|
||||
@@ -1267,6 +1269,9 @@ static void tcg_out_addsub2(TCGContext *s, TCGReg rl, TCGReg rh, TCGReg al,
|
||||
if (cbl) {
|
||||
tcg_out_opc_imm(s, OPC_ADDIU, rl, al, bl);
|
||||
tcg_out_opc_imm(s, OPC_SLTIU, TCG_TMP0, rl, bl);
|
||||
} else if (rl == al && rl == bl) {
|
||||
tcg_out_opc_sa(s, OPC_SRL, TCG_TMP0, al, 31);
|
||||
tcg_out_opc_reg(s, OPC_ADDU, rl, al, bl);
|
||||
} else {
|
||||
tcg_out_opc_reg(s, OPC_ADDU, rl, al, bl);
|
||||
tcg_out_opc_reg(s, OPC_SLTU, TCG_TMP0, rl, (rl == bl ? al : bl));
|
||||
|
||||
+2
-2
@@ -808,7 +808,7 @@ void tcg_gen_ld_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset)
|
||||
{
|
||||
/* Since arg2 and ret have different types,
|
||||
they cannot be the same temporary */
|
||||
#ifdef TCG_TARGET_WORDS_BIGENDIAN
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
tcg_gen_ld_i32(TCGV_HIGH(ret), arg2, offset);
|
||||
tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset + 4);
|
||||
#else
|
||||
@@ -819,7 +819,7 @@ void tcg_gen_ld_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset)
|
||||
|
||||
void tcg_gen_st_i64(TCGv_i64 arg1, TCGv_ptr arg2, tcg_target_long offset)
|
||||
{
|
||||
#ifdef TCG_TARGET_WORDS_BIGENDIAN
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
tcg_gen_st_i32(TCGV_HIGH(arg1), arg2, offset);
|
||||
tcg_gen_st_i32(TCGV_LOW(arg1), arg2, offset + 4);
|
||||
#else
|
||||
|
||||
@@ -78,6 +78,19 @@ for align in 512 4k; do
|
||||
echo
|
||||
echo "== verifying patterns (2) =="
|
||||
do_test $align "read -P 0x0 0x400 0x20000" "$TEST_IMG" | _filter_qemu_io
|
||||
|
||||
echo
|
||||
echo "== rewriting unaligned zeroes =="
|
||||
do_test $align "write -P 0xb 0x0 0x1000" "$TEST_IMG" | _filter_qemu_io
|
||||
do_test $align "write -z 0x200 0x200" "$TEST_IMG" | _filter_qemu_io
|
||||
|
||||
echo
|
||||
echo "== verifying patterns (3) =="
|
||||
do_test $align "read -P 0xb 0x0 0x200" "$TEST_IMG" | _filter_qemu_io
|
||||
do_test $align "read -P 0x0 0x200 0x200" "$TEST_IMG" | _filter_qemu_io
|
||||
do_test $align "read -P 0xb 0x400 0xc00" "$TEST_IMG" | _filter_qemu_io
|
||||
|
||||
echo
|
||||
done
|
||||
|
||||
# success, all done
|
||||
|
||||
@@ -27,6 +27,21 @@ wrote 65536/65536 bytes at offset 65536
|
||||
read 131072/131072 bytes at offset 1024
|
||||
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
|
||||
== rewriting unaligned zeroes ==
|
||||
wrote 4096/4096 bytes at offset 0
|
||||
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 512/512 bytes at offset 512
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
|
||||
== verifying patterns (3) ==
|
||||
read 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 512/512 bytes at offset 512
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 3072/3072 bytes at offset 1024
|
||||
3 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
|
||||
|
||||
== preparing image ==
|
||||
wrote 1024/1024 bytes at offset 512
|
||||
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
@@ -52,4 +67,19 @@ wrote 65536/65536 bytes at offset 65536
|
||||
== verifying patterns (2) ==
|
||||
read 131072/131072 bytes at offset 1024
|
||||
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
|
||||
== rewriting unaligned zeroes ==
|
||||
wrote 4096/4096 bytes at offset 0
|
||||
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 512/512 bytes at offset 512
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
|
||||
== verifying patterns (3) ==
|
||||
read 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 512/512 bytes at offset 512
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 3072/3072 bytes at offset 1024
|
||||
3 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
|
||||
*** done
|
||||
+15
-51
@@ -34,38 +34,8 @@ quorum_img3 = os.path.join(iotests.test_dir, 'quorum3.img')
|
||||
quorum_repair_img = os.path.join(iotests.test_dir, 'quorum_repair.img')
|
||||
quorum_snapshot_file = os.path.join(iotests.test_dir, 'quorum_snapshot.img')
|
||||
|
||||
class ImageMirroringTestCase(iotests.QMPTestCase):
|
||||
'''Abstract base class for image mirroring test cases'''
|
||||
|
||||
def wait_ready(self, drive='drive0'):
|
||||
'''Wait until a block job BLOCK_JOB_READY event'''
|
||||
ready = False
|
||||
while not ready:
|
||||
for event in self.vm.get_qmp_events(wait=True):
|
||||
if event['event'] == 'BLOCK_JOB_READY':
|
||||
self.assert_qmp(event, 'data/type', 'mirror')
|
||||
self.assert_qmp(event, 'data/device', drive)
|
||||
ready = True
|
||||
|
||||
def wait_ready_and_cancel(self, drive='drive0'):
|
||||
self.wait_ready(drive=drive)
|
||||
event = self.cancel_and_wait(drive=drive)
|
||||
self.assertEquals(event['event'], 'BLOCK_JOB_COMPLETED')
|
||||
self.assert_qmp(event, 'data/type', 'mirror')
|
||||
self.assert_qmp(event, 'data/offset', event['data']['len'])
|
||||
|
||||
def complete_and_wait(self, drive='drive0', wait_ready=True):
|
||||
'''Complete a block job and wait for it to finish'''
|
||||
if wait_ready:
|
||||
self.wait_ready(drive=drive)
|
||||
|
||||
result = self.vm.qmp('block-job-complete', device=drive)
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
event = self.wait_until_completed(drive=drive)
|
||||
self.assert_qmp(event, 'data/type', 'mirror')
|
||||
|
||||
class TestSingleDrive(ImageMirroringTestCase):
|
||||
class TestSingleDrive(iotests.QMPTestCase):
|
||||
image_len = 1 * 1024 * 1024 # MB
|
||||
|
||||
def setUp(self):
|
||||
@@ -221,17 +191,9 @@ class TestSingleDriveUnalignedLength(TestSingleDrive):
|
||||
test_small_buffer2 = None
|
||||
test_large_cluster = None
|
||||
|
||||
class TestMirrorNoBacking(ImageMirroringTestCase):
|
||||
class TestMirrorNoBacking(iotests.QMPTestCase):
|
||||
image_len = 2 * 1024 * 1024 # MB
|
||||
|
||||
def complete_and_wait(self, drive='drive0', wait_ready=True):
|
||||
iotests.create_image(target_backing_img, TestMirrorNoBacking.image_len)
|
||||
return ImageMirroringTestCase.complete_and_wait(self, drive, wait_ready)
|
||||
|
||||
def compare_images(self, img1, img2):
|
||||
iotests.create_image(target_backing_img, TestMirrorNoBacking.image_len)
|
||||
return iotests.compare_images(img1, img2)
|
||||
|
||||
def setUp(self):
|
||||
iotests.create_image(backing_img, TestMirrorNoBacking.image_len)
|
||||
qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
|
||||
@@ -242,7 +204,10 @@ class TestMirrorNoBacking(ImageMirroringTestCase):
|
||||
self.vm.shutdown()
|
||||
os.remove(test_img)
|
||||
os.remove(backing_img)
|
||||
os.remove(target_backing_img)
|
||||
try:
|
||||
os.remove(target_backing_img)
|
||||
except:
|
||||
pass
|
||||
os.remove(target_img)
|
||||
|
||||
def test_complete(self):
|
||||
@@ -257,7 +222,7 @@ class TestMirrorNoBacking(ImageMirroringTestCase):
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/inserted/file', target_img)
|
||||
self.vm.shutdown()
|
||||
self.assertTrue(self.compare_images(test_img, target_img),
|
||||
self.assertTrue(iotests.compare_images(test_img, target_img),
|
||||
'target image does not match source after mirroring')
|
||||
|
||||
def test_cancel(self):
|
||||
@@ -272,7 +237,7 @@ class TestMirrorNoBacking(ImageMirroringTestCase):
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/inserted/file', test_img)
|
||||
self.vm.shutdown()
|
||||
self.assertTrue(self.compare_images(test_img, target_img),
|
||||
self.assertTrue(iotests.compare_images(test_img, target_img),
|
||||
'target image does not match source after mirroring')
|
||||
|
||||
def test_large_cluster(self):
|
||||
@@ -283,7 +248,6 @@ class TestMirrorNoBacking(ImageMirroringTestCase):
|
||||
%(TestMirrorNoBacking.image_len), target_backing_img)
|
||||
qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,backing_file=%s'
|
||||
% (TestMirrorNoBacking.image_len, target_backing_img), target_img)
|
||||
os.remove(target_backing_img)
|
||||
|
||||
result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
|
||||
mode='existing', target=target_img)
|
||||
@@ -293,10 +257,10 @@ class TestMirrorNoBacking(ImageMirroringTestCase):
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/inserted/file', target_img)
|
||||
self.vm.shutdown()
|
||||
self.assertTrue(self.compare_images(test_img, target_img),
|
||||
self.assertTrue(iotests.compare_images(test_img, target_img),
|
||||
'target image does not match source after mirroring')
|
||||
|
||||
class TestMirrorResized(ImageMirroringTestCase):
|
||||
class TestMirrorResized(iotests.QMPTestCase):
|
||||
backing_len = 1 * 1024 * 1024 # MB
|
||||
image_len = 2 * 1024 * 1024 # MB
|
||||
|
||||
@@ -344,7 +308,7 @@ class TestMirrorResized(ImageMirroringTestCase):
|
||||
self.assertTrue(iotests.compare_images(test_img, target_img),
|
||||
'target image does not match source after mirroring')
|
||||
|
||||
class TestReadErrors(ImageMirroringTestCase):
|
||||
class TestReadErrors(iotests.QMPTestCase):
|
||||
image_len = 2 * 1024 * 1024 # MB
|
||||
|
||||
# this should be a multiple of twice the default granularity
|
||||
@@ -498,7 +462,7 @@ new_state = "1"
|
||||
self.assert_no_active_block_jobs()
|
||||
self.vm.shutdown()
|
||||
|
||||
class TestWriteErrors(ImageMirroringTestCase):
|
||||
class TestWriteErrors(iotests.QMPTestCase):
|
||||
image_len = 2 * 1024 * 1024 # MB
|
||||
|
||||
# this should be a multiple of twice the default granularity
|
||||
@@ -624,7 +588,7 @@ new_state = "1"
|
||||
self.assert_no_active_block_jobs()
|
||||
self.vm.shutdown()
|
||||
|
||||
class TestSetSpeed(ImageMirroringTestCase):
|
||||
class TestSetSpeed(iotests.QMPTestCase):
|
||||
image_len = 80 * 1024 * 1024 # MB
|
||||
|
||||
def setUp(self):
|
||||
@@ -690,7 +654,7 @@ class TestSetSpeed(ImageMirroringTestCase):
|
||||
|
||||
self.wait_ready_and_cancel()
|
||||
|
||||
class TestUnbackedSource(ImageMirroringTestCase):
|
||||
class TestUnbackedSource(iotests.QMPTestCase):
|
||||
image_len = 2 * 1024 * 1024 # MB
|
||||
|
||||
def setUp(self):
|
||||
@@ -731,7 +695,7 @@ class TestUnbackedSource(ImageMirroringTestCase):
|
||||
self.complete_and_wait()
|
||||
self.assert_no_active_block_jobs()
|
||||
|
||||
class TestRepairQuorum(ImageMirroringTestCase):
|
||||
class TestRepairQuorum(iotests.QMPTestCase):
|
||||
""" This class test quorum file repair using drive-mirror.
|
||||
It's mostly a fork of TestSingleDrive """
|
||||
image_len = 1 * 1024 * 1024 # MB
|
||||
|
||||
@@ -93,6 +93,16 @@ $QEMU_IO -c "open -o l2-cache-size=1M,refcount-cache-size=0.25M $TEST_IMG" \
|
||||
-c 'read -P 42 0 64k' \
|
||||
| _filter_qemu_io
|
||||
|
||||
echo
|
||||
echo '=== Testing minimal L2 cache and COW ==='
|
||||
echo
|
||||
|
||||
$QEMU_IMG snapshot -c foo "$TEST_IMG"
|
||||
# This requires a COW operation, which accesses two L2 tables simultaneously
|
||||
# (COW source and destination), so there must be enough space in the cache to
|
||||
# place both tables there (and qemu should not crash)
|
||||
$QEMU_IO -c "open -o cache-size=0 $TEST_IMG" -c 'write 0 64k' | _filter_qemu_io
|
||||
|
||||
# success, all done
|
||||
echo '*** done'
|
||||
rm -f $seq.full
|
||||
|
||||
@@ -26,4 +26,9 @@ read 65536/65536 bytes at offset 0
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 65536/65536 bytes at offset 0
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
|
||||
=== Testing minimal L2 cache and COW ===
|
||||
|
||||
wrote 65536/65536 bytes at offset 0
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
*** done
|
||||
Executable
+95
@@ -0,0 +1,95 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Test that temporary backing file overrides (on the command line or in
|
||||
# blockdev-add) don't replace the original path stored in the image during
|
||||
# header updates.
|
||||
#
|
||||
# Copyright (C) 2015 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=kwolf@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
|
||||
}
|
||||
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
# get standard environment, filters and checks
|
||||
. ./common.rc
|
||||
. ./common.filter
|
||||
. ./common.qemu
|
||||
|
||||
_supported_fmt qcow2
|
||||
_supported_proto generic
|
||||
_supported_os Linux
|
||||
|
||||
qemu_comm_method="monitor"
|
||||
|
||||
|
||||
TEST_IMG="$TEST_IMG.orig" _make_test_img 64M
|
||||
TEST_IMG="$TEST_IMG.base" _make_test_img 64M
|
||||
_make_test_img 64M
|
||||
_img_info | _filter_img_info
|
||||
|
||||
echo
|
||||
echo "=== HMP commit ==="
|
||||
echo
|
||||
# bdrv_make_empty() involves a header update for qcow2
|
||||
|
||||
# Test that a backing file isn't written
|
||||
_launch_qemu -drive file="$TEST_IMG",backing.file.filename="$TEST_IMG.base"
|
||||
_send_qemu_cmd $QEMU_HANDLE "commit ide0-hd0" "(qemu)"
|
||||
_send_qemu_cmd $QEMU_HANDLE '' '(qemu)'
|
||||
_cleanup_qemu
|
||||
_img_info | _filter_img_info
|
||||
|
||||
# Make sure that if there was a backing file that was just overridden on the
|
||||
# command line, that backing file is retained, with the right format
|
||||
_make_test_img -F raw -b "$TEST_IMG.orig" 64M
|
||||
_launch_qemu -drive file="$TEST_IMG",backing.file.filename="$TEST_IMG.base",backing.driver=$IMGFMT
|
||||
_send_qemu_cmd $QEMU_HANDLE "commit ide0-hd0" "(qemu)"
|
||||
_send_qemu_cmd $QEMU_HANDLE '' '(qemu)'
|
||||
_cleanup_qemu
|
||||
_img_info | _filter_img_info
|
||||
|
||||
echo
|
||||
echo "=== Marking image dirty (lazy refcounts) ==="
|
||||
echo
|
||||
|
||||
# Test that a backing file isn't written
|
||||
_make_test_img 64M
|
||||
$QEMU_IO -c "open -o backing.file.filename=$TEST_IMG.base,lazy-refcounts=on $TEST_IMG" -c "write 0 4k" | _filter_qemu_io
|
||||
_img_info | _filter_img_info
|
||||
|
||||
# Make sure that if there was a backing file that was just overridden on the
|
||||
# command line, that backing file is retained, with the right format
|
||||
_make_test_img -F raw -b "$TEST_IMG.orig" 64M
|
||||
$QEMU_IO -c "open -o backing.file.filename=$TEST_IMG.base,backing.driver=$IMGFMT,lazy-refcounts=on $TEST_IMG" -c "write 0 4k" | _filter_qemu_io
|
||||
_img_info | _filter_img_info
|
||||
|
||||
# success, all done
|
||||
echo '*** done'
|
||||
rm -f $seq.full
|
||||
status=0
|
||||
@@ -0,0 +1,43 @@
|
||||
QA output created by 130
|
||||
Formatting 'TEST_DIR/t.IMGFMT.orig', fmt=IMGFMT size=67108864
|
||||
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
image: TEST_DIR/t.IMGFMT
|
||||
file format: IMGFMT
|
||||
virtual size: 64M (67108864 bytes)
|
||||
|
||||
=== HMP commit ===
|
||||
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
(qemu) c[K[Dco[K[D[Dcom[K[D[D[Dcomm[K[D[D[D[Dcommi[K[D[D[D[D[Dcommit[K[D[D[D[D[D[Dcommit [K[D[D[D[D[D[D[Dcommit i[K[D[D[D[D[D[D[D[Dcommit id[K[D[D[D[D[D[D[D[D[Dcommit ide[K[D[D[D[D[D[D[D[D[D[Dcommit ide0[K[D[D[D[D[D[D[D[D[D[D[Dcommit ide0-[K[D[D[D[D[D[D[D[D[D[D[D[Dcommit ide0-h[K[D[D[D[D[D[D[D[D[D[D[D[D[Dcommit ide0-hd[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dcommit ide0-hd0[K
|
||||
(qemu)
|
||||
image: TEST_DIR/t.IMGFMT
|
||||
file format: IMGFMT
|
||||
virtual size: 64M (67108864 bytes)
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file='TEST_DIR/t.IMGFMT.orig' backing_fmt='raw'
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
(qemu) c[K[Dco[K[D[Dcom[K[D[D[Dcomm[K[D[D[D[Dcommi[K[D[D[D[D[Dcommit[K[D[D[D[D[D[Dcommit [K[D[D[D[D[D[D[Dcommit i[K[D[D[D[D[D[D[D[Dcommit id[K[D[D[D[D[D[D[D[D[Dcommit ide[K[D[D[D[D[D[D[D[D[D[Dcommit ide0[K[D[D[D[D[D[D[D[D[D[D[Dcommit ide0-[K[D[D[D[D[D[D[D[D[D[D[D[Dcommit ide0-h[K[D[D[D[D[D[D[D[D[D[D[D[D[Dcommit ide0-hd[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dcommit ide0-hd0[K
|
||||
(qemu)
|
||||
image: TEST_DIR/t.IMGFMT
|
||||
file format: IMGFMT
|
||||
virtual size: 64M (67108864 bytes)
|
||||
backing file: TEST_DIR/t.IMGFMT.orig
|
||||
backing file format: raw
|
||||
|
||||
=== Marking image dirty (lazy refcounts) ===
|
||||
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
wrote 4096/4096 bytes at offset 0
|
||||
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
image: TEST_DIR/t.IMGFMT
|
||||
file format: IMGFMT
|
||||
virtual size: 64M (67108864 bytes)
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file='TEST_DIR/t.IMGFMT.orig' backing_fmt='raw'
|
||||
wrote 4096/4096 bytes at offset 0
|
||||
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
image: TEST_DIR/t.IMGFMT
|
||||
file format: IMGFMT
|
||||
virtual size: 64M (67108864 bytes)
|
||||
backing file: TEST_DIR/t.IMGFMT.orig
|
||||
backing file format: raw
|
||||
*** done
|
||||
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Test mirror with unmap
|
||||
#
|
||||
# Copyright (C) 2015 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/>.
|
||||
#
|
||||
|
||||
import time
|
||||
import os
|
||||
import iotests
|
||||
from iotests import qemu_img, qemu_io
|
||||
|
||||
test_img = os.path.join(iotests.test_dir, 'test.img')
|
||||
target_img = os.path.join(iotests.test_dir, 'target.img')
|
||||
|
||||
class TestSingleDrive(iotests.QMPTestCase):
|
||||
image_len = 2 * 1024 * 1024 # MB
|
||||
|
||||
def setUp(self):
|
||||
# Write data to the image so we can compare later
|
||||
qemu_img('create', '-f', iotests.imgfmt, test_img, str(TestSingleDrive.image_len))
|
||||
qemu_io('-f', iotests.imgfmt, '-c', 'write -P0x5d 0 2M', test_img)
|
||||
|
||||
self.vm = iotests.VM().add_drive(test_img, 'discard=unmap')
|
||||
self.vm.launch()
|
||||
|
||||
def tearDown(self):
|
||||
self.vm.shutdown()
|
||||
os.remove(test_img)
|
||||
try:
|
||||
os.remove(target_img)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def test_mirror_discard(self):
|
||||
result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
|
||||
target=target_img)
|
||||
self.assert_qmp(result, 'return', {})
|
||||
self.vm.hmp_qemu_io('drive0', 'discard 0 64k')
|
||||
self.complete_and_wait('drive0')
|
||||
self.vm.shutdown()
|
||||
self.assertTrue(iotests.compare_images(test_img, target_img),
|
||||
'target image does not match source after mirroring')
|
||||
|
||||
if __name__ == '__main__':
|
||||
iotests.main(supported_fmts=['raw', 'qcow2'])
|
||||
@@ -0,0 +1,5 @@
|
||||
.
|
||||
----------------------------------------------------------------------
|
||||
Ran 1 tests
|
||||
|
||||
OK
|
||||
Executable
+54
@@ -0,0 +1,54 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Test VPC open of image with large Max Table Entries value.
|
||||
#
|
||||
# Copyright (C) 2015 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=jcody@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
|
||||
}
|
||||
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
# get standard environment, filters and checks
|
||||
. ./common.rc
|
||||
. ./common.filter
|
||||
|
||||
_supported_fmt vpc
|
||||
_supported_proto generic
|
||||
_supported_os Linux
|
||||
|
||||
_use_sample_img afl5.img.bz2
|
||||
|
||||
echo
|
||||
echo "=== Verify image open and failure ===="
|
||||
$QEMU_IMG info "$TEST_IMG" 2>&1| _filter_testdir
|
||||
|
||||
# success, all done
|
||||
echo "*** done"
|
||||
rm -f $seq.full
|
||||
status=0
|
||||
@@ -0,0 +1,5 @@
|
||||
QA output created by 135
|
||||
|
||||
=== Verify image open and failure ====
|
||||
qemu-img: Could not open 'TEST_DIR/afl5.img': Max Table Entries too large (1073741825)
|
||||
*** done
|
||||
@@ -124,3 +124,6 @@
|
||||
121 rw auto
|
||||
123 rw auto quick
|
||||
128 rw auto quick
|
||||
130 rw auto quick
|
||||
132 rw auto quick
|
||||
135 rw auto
|
||||
@@ -78,6 +78,23 @@ def create_image(name, size):
|
||||
i = i + 512
|
||||
file.close()
|
||||
|
||||
# Test if 'match' is a recursive subset of 'event'
|
||||
def event_match(event, match=None):
|
||||
if match is None:
|
||||
return True
|
||||
|
||||
for key in match:
|
||||
if key in event:
|
||||
if isinstance(event[key], dict):
|
||||
if not event_match(event[key], match[key]):
|
||||
return False
|
||||
elif event[key] != match[key]:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
class VM(object):
|
||||
'''A QEMU VM'''
|
||||
|
||||
@@ -92,6 +109,7 @@ class VM(object):
|
||||
'-machine', 'accel=qtest',
|
||||
'-display', 'none', '-vga', 'none']
|
||||
self._num_drives = 0
|
||||
self._events = []
|
||||
|
||||
# This can be used to add an unused monitor instance.
|
||||
def add_monitor_telnet(self, ip, port):
|
||||
@@ -202,14 +220,34 @@ class VM(object):
|
||||
|
||||
def get_qmp_event(self, wait=False):
|
||||
'''Poll for one queued QMP events and return it'''
|
||||
if len(self._events) > 0:
|
||||
return self._events.pop(0)
|
||||
return self._qmp.pull_event(wait=wait)
|
||||
|
||||
def get_qmp_events(self, wait=False):
|
||||
'''Poll for queued QMP events and return a list of dicts'''
|
||||
events = self._qmp.get_events(wait=wait)
|
||||
events.extend(self._events)
|
||||
del self._events[:]
|
||||
self._qmp.clear_events()
|
||||
return events
|
||||
|
||||
def event_wait(self, name='BLOCK_JOB_COMPLETED', timeout=60.0, match=None):
|
||||
# Search cached events
|
||||
for event in self._events:
|
||||
if (event['event'] == name) and event_match(event, match):
|
||||
self._events.remove(event)
|
||||
return event
|
||||
|
||||
# Poll for new events
|
||||
while True:
|
||||
event = self._qmp.pull_event(wait=timeout)
|
||||
if (event['event'] == name) and event_match(event, match):
|
||||
return event
|
||||
self._events.append(event)
|
||||
|
||||
return None
|
||||
|
||||
index_re = re.compile(r'([^\[]+)\[([^\]]+)\]')
|
||||
|
||||
class QMPTestCase(unittest.TestCase):
|
||||
@@ -288,6 +326,29 @@ class QMPTestCase(unittest.TestCase):
|
||||
self.assert_no_active_block_jobs()
|
||||
return event
|
||||
|
||||
def wait_ready(self, drive='drive0'):
|
||||
'''Wait until a block job BLOCK_JOB_READY event'''
|
||||
f = {'data': {'type': 'mirror', 'device': drive } }
|
||||
event = self.vm.event_wait(name='BLOCK_JOB_READY', match=f)
|
||||
|
||||
def wait_ready_and_cancel(self, drive='drive0'):
|
||||
self.wait_ready(drive=drive)
|
||||
event = self.cancel_and_wait(drive=drive)
|
||||
self.assertEquals(event['event'], 'BLOCK_JOB_COMPLETED')
|
||||
self.assert_qmp(event, 'data/type', 'mirror')
|
||||
self.assert_qmp(event, 'data/offset', event['data']['len'])
|
||||
|
||||
def complete_and_wait(self, drive='drive0', wait_ready=True):
|
||||
'''Complete a block job and wait for it to finish'''
|
||||
if wait_ready:
|
||||
self.wait_ready(drive=drive)
|
||||
|
||||
result = self.vm.qmp('block-job-complete', device=drive)
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
event = self.wait_until_completed(drive=drive)
|
||||
self.assert_qmp(event, 'data/type', 'mirror')
|
||||
|
||||
def notrun(reason):
|
||||
'''Skip this test suite'''
|
||||
# Each test in qemu-iotests has a number ("seq")
|
||||
|
||||
Binary file not shown.
@@ -1334,8 +1334,6 @@ static inline void tb_alloc_page(TranslationBlock *tb,
|
||||
p->first_tb = (TranslationBlock *)((uintptr_t)tb | n);
|
||||
invalidate_page_bitmap(p);
|
||||
|
||||
#if defined(TARGET_HAS_SMC) || 1
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
if (p->flags & PAGE_WRITE) {
|
||||
target_ulong addr;
|
||||
@@ -1371,8 +1369,6 @@ static inline void tb_alloc_page(TranslationBlock *tb,
|
||||
tlb_protect_code(page_addr);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* TARGET_HAS_SMC */
|
||||
}
|
||||
|
||||
/* add a new TB and link it to the physical page tables. phys_page2 is
|
||||
|
||||
@@ -128,6 +128,10 @@ static const int qcode_to_number[] = {
|
||||
|
||||
[Q_KEY_CODE_INSERT] = 0xd2,
|
||||
[Q_KEY_CODE_DELETE] = 0xd3,
|
||||
|
||||
[Q_KEY_CODE_RO] = 0x73,
|
||||
[Q_KEY_CODE_KP_COMMA] = 0x7e,
|
||||
|
||||
[Q_KEY_CODE_MAX] = 0,
|
||||
};
|
||||
|
||||
|
||||
@@ -511,6 +511,10 @@ static void handle_windowevent(SDL_Event *ev)
|
||||
{
|
||||
struct sdl2_console *scon = get_scon_from_window(ev->window.windowID);
|
||||
|
||||
if (!scon) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (ev->window.event) {
|
||||
case SDL_WINDOWEVENT_RESIZED:
|
||||
{
|
||||
|
||||
+5
-4
@@ -199,7 +199,7 @@ static void qemu_spice_create_update(SimpleSpiceDisplay *ssd)
|
||||
static const int blksize = 32;
|
||||
int blocks = (surface_width(ssd->ds) + blksize - 1) / blksize;
|
||||
int dirty_top[blocks];
|
||||
int y, yoff, x, xoff, blk, bw;
|
||||
int y, yoff1, yoff2, x, xoff, blk, bw;
|
||||
int bpp = surface_bytes_per_pixel(ssd->ds);
|
||||
uint8_t *guest, *mirror;
|
||||
|
||||
@@ -214,13 +214,14 @@ static void qemu_spice_create_update(SimpleSpiceDisplay *ssd)
|
||||
guest = surface_data(ssd->ds);
|
||||
mirror = (void *)pixman_image_get_data(ssd->mirror);
|
||||
for (y = ssd->dirty.top; y < ssd->dirty.bottom; y++) {
|
||||
yoff = y * surface_stride(ssd->ds);
|
||||
yoff1 = y * surface_stride(ssd->ds);
|
||||
yoff2 = y * pixman_image_get_stride(ssd->mirror);
|
||||
for (x = ssd->dirty.left; x < ssd->dirty.right; x += blksize) {
|
||||
xoff = x * bpp;
|
||||
blk = x / blksize;
|
||||
bw = MIN(blksize, ssd->dirty.right - x);
|
||||
if (memcmp(guest + yoff + xoff,
|
||||
mirror + yoff + xoff,
|
||||
if (memcmp(guest + yoff1 + xoff,
|
||||
mirror + yoff2 + xoff,
|
||||
bw * bpp) == 0) {
|
||||
if (dirty_top[blk] != -1) {
|
||||
QXLRect update = {
|
||||
|
||||
@@ -3482,7 +3482,14 @@ void vnc_display_open(const char *id, Error **errp)
|
||||
|
||||
h = strrchr(vnc, ':');
|
||||
if (h) {
|
||||
char *host = g_strndup(vnc, h - vnc);
|
||||
char *host;
|
||||
size_t hlen = h - vnc;
|
||||
|
||||
if (vnc[0] == '[' && vnc[hlen - 1] == ']') {
|
||||
host = g_strndup(vnc + 1, hlen - 2);
|
||||
} else {
|
||||
host = g_strndup(vnc, hlen);
|
||||
}
|
||||
qemu_opt_set(sopts, "host", host, &error_abort);
|
||||
qemu_opt_set(wsopts, "host", host, &error_abort);
|
||||
qemu_opt_set(sopts, "port", h+1, &error_abort);
|
||||
|
||||
+2
-2
@@ -94,7 +94,7 @@ static const uint8_t x_keycode_to_pc_keycode[115] = {
|
||||
*/
|
||||
|
||||
static const uint8_t evdev_keycode_to_pc_keycode[61] = {
|
||||
0, /* 97 EVDEV - RO ("Internet" Keyboards) */
|
||||
0x73, /* 97 EVDEV - RO ("Internet" Keyboards) */
|
||||
0, /* 98 EVDEV - KATA (Katakana) */
|
||||
0, /* 99 EVDEV - HIRA (Hiragana) */
|
||||
0x79, /* 100 EVDEV - HENK (Henkan) */
|
||||
@@ -126,7 +126,7 @@ static const uint8_t evdev_keycode_to_pc_keycode[61] = {
|
||||
0, /* 126 EVDEV - I126 ("Internet" Keyboards) */
|
||||
0, /* 127 EVDEV - PAUS */
|
||||
0, /* 128 EVDEV - ???? */
|
||||
0, /* 129 EVDEV - I129 ("Internet" Keyboards) */
|
||||
0x7e, /* 129 EVDEV - KP_COMMA (brazilian) */
|
||||
0xf1, /* 130 EVDEV - HNGL (Korean Hangul Latin toggle) */
|
||||
0xf2, /* 131 EVDEV - HJCV (Korean Hangul Hanja toggle) */
|
||||
0x7d, /* 132 AE13 (Yen)*/
|
||||
|
||||
Reference in new issue
Block a user