Compare commits
71 Commits
master
...
stable-2.7
Author | SHA1 | Date |
---|---|---|
Michael Roth | 0d83fccb4f | |
Ashijeet Acharya | 4dde694191 | |
Marc-André Lureau | 7d17d68971 | |
John Snow | 345f1cd9f6 | |
Mark Cave-Ayland | 8d5f2a7570 | |
John Snow | 5f20161cf3 | |
Stefan Hajnoczi | 05838b4688 | |
Thorsten Kohfeldt | 223d1a2da1 | |
Lin Ma | 7f7ac2141e | |
Paolo Bonzini | db1604cd60 | |
Eduardo Habkost | cc1fd25295 | |
Eduardo Habkost | ee99e42be4 | |
Peter Xu | 0ef167c907 | |
Adrian Bunk | 248a780fd3 | |
Peter Xu | 80f630be21 | |
Zhuang Yanying | 353801cde4 | |
Greg Kurz | c8a3159df4 | |
Max Reitz | 48fdfebab6 | |
Max Reitz | 6eb194ddd7 | |
Max Reitz | 7e278ef797 | |
Max Reitz | 6a5ea68e9e | |
Eric Blake | 31454ebde5 | |
Eric Blake | 5e4eb851dd | |
Eric Blake | dd11d33deb | |
Eric Blake | c4bf37e0b0 | |
Samuel Thibault | e9dbd28e2a | |
Greg Kurz | 92230a5963 | |
Kevin Wolf | 48b3aa20ae | |
Michael S. Tsirkin | f1372d6e14 | |
Michael S. Tsirkin | 63087cd74b | |
David Gibson | 9df69dcd14 | |
Daniel P. Berrange | 95a0638043 | |
Corey Minyard | 1790a9d77d | |
Alex Williamson | 1b16ded6a5 | |
Alex Williamson | ca83f87a66 | |
Prasad J Pandit | 2817466c55 | |
Alberto Garcia | e389e44a35 | |
Alberto Garcia | b1fdc94193 | |
Thomas Huth | 61781984db | |
Paolo Bonzini | 857efecf91 | |
Markus Armbruster | 99837b0d36 | |
Marc-André Lureau | b34c7bd463 | |
Marc-André Lureau | f3467f56c1 | |
Daniel P. Berrange | 5be5335661 | |
Emilio G. Cota | af29bd3193 | |
Emilio G. Cota | f72ca1ac6f | |
Eric Blake | 4d45fe11d1 | |
John Snow | 4a25ab2a04 | |
John Snow | 95200ebb50 | |
John Snow | 8e94512568 | |
Eric Blake | d40d148feb | |
Daniel P. Berrange | f9856029d5 | |
David Gibson | a3a254550b | |
Cornelia Huck | 533dedf059 | |
John Snow | 54c26b7340 | |
Fam Zheng | f5436d1dab | |
Fam Zheng | 3550eeafcd | |
Fam Zheng | 316c2c9448 | |
Daniel P. Berrange | 98b4465f7d | |
Paolo Bonzini | 8342e1240b | |
Prasad J Pandit | 0b6ab25367 | |
Prasad J Pandit | 742886578d | |
Rony Weng | 2f8e8c7396 | |
Lin Ma | 069e885d83 | |
Prasad J Pandit | bfb15f77bb | |
Li Qiang | c6a7b922f8 | |
Greg Kurz | d06c61f310 | |
Gonglei | 91a2f46297 | |
Ladi Prosek | 520d4b288f | |
Stefan Hajnoczi | 4b6542dd17 | |
Michael Roth | c1a77fd6fa |
|
@ -139,7 +139,6 @@ static void msmouse_chr_close (struct CharDriverState *chr)
|
|||
|
||||
qemu_input_handler_unregister(mouse->hs);
|
||||
g_free(mouse);
|
||||
g_free(chr);
|
||||
}
|
||||
|
||||
static QemuInputHandler msmouse_handler = {
|
||||
|
@ -159,6 +158,9 @@ static CharDriverState *qemu_chr_open_msmouse(const char *id,
|
|||
CharDriverState *chr;
|
||||
|
||||
chr = qemu_chr_alloc(common, errp);
|
||||
if (!chr) {
|
||||
return NULL;
|
||||
}
|
||||
chr->chr_write = msmouse_chr_write;
|
||||
chr->chr_close = msmouse_chr_close;
|
||||
chr->chr_accept_input = msmouse_chr_accept_input;
|
||||
|
|
|
@ -1296,6 +1296,11 @@ void blk_eject(BlockBackend *blk, bool eject_flag)
|
|||
if (bs) {
|
||||
bdrv_eject(bs, eject_flag);
|
||||
}
|
||||
|
||||
/* Whether or not we ejected on the backend,
|
||||
* the frontend experienced a tray event. */
|
||||
qapi_event_send_device_tray_moved(blk_name(blk),
|
||||
eject_flag, &error_abort);
|
||||
}
|
||||
|
||||
int blk_get_flags(BlockBackend *blk)
|
||||
|
@ -1624,28 +1629,6 @@ int blk_commit_all(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int blk_flush_all(void)
|
||||
{
|
||||
BlockBackend *blk = NULL;
|
||||
int result = 0;
|
||||
|
||||
while ((blk = blk_all_next(blk)) != NULL) {
|
||||
AioContext *aio_context = blk_get_aio_context(blk);
|
||||
int ret;
|
||||
|
||||
aio_context_acquire(aio_context);
|
||||
if (blk_is_inserted(blk)) {
|
||||
ret = blk_flush(blk);
|
||||
if (ret < 0 && !result) {
|
||||
result = ret;
|
||||
}
|
||||
}
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* throttling disk I/O limits */
|
||||
void blk_set_io_limits(BlockBackend *blk, ThrottleConfig *cfg)
|
||||
|
|
99
block/curl.c
99
block/curl.c
|
@ -73,7 +73,6 @@ static CURLMcode __curl_multi_socket_action(CURLM *multi_handle,
|
|||
|
||||
#define CURL_NUM_STATES 8
|
||||
#define CURL_NUM_ACB 8
|
||||
#define SECTOR_SIZE 512
|
||||
#define READ_AHEAD_DEFAULT (256 * 1024)
|
||||
#define CURL_TIMEOUT_DEFAULT 5
|
||||
#define CURL_TIMEOUT_MAX 10000
|
||||
|
@ -106,12 +105,17 @@ typedef struct CURLAIOCB {
|
|||
size_t end;
|
||||
} CURLAIOCB;
|
||||
|
||||
typedef struct CURLSocket {
|
||||
int fd;
|
||||
QLIST_ENTRY(CURLSocket) next;
|
||||
} CURLSocket;
|
||||
|
||||
typedef struct CURLState
|
||||
{
|
||||
struct BDRVCURLState *s;
|
||||
CURLAIOCB *acb[CURL_NUM_ACB];
|
||||
CURL *curl;
|
||||
curl_socket_t sock_fd;
|
||||
QLIST_HEAD(, CURLSocket) sockets;
|
||||
char *orig_buf;
|
||||
size_t buf_start;
|
||||
size_t buf_off;
|
||||
|
@ -165,10 +169,27 @@ static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
|
|||
{
|
||||
BDRVCURLState *s;
|
||||
CURLState *state = NULL;
|
||||
CURLSocket *socket;
|
||||
|
||||
curl_easy_getinfo(curl, CURLINFO_PRIVATE, (char **)&state);
|
||||
state->sock_fd = fd;
|
||||
s = state->s;
|
||||
|
||||
QLIST_FOREACH(socket, &state->sockets, next) {
|
||||
if (socket->fd == fd) {
|
||||
if (action == CURL_POLL_REMOVE) {
|
||||
QLIST_REMOVE(socket, next);
|
||||
g_free(socket);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!socket) {
|
||||
socket = g_new0(CURLSocket, 1);
|
||||
socket->fd = fd;
|
||||
QLIST_INSERT_HEAD(&state->sockets, socket, next);
|
||||
}
|
||||
socket = NULL;
|
||||
|
||||
DPRINTF("CURL (AIO): Sock action %d on fd %d\n", action, (int)fd);
|
||||
switch (action) {
|
||||
case CURL_POLL_IN:
|
||||
|
@ -214,12 +235,13 @@ static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
|
|||
|
||||
DPRINTF("CURL: Just reading %zd bytes\n", realsize);
|
||||
|
||||
if (!s || !s->orig_buf)
|
||||
return 0;
|
||||
if (!s || !s->orig_buf) {
|
||||
goto read_end;
|
||||
}
|
||||
|
||||
if (s->buf_off >= s->buf_len) {
|
||||
/* buffer full, read nothing */
|
||||
return 0;
|
||||
goto read_end;
|
||||
}
|
||||
realsize = MIN(realsize, s->buf_len - s->buf_off);
|
||||
memcpy(s->orig_buf + s->buf_off, ptr, realsize);
|
||||
|
@ -232,15 +254,26 @@ static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
|
|||
continue;
|
||||
|
||||
if ((s->buf_off >= acb->end)) {
|
||||
size_t request_length = acb->nb_sectors * BDRV_SECTOR_SIZE;
|
||||
|
||||
qemu_iovec_from_buf(acb->qiov, 0, s->orig_buf + acb->start,
|
||||
acb->end - acb->start);
|
||||
|
||||
if (acb->end - acb->start < request_length) {
|
||||
size_t offset = acb->end - acb->start;
|
||||
qemu_iovec_memset(acb->qiov, offset, 0,
|
||||
request_length - offset);
|
||||
}
|
||||
|
||||
acb->common.cb(acb->common.opaque, 0);
|
||||
qemu_aio_unref(acb);
|
||||
s->acb[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return realsize;
|
||||
read_end:
|
||||
/* curl will error out if we do not return this value */
|
||||
return size * nmemb;
|
||||
}
|
||||
|
||||
static int curl_find_buf(BDRVCURLState *s, size_t start, size_t len,
|
||||
|
@ -248,6 +281,8 @@ static int curl_find_buf(BDRVCURLState *s, size_t start, size_t len,
|
|||
{
|
||||
int i;
|
||||
size_t end = start + len;
|
||||
size_t clamped_end = MIN(end, s->len);
|
||||
size_t clamped_len = clamped_end - start;
|
||||
|
||||
for (i=0; i<CURL_NUM_STATES; i++) {
|
||||
CURLState *state = &s->states[i];
|
||||
|
@ -262,12 +297,15 @@ static int curl_find_buf(BDRVCURLState *s, size_t start, size_t len,
|
|||
// Does the existing buffer cover our section?
|
||||
if ((start >= state->buf_start) &&
|
||||
(start <= buf_end) &&
|
||||
(end >= state->buf_start) &&
|
||||
(end <= buf_end))
|
||||
(clamped_end >= state->buf_start) &&
|
||||
(clamped_end <= buf_end))
|
||||
{
|
||||
char *buf = state->orig_buf + (start - state->buf_start);
|
||||
|
||||
qemu_iovec_from_buf(acb->qiov, 0, buf, len);
|
||||
qemu_iovec_from_buf(acb->qiov, 0, buf, clamped_len);
|
||||
if (clamped_len < len) {
|
||||
qemu_iovec_memset(acb->qiov, clamped_len, 0, len - clamped_len);
|
||||
}
|
||||
acb->common.cb(acb->common.opaque, 0);
|
||||
|
||||
return FIND_RET_OK;
|
||||
|
@ -277,13 +315,13 @@ static int curl_find_buf(BDRVCURLState *s, size_t start, size_t len,
|
|||
if (state->in_use &&
|
||||
(start >= state->buf_start) &&
|
||||
(start <= buf_fend) &&
|
||||
(end >= state->buf_start) &&
|
||||
(end <= buf_fend))
|
||||
(clamped_end >= state->buf_start) &&
|
||||
(clamped_end <= buf_fend))
|
||||
{
|
||||
int j;
|
||||
|
||||
acb->start = start - state->buf_start;
|
||||
acb->end = acb->start + len;
|
||||
acb->end = acb->start + clamped_len;
|
||||
|
||||
for (j=0; j<CURL_NUM_ACB; j++) {
|
||||
if (!state->acb[j]) {
|
||||
|
@ -353,6 +391,7 @@ static void curl_multi_check_completion(BDRVCURLState *s)
|
|||
static void curl_multi_do(void *arg)
|
||||
{
|
||||
CURLState *s = (CURLState *)arg;
|
||||
CURLSocket *socket, *next_socket;
|
||||
int running;
|
||||
int r;
|
||||
|
||||
|
@ -360,10 +399,13 @@ static void curl_multi_do(void *arg)
|
|||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
r = curl_multi_socket_action(s->s->multi, s->sock_fd, 0, &running);
|
||||
} while(r == CURLM_CALL_MULTI_PERFORM);
|
||||
|
||||
/* Need to use _SAFE because curl_multi_socket_action() may trigger
|
||||
* curl_sock_cb() which might modify this list */
|
||||
QLIST_FOREACH_SAFE(socket, &s->sockets, next, next_socket) {
|
||||
do {
|
||||
r = curl_multi_socket_action(s->s->multi, socket->fd, 0, &running);
|
||||
} while (r == CURLM_CALL_MULTI_PERFORM);
|
||||
}
|
||||
}
|
||||
|
||||
static void curl_multi_read(void *arg)
|
||||
|
@ -467,6 +509,7 @@ static CURLState *curl_init_state(BlockDriverState *bs, BDRVCURLState *s)
|
|||
#endif
|
||||
}
|
||||
|
||||
QLIST_INIT(&state->sockets);
|
||||
state->s = s;
|
||||
|
||||
return state;
|
||||
|
@ -476,6 +519,14 @@ static void curl_clean_state(CURLState *s)
|
|||
{
|
||||
if (s->s->multi)
|
||||
curl_multi_remove_handle(s->s->multi, s->curl);
|
||||
|
||||
while (!QLIST_EMPTY(&s->sockets)) {
|
||||
CURLSocket *socket = QLIST_FIRST(&s->sockets);
|
||||
|
||||
QLIST_REMOVE(socket, next);
|
||||
g_free(socket);
|
||||
}
|
||||
|
||||
s->in_use = 0;
|
||||
}
|
||||
|
||||
|
@ -725,12 +776,12 @@ static void curl_readv_bh_cb(void *p)
|
|||
qemu_bh_delete(acb->bh);
|
||||
acb->bh = NULL;
|
||||
|
||||
size_t start = acb->sector_num * SECTOR_SIZE;
|
||||
size_t start = acb->sector_num * BDRV_SECTOR_SIZE;
|
||||
size_t end;
|
||||
|
||||
// In case we have the requested data already (e.g. read-ahead),
|
||||
// we can just call the callback and be done.
|
||||
switch (curl_find_buf(s, start, acb->nb_sectors * SECTOR_SIZE, acb)) {
|
||||
switch (curl_find_buf(s, start, acb->nb_sectors * BDRV_SECTOR_SIZE, acb)) {
|
||||
case FIND_RET_OK:
|
||||
qemu_aio_unref(acb);
|
||||
// fall through
|
||||
|
@ -749,13 +800,13 @@ static void curl_readv_bh_cb(void *p)
|
|||
}
|
||||
|
||||
acb->start = 0;
|
||||
acb->end = (acb->nb_sectors * SECTOR_SIZE);
|
||||
acb->end = MIN(acb->nb_sectors * BDRV_SECTOR_SIZE, s->len - start);
|
||||
|
||||
state->buf_off = 0;
|
||||
g_free(state->orig_buf);
|
||||
state->buf_start = start;
|
||||
state->buf_len = acb->end + s->readahead_size;
|
||||
end = MIN(start + state->buf_len, s->len) - 1;
|
||||
state->buf_len = MIN(acb->end + s->readahead_size, s->len - start);
|
||||
end = start + state->buf_len - 1;
|
||||
state->orig_buf = g_try_malloc(state->buf_len);
|
||||
if (state->buf_len && state->orig_buf == NULL) {
|
||||
curl_clean_state(state);
|
||||
|
@ -766,8 +817,8 @@ static void curl_readv_bh_cb(void *p)
|
|||
state->acb[0] = acb;
|
||||
|
||||
snprintf(state->range, 127, "%zd-%zd", start, end);
|
||||
DPRINTF("CURL (AIO): Reading %d at %zd (%s)\n",
|
||||
(acb->nb_sectors * SECTOR_SIZE), start, state->range);
|
||||
DPRINTF("CURL (AIO): Reading %llu at %zd (%s)\n",
|
||||
(acb->nb_sectors * BDRV_SECTOR_SIZE), start, state->range);
|
||||
curl_easy_setopt(state->curl, CURLOPT_RANGE, state->range);
|
||||
|
||||
curl_multi_add_handle(s->multi, state->curl);
|
||||
|
|
87
block/io.c
87
block/io.c
|
@ -1179,6 +1179,8 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
|
|||
int max_write_zeroes = MIN_NON_ZERO(bs->bl.max_pwrite_zeroes, INT_MAX);
|
||||
int alignment = MAX(bs->bl.pwrite_zeroes_alignment,
|
||||
bs->bl.request_alignment);
|
||||
int max_transfer = MIN_NON_ZERO(bs->bl.max_transfer,
|
||||
MAX_WRITE_ZEROES_BOUNCE_BUFFER);
|
||||
|
||||
assert(alignment % bs->bl.request_alignment == 0);
|
||||
head = offset % alignment;
|
||||
|
@ -1194,9 +1196,12 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
|
|||
* boundaries.
|
||||
*/
|
||||
if (head) {
|
||||
/* Make a small request up to the first aligned sector. */
|
||||
num = MIN(count, alignment - head);
|
||||
head = 0;
|
||||
/* Make a small request up to the first aligned sector. For
|
||||
* convenience, limit this request to max_transfer even if
|
||||
* we don't need to fall back to writes. */
|
||||
num = MIN(MIN(count, max_transfer), alignment - head);
|
||||
head = (head + num) % alignment;
|
||||
assert(num < max_write_zeroes);
|
||||
} else if (tail && num > alignment) {
|
||||
/* Shorten the request to the last aligned sector. */
|
||||
num -= tail;
|
||||
|
@ -1222,8 +1227,6 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
|
|||
|
||||
if (ret == -ENOTSUP) {
|
||||
/* Fall back to bounce buffer if write zeroes is unsupported */
|
||||
int max_transfer = MIN_NON_ZERO(bs->bl.max_transfer,
|
||||
MAX_WRITE_ZEROES_BOUNCE_BUFFER);
|
||||
BdrvRequestFlags write_flags = flags & ~BDRV_REQ_ZERO_WRITE;
|
||||
|
||||
if ((flags & BDRV_REQ_FUA) &&
|
||||
|
@ -1615,6 +1618,31 @@ int coroutine_fn bdrv_co_pwrite_zeroes(BdrvChild *child, int64_t offset,
|
|||
BDRV_REQ_ZERO_WRITE | flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush ALL BDSes regardless of if they are reachable via a BlkBackend or not.
|
||||
*/
|
||||
int bdrv_flush_all(void)
|
||||
{
|
||||
BdrvNextIterator it;
|
||||
BlockDriverState *bs = NULL;
|
||||
int result = 0;
|
||||
|
||||
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
|
||||
AioContext *aio_context = bdrv_get_aio_context(bs);
|
||||
int ret;
|
||||
|
||||
aio_context_acquire(aio_context);
|
||||
ret = bdrv_flush(bs);
|
||||
if (ret < 0 && !result) {
|
||||
result = ret;
|
||||
}
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
typedef struct BdrvCoGetBlockStatusData {
|
||||
BlockDriverState *bs;
|
||||
BlockDriverState *base;
|
||||
|
@ -2356,7 +2384,9 @@ flush_parent:
|
|||
ret = bs->file ? bdrv_co_flush(bs->file->bs) : 0;
|
||||
out:
|
||||
/* Notify any pending flushes that we have completed */
|
||||
bs->flushed_gen = current_gen;
|
||||
if (ret == 0) {
|
||||
bs->flushed_gen = current_gen;
|
||||
}
|
||||
bs->active_flush_req = NULL;
|
||||
/* Return value is ignored - it's ok if wait queue is empty */
|
||||
qemu_co_queue_next(&bs->flush_queue);
|
||||
|
@ -2407,7 +2437,7 @@ int coroutine_fn bdrv_co_pdiscard(BlockDriverState *bs, int64_t offset,
|
|||
{
|
||||
BdrvTrackedRequest req;
|
||||
int max_pdiscard, ret;
|
||||
int head, align;
|
||||
int head, tail, align;
|
||||
|
||||
if (!bs->drv) {
|
||||
return -ENOMEDIUM;
|
||||
|
@ -2430,19 +2460,15 @@ int coroutine_fn bdrv_co_pdiscard(BlockDriverState *bs, int64_t offset,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Discard is advisory, so ignore any unaligned head or tail */
|
||||
/* Discard is advisory, but some devices track and coalesce
|
||||
* unaligned requests, so we must pass everything down rather than
|
||||
* round here. Still, most devices will just silently ignore
|
||||
* unaligned requests (by returning -ENOTSUP), so we must fragment
|
||||
* the request accordingly. */
|
||||
align = MAX(bs->bl.pdiscard_alignment, bs->bl.request_alignment);
|
||||
assert(align % bs->bl.request_alignment == 0);
|
||||
head = offset % align;
|
||||
if (head) {
|
||||
head = MIN(count, align - head);
|
||||
count -= head;
|
||||
offset += head;
|
||||
}
|
||||
count = QEMU_ALIGN_DOWN(count, align);
|
||||
if (!count) {
|
||||
return 0;
|
||||
}
|
||||
tail = (offset + count) % align;
|
||||
|
||||
tracked_request_begin(&req, bs, offset, count, BDRV_TRACKED_DISCARD);
|
||||
|
||||
|
@ -2453,11 +2479,34 @@ int coroutine_fn bdrv_co_pdiscard(BlockDriverState *bs, int64_t offset,
|
|||
|
||||
max_pdiscard = QEMU_ALIGN_DOWN(MIN_NON_ZERO(bs->bl.max_pdiscard, INT_MAX),
|
||||
align);
|
||||
assert(max_pdiscard);
|
||||
assert(max_pdiscard >= bs->bl.request_alignment);
|
||||
|
||||
while (count > 0) {
|
||||
int ret;
|
||||
int num = MIN(count, max_pdiscard);
|
||||
int num = count;
|
||||
|
||||
if (head) {
|
||||
/* Make small requests to get to alignment boundaries. */
|
||||
num = MIN(count, align - head);
|
||||
if (!QEMU_IS_ALIGNED(num, bs->bl.request_alignment)) {
|
||||
num %= bs->bl.request_alignment;
|
||||
}
|
||||
head = (head + num) % align;
|
||||
assert(num < max_pdiscard);
|
||||
} else if (tail) {
|
||||
if (num > align) {
|
||||
/* Shorten the request to the last aligned cluster. */
|
||||
num -= tail;
|
||||
} else if (!QEMU_IS_ALIGNED(tail, bs->bl.request_alignment) &&
|
||||
tail > bs->bl.request_alignment) {
|
||||
tail %= bs->bl.request_alignment;
|
||||
num -= tail;
|
||||
}
|
||||
}
|
||||
/* limit request size */
|
||||
if (num > max_pdiscard) {
|
||||
num = max_pdiscard;
|
||||
}
|
||||
|
||||
if (bs->drv->bdrv_co_pdiscard) {
|
||||
ret = bs->drv->bdrv_co_pdiscard(bs, offset, num);
|
||||
|
|
|
@ -1048,7 +1048,9 @@ coroutine_fn iscsi_co_pdiscard(BlockDriverState *bs, int64_t offset, int count)
|
|||
struct IscsiTask iTask;
|
||||
struct unmap_list list;
|
||||
|
||||
assert(is_byte_request_lun_aligned(offset, count, iscsilun));
|
||||
if (!is_byte_request_lun_aligned(offset, count, iscsilun)) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (!iscsilun->lbp.lbpu) {
|
||||
/* UNMAP is not supported by the target */
|
||||
|
@ -1813,19 +1815,22 @@ static void iscsi_refresh_limits(BlockDriverState *bs, Error **errp)
|
|||
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
uint64_t max_xfer_len = iscsilun->use_16_for_rw ? 0xffffffff : 0xffff;
|
||||
unsigned int block_size = MAX(BDRV_SECTOR_SIZE, iscsilun->block_size);
|
||||
|
||||
bs->bl.request_alignment = iscsilun->block_size;
|
||||
assert(iscsilun->block_size >= BDRV_SECTOR_SIZE || bs->sg);
|
||||
|
||||
bs->bl.request_alignment = block_size;
|
||||
|
||||
if (iscsilun->bl.max_xfer_len) {
|
||||
max_xfer_len = MIN(max_xfer_len, iscsilun->bl.max_xfer_len);
|
||||
}
|
||||
|
||||
if (max_xfer_len * iscsilun->block_size < INT_MAX) {
|
||||
if (max_xfer_len * block_size < INT_MAX) {
|
||||
bs->bl.max_transfer = max_xfer_len * iscsilun->block_size;
|
||||
}
|
||||
|
||||
if (iscsilun->lbp.lbpu) {
|
||||
if (iscsilun->bl.max_unmap < 0xffffffff / iscsilun->block_size) {
|
||||
if (iscsilun->bl.max_unmap < 0xffffffff / block_size) {
|
||||
bs->bl.max_pdiscard =
|
||||
iscsilun->bl.max_unmap * iscsilun->block_size;
|
||||
}
|
||||
|
@ -1835,7 +1840,7 @@ static void iscsi_refresh_limits(BlockDriverState *bs, Error **errp)
|
|||
bs->bl.pdiscard_alignment = iscsilun->block_size;
|
||||
}
|
||||
|
||||
if (iscsilun->bl.max_ws_len < 0xffffffff / iscsilun->block_size) {
|
||||
if (iscsilun->bl.max_ws_len < 0xffffffff / block_size) {
|
||||
bs->bl.max_pwrite_zeroes =
|
||||
iscsilun->bl.max_ws_len * iscsilun->block_size;
|
||||
}
|
||||
|
@ -1846,7 +1851,7 @@ static void iscsi_refresh_limits(BlockDriverState *bs, Error **errp)
|
|||
bs->bl.pwrite_zeroes_alignment = iscsilun->block_size;
|
||||
}
|
||||
if (iscsilun->bl.opt_xfer_len &&
|
||||
iscsilun->bl.opt_xfer_len < INT_MAX / iscsilun->block_size) {
|
||||
iscsilun->bl.opt_xfer_len < INT_MAX / block_size) {
|
||||
bs->bl.opt_transfer = pow2floor(iscsilun->bl.opt_xfer_len *
|
||||
iscsilun->block_size);
|
||||
}
|
||||
|
|
|
@ -427,7 +427,7 @@ static int coroutine_fn do_perform_cow(BlockDriverState *bs,
|
|||
|
||||
if (bs->encrypted) {
|
||||
Error *err = NULL;
|
||||
int64_t sector = (cluster_offset + offset_in_cluster)
|
||||
int64_t sector = (src_cluster_offset + offset_in_cluster)
|
||||
>> BDRV_SECTOR_BITS;
|
||||
assert(s->cipher);
|
||||
assert((offset_in_cluster & ~BDRV_SECTOR_MASK) == 0);
|
||||
|
|
|
@ -1204,6 +1204,7 @@ static void qcow2_refresh_limits(BlockDriverState *bs, Error **errp)
|
|||
bs->bl.request_alignment = BDRV_SECTOR_SIZE;
|
||||
}
|
||||
bs->bl.pwrite_zeroes_alignment = s->cluster_size;
|
||||
bs->bl.pdiscard_alignment = s->cluster_size;
|
||||
}
|
||||
|
||||
static int qcow2_set_key(BlockDriverState *bs, const char *key)
|
||||
|
@ -2485,6 +2486,11 @@ static coroutine_fn int qcow2_co_pdiscard(BlockDriverState *bs,
|
|||
int ret;
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
|
||||
if (!QEMU_IS_ALIGNED(offset | count, s->cluster_size)) {
|
||||
assert(count < s->cluster_size);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
qemu_co_mutex_lock(&s->lock);
|
||||
ret = qcow2_discard_clusters(bs, offset, count >> BDRV_SECTOR_BITS,
|
||||
QCOW2_DISCARD_REQUEST, false);
|
||||
|
|
|
@ -737,7 +737,7 @@ static BlockAIOCB *qemu_rbd_aio_readv(BlockDriverState *bs,
|
|||
void *opaque)
|
||||
{
|
||||
return rbd_start_aio(bs, sector_num << BDRV_SECTOR_BITS, qiov,
|
||||
nb_sectors << BDRV_SECTOR_BITS, cb, opaque,
|
||||
(int64_t) nb_sectors << BDRV_SECTOR_BITS, cb, opaque,
|
||||
RBD_AIO_READ);
|
||||
}
|
||||
|
||||
|
@ -749,7 +749,7 @@ static BlockAIOCB *qemu_rbd_aio_writev(BlockDriverState *bs,
|
|||
void *opaque)
|
||||
{
|
||||
return rbd_start_aio(bs, sector_num << BDRV_SECTOR_BITS, qiov,
|
||||
nb_sectors << BDRV_SECTOR_BITS, cb, opaque,
|
||||
(int64_t) nb_sectors << BDRV_SECTOR_BITS, cb, opaque,
|
||||
RBD_AIO_WRITE);
|
||||
}
|
||||
|
||||
|
|
|
@ -2820,8 +2820,9 @@ static coroutine_fn int sd_co_pdiscard(BlockDriverState *bs, int64_t offset,
|
|||
iov.iov_len = sizeof(zero);
|
||||
discard_iov.iov = &iov;
|
||||
discard_iov.niov = 1;
|
||||
assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
|
||||
assert((count & (BDRV_SECTOR_SIZE - 1)) == 0);
|
||||
if (!QEMU_IS_ALIGNED(offset | count, BDRV_SECTOR_SIZE)) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
acb = sd_aio_setup(bs, &discard_iov, offset >> BDRV_SECTOR_BITS,
|
||||
count >> BDRV_SECTOR_BITS);
|
||||
acb->aiocb_type = AIOCB_DISCARD_OBJ;
|
||||
|
|
|
@ -168,6 +168,22 @@ static BlockBackend *throttle_group_next_blk(BlockBackend *blk)
|
|||
return blk_by_public(next);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return whether a BlockBackend has pending requests.
|
||||
*
|
||||
* This assumes that tg->lock is held.
|
||||
*
|
||||
* @blk: the BlockBackend
|
||||
* @is_write: the type of operation (read/write)
|
||||
* @ret: whether the BlockBackend has pending requests.
|
||||
*/
|
||||
static inline bool blk_has_pending_reqs(BlockBackend *blk,
|
||||
bool is_write)
|
||||
{
|
||||
const BlockBackendPublic *blkp = blk_get_public(blk);
|
||||
return blkp->pending_reqs[is_write];
|
||||
}
|
||||
|
||||
/* Return the next BlockBackend in the round-robin sequence with pending I/O
|
||||
* requests.
|
||||
*
|
||||
|
@ -188,7 +204,7 @@ static BlockBackend *next_throttle_token(BlockBackend *blk, bool is_write)
|
|||
|
||||
/* get next bs round in round robin style */
|
||||
token = throttle_group_next_blk(token);
|
||||
while (token != start && !blkp->pending_reqs[is_write]) {
|
||||
while (token != start && !blk_has_pending_reqs(token, is_write)) {
|
||||
token = throttle_group_next_blk(token);
|
||||
}
|
||||
|
||||
|
@ -196,10 +212,13 @@ static BlockBackend *next_throttle_token(BlockBackend *blk, bool is_write)
|
|||
* then decide the token is the current bs because chances are
|
||||
* the current bs get the current request queued.
|
||||
*/
|
||||
if (token == start && !blkp->pending_reqs[is_write]) {
|
||||
if (token == start && !blk_has_pending_reqs(token, is_write)) {
|
||||
token = blk;
|
||||
}
|
||||
|
||||
/* Either we return the original BB, or one with pending requests */
|
||||
assert(token == blk || blk_has_pending_reqs(token, is_write));
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
|
@ -257,7 +276,7 @@ static void schedule_next_request(BlockBackend *blk, bool is_write)
|
|||
|
||||
/* Check if there's any pending request to schedule next */
|
||||
token = next_throttle_token(blk, is_write);
|
||||
if (!blkp->pending_reqs[is_write]) {
|
||||
if (!blk_has_pending_reqs(token, is_write)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -271,7 +290,7 @@ static void schedule_next_request(BlockBackend *blk, bool is_write)
|
|||
qemu_co_queue_next(&blkp->throttled_reqs[is_write])) {
|
||||
token = blk;
|
||||
} else {
|
||||
ThrottleTimers *tt = &blkp->throttle_timers;
|
||||
ThrottleTimers *tt = &blk_get_public(token)->throttle_timers;
|
||||
int64_t now = qemu_clock_get_ns(tt->clock_type);
|
||||
timer_mod(tt->timers[is_write], now + 1);
|
||||
tg->any_timer_armed[is_write] = true;
|
||||
|
|
4
cpus.c
4
cpus.c
|
@ -745,7 +745,7 @@ static int do_vm_stop(RunState state)
|
|||
}
|
||||
|
||||
bdrv_drain_all();
|
||||
ret = blk_flush_all();
|
||||
ret = bdrv_flush_all();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1488,7 +1488,7 @@ int vm_stop_force_state(RunState state)
|
|||
bdrv_drain_all();
|
||||
/* Make sure to return an error if the flush in a previous vm_stop()
|
||||
* failed. */
|
||||
return blk_flush_all();
|
||||
return bdrv_flush_all();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -192,6 +192,12 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
|||
}
|
||||
|
||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
if (ctx->blocksize != XTS_BLOCK_SIZE) {
|
||||
error_setg(errp,
|
||||
"Cipher block size %zu must equal XTS block size %d",
|
||||
ctx->blocksize, XTS_BLOCK_SIZE);
|
||||
goto error;
|
||||
}
|
||||
ctx->iv = g_new0(uint8_t, ctx->blocksize);
|
||||
}
|
||||
|
||||
|
|
|
@ -361,6 +361,13 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
|||
goto error;
|
||||
}
|
||||
|
||||
if (mode == QCRYPTO_CIPHER_MODE_XTS &&
|
||||
ctx->blocksize != XTS_BLOCK_SIZE) {
|
||||
error_setg(errp, "Cipher block size %zu must equal XTS block size %d",
|
||||
ctx->blocksize, XTS_BLOCK_SIZE);
|
||||
goto error;
|
||||
}
|
||||
|
||||
ctx->iv = g_new0(uint8_t, ctx->blocksize);
|
||||
cipher->opaque = ctx;
|
||||
|
||||
|
@ -456,11 +463,6 @@ int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
|
|||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_MODE_XTS:
|
||||
if (ctx->blocksize != XTS_BLOCK_SIZE) {
|
||||
error_setg(errp, "Block size must be %d not %zu",
|
||||
XTS_BLOCK_SIZE, ctx->blocksize);
|
||||
return -1;
|
||||
}
|
||||
xts_decrypt(ctx->ctx, ctx->ctx_tweak,
|
||||
ctx->alg_encrypt_wrapper, ctx->alg_decrypt_wrapper,
|
||||
ctx->iv, len, out, in);
|
||||
|
|
|
@ -73,6 +73,7 @@ typedef struct {
|
|||
AioContext *ctx;
|
||||
BlockAIOCB *acb;
|
||||
QEMUSGList *sg;
|
||||
uint32_t align;
|
||||
uint64_t offset;
|
||||
DMADirection dir;
|
||||
int sg_cur_index;
|
||||
|
@ -160,8 +161,9 @@ static void dma_blk_cb(void *opaque, int ret)
|
|||
return;
|
||||
}
|
||||
|
||||
if (dbs->iov.size & ~BDRV_SECTOR_MASK) {
|
||||
qemu_iovec_discard_back(&dbs->iov, dbs->iov.size & ~BDRV_SECTOR_MASK);
|
||||
if (!QEMU_IS_ALIGNED(dbs->iov.size, dbs->align)) {
|
||||
qemu_iovec_discard_back(&dbs->iov,
|
||||
QEMU_ALIGN_DOWN(dbs->iov.size, dbs->align));
|
||||
}
|
||||
|
||||
dbs->acb = dbs->io_func(dbs->offset, &dbs->iov,
|
||||
|
@ -199,7 +201,7 @@ static const AIOCBInfo dma_aiocb_info = {
|
|||
};
|
||||
|
||||
BlockAIOCB *dma_blk_io(AioContext *ctx,
|
||||
QEMUSGList *sg, uint64_t offset,
|
||||
QEMUSGList *sg, uint64_t offset, uint32_t align,
|
||||
DMAIOFunc *io_func, void *io_func_opaque,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque, DMADirection dir)
|
||||
|
@ -212,6 +214,7 @@ BlockAIOCB *dma_blk_io(AioContext *ctx,
|
|||
dbs->sg = sg;
|
||||
dbs->ctx = ctx;
|
||||
dbs->offset = offset;
|
||||
dbs->align = align;
|
||||
dbs->sg_cur_index = 0;
|
||||
dbs->sg_cur_byte = 0;
|
||||
dbs->dir = dir;
|
||||
|
@ -234,11 +237,11 @@ BlockAIOCB *dma_blk_read_io_func(int64_t offset, QEMUIOVector *iov,
|
|||
}
|
||||
|
||||
BlockAIOCB *dma_blk_read(BlockBackend *blk,
|
||||
QEMUSGList *sg, uint64_t offset,
|
||||
QEMUSGList *sg, uint64_t offset, uint32_t align,
|
||||
void (*cb)(void *opaque, int ret), void *opaque)
|
||||
{
|
||||
return dma_blk_io(blk_get_aio_context(blk),
|
||||
sg, offset, dma_blk_read_io_func, blk, cb, opaque,
|
||||
return dma_blk_io(blk_get_aio_context(blk), sg, offset, align,
|
||||
dma_blk_read_io_func, blk, cb, opaque,
|
||||
DMA_DIRECTION_FROM_DEVICE);
|
||||
}
|
||||
|
||||
|
@ -252,11 +255,11 @@ BlockAIOCB *dma_blk_write_io_func(int64_t offset, QEMUIOVector *iov,
|
|||
}
|
||||
|
||||
BlockAIOCB *dma_blk_write(BlockBackend *blk,
|
||||
QEMUSGList *sg, uint64_t offset,
|
||||
QEMUSGList *sg, uint64_t offset, uint32_t align,
|
||||
void (*cb)(void *opaque, int ret), void *opaque)
|
||||
{
|
||||
return dma_blk_io(blk_get_aio_context(blk),
|
||||
sg, offset, dma_blk_write_io_func, blk, cb, opaque,
|
||||
return dma_blk_io(blk_get_aio_context(blk), sg, offset, align,
|
||||
dma_blk_write_io_func, blk, cb, opaque,
|
||||
DMA_DIRECTION_TO_DEVICE);
|
||||
}
|
||||
|
||||
|
|
1
hmp.c
1
hmp.c
|
@ -1284,6 +1284,7 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict)
|
|||
break;
|
||||
case MIGRATION_PARAMETER_CPU_THROTTLE_INCREMENT:
|
||||
has_cpu_throttle_increment = true;
|
||||
use_int_value = true;
|
||||
break;
|
||||
case MIGRATION_PARAMETER_TLS_CREDS:
|
||||
has_tls_creds = true;
|
||||
|
|
|
@ -1320,13 +1320,14 @@ static void v9fs_walk(void *opaque)
|
|||
goto out_nofid;
|
||||
}
|
||||
|
||||
v9fs_path_init(&dpath);
|
||||
v9fs_path_init(&path);
|
||||
|
||||
err = fid_to_qid(pdu, fidp, &qid);
|
||||
if (err < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
v9fs_path_init(&dpath);
|
||||
v9fs_path_init(&path);
|
||||
/*
|
||||
* Both dpath and path initially poin to fidp.
|
||||
* Needed to handle request with nwnames == 0
|
||||
|
|
|
@ -99,6 +99,7 @@ void build_acpi_ipmi_devices(Aml *scope, BusState *bus)
|
|||
|
||||
ii = IPMI_INTERFACE(obj);
|
||||
iic = IPMI_INTERFACE_GET_CLASS(obj);
|
||||
memset(&info, 0, sizeof(info));
|
||||
iic->get_fwinfo(ii, &info);
|
||||
aml_append(scope, aml_ipmi_device(&info));
|
||||
}
|
||||
|
|
|
@ -60,6 +60,8 @@ typedef struct GUSState {
|
|||
int64_t last_ticks;
|
||||
qemu_irq pic;
|
||||
IsaDma *isa_dma;
|
||||
PortioList portio_list1;
|
||||
PortioList portio_list2;
|
||||
} GUSState;
|
||||
|
||||
static uint32_t gus_readb(void *opaque, uint32_t nport)
|
||||
|
@ -265,9 +267,10 @@ static void gus_realizefn (DeviceState *dev, Error **errp)
|
|||
s->samples = AUD_get_buffer_size_out (s->voice) >> s->shift;
|
||||
s->mixbuf = g_malloc0 (s->samples << s->shift);
|
||||
|
||||
isa_register_portio_list (d, s->port, gus_portio_list1, s, "gus");
|
||||
isa_register_portio_list (d, (s->port + 0x100) & 0xf00,
|
||||
gus_portio_list2, s, "gus");
|
||||
isa_register_portio_list(d, &s->portio_list1, s->port,
|
||||
gus_portio_list1, s, "gus");
|
||||
isa_register_portio_list(d, &s->portio_list2, (s->port + 0x100) & 0xf00,
|
||||
gus_portio_list2, s, "gus");
|
||||
|
||||
s->isa_dma = isa_get_dma(isa_bus_from_device(d), s->emu.gusdma);
|
||||
k = ISADMA_GET_CLASS(s->isa_dma);
|
||||
|
|
|
@ -106,6 +106,7 @@ typedef struct SB16State {
|
|||
/* mixer state */
|
||||
int mixer_nreg;
|
||||
uint8_t mixer_regs[256];
|
||||
PortioList portio_list;
|
||||
} SB16State;
|
||||
|
||||
static void SB_audio_callback (void *opaque, int free);
|
||||
|
@ -1378,7 +1379,8 @@ static void sb16_realizefn (DeviceState *dev, Error **errp)
|
|||
dolog ("warning: Could not create auxiliary timer\n");
|
||||
}
|
||||
|
||||
isa_register_portio_list (isadev, s->port, sb16_ioport_list, s, "sb16");
|
||||
isa_register_portio_list(isadev, &s->portio_list, s->port,
|
||||
sb16_ioport_list, s, "sb16");
|
||||
|
||||
s->isa_hdma = isa_get_dma(isa_bus_from_device(isadev), s->hdma);
|
||||
k = ISADMA_GET_CLASS(s->isa_hdma);
|
||||
|
|
|
@ -692,6 +692,7 @@ struct FDCtrl {
|
|||
/* Timers state */
|
||||
uint8_t timer0;
|
||||
uint8_t timer1;
|
||||
PortioList portio_list;
|
||||
};
|
||||
|
||||
static FloppyDriveType get_fallback_drive_type(FDrive *drv)
|
||||
|
@ -2495,7 +2496,8 @@ static void isabus_fdc_realize(DeviceState *dev, Error **errp)
|
|||
FDCtrl *fdctrl = &isa->state;
|
||||
Error *err = NULL;
|
||||
|
||||
isa_register_portio_list(isadev, isa->iobase, fdc_portio_list, fdctrl,
|
||||
isa_register_portio_list(isadev, &fdctrl->portio_list,
|
||||
isa->iobase, fdc_portio_list, fdctrl,
|
||||
"fdc");
|
||||
|
||||
isa_init_irq(isadev, &fdctrl->irq, isa->irq);
|
||||
|
|
|
@ -258,8 +258,10 @@ static uint16_t nvme_rw(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
|
|||
req->has_sg = true;
|
||||
dma_acct_start(n->conf.blk, &req->acct, &req->qsg, acct);
|
||||
req->aiocb = is_write ?
|
||||
dma_blk_write(n->conf.blk, &req->qsg, data_offset, nvme_rw_cb, req) :
|
||||
dma_blk_read(n->conf.blk, &req->qsg, data_offset, nvme_rw_cb, req);
|
||||
dma_blk_write(n->conf.blk, &req->qsg, data_offset, BDRV_SECTOR_SIZE,
|
||||
nvme_rw_cb, req) :
|
||||
dma_blk_read(n->conf.blk, &req->qsg, data_offset, BDRV_SECTOR_SIZE,
|
||||
nvme_rw_cb, req);
|
||||
|
||||
return NVME_NO_COMPLETE;
|
||||
}
|
||||
|
|
|
@ -80,6 +80,7 @@ typedef struct ParallelState {
|
|||
uint32_t last_read_offset; /* For debugging */
|
||||
/* Memory-mapped interface */
|
||||
int it_shift;
|
||||
PortioList portio_list;
|
||||
} ParallelState;
|
||||
|
||||
#define TYPE_ISA_PARALLEL "isa-parallel"
|
||||
|
@ -532,7 +533,7 @@ static void parallel_isa_realizefn(DeviceState *dev, Error **errp)
|
|||
s->status = dummy;
|
||||
}
|
||||
|
||||
isa_register_portio_list(isadev, base,
|
||||
isa_register_portio_list(isadev, &s->portio_list, base,
|
||||
(s->hw_driver
|
||||
? &isa_parallel_portio_hw_list[0]
|
||||
: &isa_parallel_portio_sw_list[0]),
|
||||
|
|
|
@ -39,6 +39,8 @@ typedef struct ISAVGAState {
|
|||
ISADevice parent_obj;
|
||||
|
||||
struct VGACommonState state;
|
||||
PortioList portio_vga;
|
||||
PortioList portio_vbe;
|
||||
} ISAVGAState;
|
||||
|
||||
static void vga_isa_reset(DeviceState *dev)
|
||||
|
@ -60,9 +62,11 @@ static void vga_isa_realizefn(DeviceState *dev, Error **errp)
|
|||
vga_common_init(s, OBJECT(dev), true);
|
||||
s->legacy_address_space = isa_address_space(isadev);
|
||||
vga_io_memory = vga_init_io(s, OBJECT(dev), &vga_ports, &vbe_ports);
|
||||
isa_register_portio_list(isadev, 0x3b0, vga_ports, s, "vga");
|
||||
isa_register_portio_list(isadev, &d->portio_vga,
|
||||
0x3b0, vga_ports, s, "vga");
|
||||
if (vbe_ports) {
|
||||
isa_register_portio_list(isadev, 0x1ce, vbe_ports, s, "vbe");
|
||||
isa_register_portio_list(isadev, &d->portio_vbe,
|
||||
0x1ce, vbe_ports, s, "vbe");
|
||||
}
|
||||
memory_region_add_subregion_overlap(isa_address_space(isadev),
|
||||
0x000a0000,
|
||||
|
|
|
@ -553,10 +553,12 @@ static void i8257_realize(DeviceState *dev, Error **errp)
|
|||
memory_region_add_subregion(isa_address_space_io(isa),
|
||||
d->base, &d->channel_io);
|
||||
|
||||
isa_register_portio_list(isa, d->page_base, page_portio_list, d,
|
||||
isa_register_portio_list(isa, &d->portio_page,
|
||||
d->page_base, page_portio_list, d,
|
||||
"dma-page");
|
||||
if (d->pageh_base >= 0) {
|
||||
isa_register_portio_list(isa, d->pageh_base, pageh_portio_list, d,
|
||||
isa_register_portio_list(isa, &d->portio_pageh,
|
||||
d->pageh_base, pageh_portio_list, d,
|
||||
"dma-pageh");
|
||||
}
|
||||
|
||||
|
|
|
@ -985,6 +985,7 @@ static void vtd_context_device_invalidate(IntelIOMMUState *s,
|
|||
mask = 7; /* Mask bit 2:0 in the SID field */
|
||||
break;
|
||||
}
|
||||
mask = ~mask;
|
||||
VTD_DPRINTF(INV, "device-selective invalidation source 0x%"PRIx16
|
||||
" mask %"PRIu16, source_id, mask);
|
||||
vtd_bus = vtd_find_as_from_bus_num(s, VTD_SID_TO_BUS(source_id));
|
||||
|
|
|
@ -1251,6 +1251,7 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev, Error **errp)
|
|||
error_propagate(errp, local_err);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
dev->dev.cap_present |= QEMU_PCI_CAP_MSI;
|
||||
dev->cap.available |= ASSIGNED_DEVICE_CAP_MSI;
|
||||
/* Only 32-bit/no-mask currently supported */
|
||||
ret = pci_add_capability2(pci_dev, PCI_CAP_ID_MSI, pos, 10,
|
||||
|
@ -1285,6 +1286,7 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev, Error **errp)
|
|||
error_propagate(errp, local_err);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
dev->dev.cap_present |= QEMU_PCI_CAP_MSIX;
|
||||
dev->cap.available |= ASSIGNED_DEVICE_CAP_MSIX;
|
||||
ret = pci_add_capability2(pci_dev, PCI_CAP_ID_MSIX, pos, 12,
|
||||
&local_err);
|
||||
|
@ -1648,6 +1650,7 @@ static void assigned_dev_register_msix_mmio(AssignedDevice *dev, Error **errp)
|
|||
dev->msix_table = NULL;
|
||||
return;
|
||||
}
|
||||
dev->dev.msix_table = (uint8_t *)dev->msix_table;
|
||||
|
||||
assigned_dev_msix_reset(dev);
|
||||
|
||||
|
@ -1665,6 +1668,7 @@ static void assigned_dev_unregister_msix_mmio(AssignedDevice *dev)
|
|||
error_report("error unmapping msix_table! %s", strerror(errno));
|
||||
}
|
||||
dev->msix_table = NULL;
|
||||
dev->dev.msix_table = NULL;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_assigned_device = {
|
||||
|
|
|
@ -134,8 +134,6 @@ static void platform_fixed_ioport_writew(void *opaque, uint32_t addr, uint32_t v
|
|||
devices, and bit 2 the non-primary-master IDE devices. */
|
||||
if (val & UNPLUG_ALL_IDE_DISKS) {
|
||||
DPRINTF("unplug disks\n");
|
||||
blk_drain_all();
|
||||
blk_flush_all();
|
||||
pci_unplug_disks(pci_dev->bus);
|
||||
}
|
||||
if (val & UNPLUG_ALL_NICS) {
|
||||
|
|
|
@ -948,6 +948,7 @@ static void ncq_cb(void *opaque, int ret)
|
|||
NCQTransferState *ncq_tfs = (NCQTransferState *)opaque;
|
||||
IDEState *ide_state = &ncq_tfs->drive->port.ifs[0];
|
||||
|
||||
ncq_tfs->aiocb = NULL;
|
||||
if (ret == -ECANCELED) {
|
||||
return;
|
||||
}
|
||||
|
@ -1008,6 +1009,7 @@ static void execute_ncq_command(NCQTransferState *ncq_tfs)
|
|||
&ncq_tfs->sglist, BLOCK_ACCT_READ);
|
||||
ncq_tfs->aiocb = dma_blk_read(ide_state->blk, &ncq_tfs->sglist,
|
||||
ncq_tfs->lba << BDRV_SECTOR_BITS,
|
||||
BDRV_SECTOR_SIZE,
|
||||
ncq_cb, ncq_tfs);
|
||||
break;
|
||||
case WRITE_FPDMA_QUEUED:
|
||||
|
@ -1021,6 +1023,7 @@ static void execute_ncq_command(NCQTransferState *ncq_tfs)
|
|||
&ncq_tfs->sglist, BLOCK_ACCT_WRITE);
|
||||
ncq_tfs->aiocb = dma_blk_write(ide_state->blk, &ncq_tfs->sglist,
|
||||
ncq_tfs->lba << BDRV_SECTOR_BITS,
|
||||
BDRV_SECTOR_SIZE,
|
||||
ncq_cb, ncq_tfs);
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -637,6 +637,23 @@ static unsigned int event_status_media(IDEState *s,
|
|||
return 8; /* We wrote to 4 extra bytes from the header */
|
||||
}
|
||||
|
||||
/*
|
||||
* Before transferring data or otherwise signalling acceptance of a command
|
||||
* marked CONDDATA, we must check the validity of the byte_count_limit.
|
||||
*/
|
||||
static bool validate_bcl(IDEState *s)
|
||||
{
|
||||
/* TODO: Check IDENTIFY data word 125 for defacult BCL (currently 0) */
|
||||
if (s->atapi_dma || atapi_byte_count_limit(s)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* TODO: Move abort back into core.c and introduce proper error flow between
|
||||
* ATAPI layer and IDE core layer */
|
||||
ide_abort_command(s);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void cmd_get_event_status_notification(IDEState *s,
|
||||
uint8_t *buf)
|
||||
{
|
||||
|
@ -1028,12 +1045,19 @@ static void cmd_read_cd(IDEState *s, uint8_t* buf)
|
|||
return;
|
||||
}
|
||||
|
||||
transfer_request = buf[9];
|
||||
switch(transfer_request & 0xf8) {
|
||||
case 0x00:
|
||||
transfer_request = buf[9] & 0xf8;
|
||||
if (transfer_request == 0x00) {
|
||||
/* nothing */
|
||||
ide_atapi_cmd_ok(s);
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check validity of BCL before transferring data */
|
||||
if (!validate_bcl(s)) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (transfer_request) {
|
||||
case 0x10:
|
||||
/* normal read */
|
||||
ide_atapi_cmd_read(s, lba, nb_sectors, 2048);
|
||||
|
@ -1266,6 +1290,14 @@ enum {
|
|||
* See ATA8-ACS3 "7.21.5 Byte Count Limit"
|
||||
*/
|
||||
NONDATA = 0x04,
|
||||
|
||||
/*
|
||||
* CONDDATA implies a command that transfers data only conditionally based
|
||||
* on the presence of suboptions. It should be exempt from the BCL check at
|
||||
* command validation time, but it needs to be checked at the command
|
||||
* handler level instead.
|
||||
*/
|
||||
CONDDATA = 0x08,
|
||||
};
|
||||
|
||||
static const struct AtapiCmd {
|
||||
|
@ -1289,7 +1321,7 @@ static const struct AtapiCmd {
|
|||
[ 0xad ] = { cmd_read_dvd_structure, CHECK_READY },
|
||||
[ 0xbb ] = { cmd_set_speed, NONDATA },
|
||||
[ 0xbd ] = { cmd_mechanism_status, 0 },
|
||||
[ 0xbe ] = { cmd_read_cd, CHECK_READY },
|
||||
[ 0xbe ] = { cmd_read_cd, CHECK_READY | CONDDATA },
|
||||
/* [1] handler detects and reports not ready condition itself */
|
||||
};
|
||||
|
||||
|
@ -1348,15 +1380,12 @@ void ide_atapi_cmd(IDEState *s)
|
|||
return;
|
||||
}
|
||||
|
||||
/* Nondata commands permit the byte_count_limit to be 0.
|
||||
/* Commands that don't transfer DATA permit the byte_count_limit to be 0.
|
||||
* If this is a data-transferring PIO command and BCL is 0,
|
||||
* we abort at the /ATA/ level, not the ATAPI level.
|
||||
* See ATA8 ACS3 section 7.17.6.49 and 7.21.5 */
|
||||
if (cmd->handler && !(cmd->flags & NONDATA)) {
|
||||
/* TODO: Check IDENTIFY data word 125 for default BCL (currently 0) */
|
||||
if (!(atapi_byte_count_limit(s) || s->atapi_dma)) {
|
||||
/* TODO: Move abort back into core.c and make static inline again */
|
||||
ide_abort_command(s);
|
||||
if (cmd->handler && !(cmd->flags & (NONDATA | CONDDATA))) {
|
||||
if (!validate_bcl(s)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -882,15 +882,15 @@ static void ide_dma_cb(void *opaque, int ret)
|
|||
switch (s->dma_cmd) {
|
||||
case IDE_DMA_READ:
|
||||
s->bus->dma->aiocb = dma_blk_read(s->blk, &s->sg, offset,
|
||||
ide_dma_cb, s);
|
||||
BDRV_SECTOR_SIZE, ide_dma_cb, s);
|
||||
break;
|
||||
case IDE_DMA_WRITE:
|
||||
s->bus->dma->aiocb = dma_blk_write(s->blk, &s->sg, offset,
|
||||
ide_dma_cb, s);
|
||||
BDRV_SECTOR_SIZE, ide_dma_cb, s);
|
||||
break;
|
||||
case IDE_DMA_TRIM:
|
||||
s->bus->dma->aiocb = dma_blk_io(blk_get_aio_context(s->blk),
|
||||
&s->sg, offset,
|
||||
&s->sg, offset, BDRV_SECTOR_SIZE,
|
||||
ide_issue_trim, s->blk, ide_dma_cb, s,
|
||||
DMA_DIRECTION_TO_DEVICE);
|
||||
break;
|
||||
|
@ -2582,7 +2582,7 @@ static void ide_restart_cb(void *opaque, int running, RunState state)
|
|||
void ide_register_restart_cb(IDEBus *bus)
|
||||
{
|
||||
if (bus->dma->ops->restart_dma) {
|
||||
qemu_add_vm_change_state_handler(ide_restart_cb, bus);
|
||||
bus->vmstate = qemu_add_vm_change_state_handler(ide_restart_cb, bus);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2619,10 +2619,12 @@ void ide_init_ioport(IDEBus *bus, ISADevice *dev, int iobase, int iobase2)
|
|||
{
|
||||
/* ??? Assume only ISA and PCI configurations, and that the PCI-ISA
|
||||
bridge has been setup properly to always register with ISA. */
|
||||
isa_register_portio_list(dev, iobase, ide_portio_list, bus, "ide");
|
||||
isa_register_portio_list(dev, &bus->portio_list,
|
||||
iobase, ide_portio_list, bus, "ide");
|
||||
|
||||
if (iobase2) {
|
||||
isa_register_portio_list(dev, iobase2, ide_portio2_list, bus, "ide");
|
||||
isa_register_portio_list(dev, &bus->portio2_list,
|
||||
iobase2, ide_portio2_list, bus, "ide");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -179,6 +179,10 @@ int pci_piix3_xen_ide_unplug(DeviceState *dev)
|
|||
if (di != NULL && !di->media_cd) {
|
||||
BlockBackend *blk = blk_by_legacy_dinfo(di);
|
||||
DeviceState *ds = blk_get_attached_dev(blk);
|
||||
|
||||
blk_drain(blk);
|
||||
blk_flush(blk);
|
||||
|
||||
if (ds) {
|
||||
blk_detach_dev(blk, ds);
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
/* --------------------------------- */
|
||||
|
||||
static char *idebus_get_fw_dev_path(DeviceState *dev);
|
||||
static void idebus_unrealize(DeviceState *qdev, Error **errp);
|
||||
|
||||
static Property ide_props[] = {
|
||||
DEFINE_PROP_UINT32("unit", IDEDevice, unit, -1),
|
||||
|
@ -44,6 +45,15 @@ static void ide_bus_class_init(ObjectClass *klass, void *data)
|
|||
k->get_fw_dev_path = idebus_get_fw_dev_path;
|
||||
}
|
||||
|
||||
static void idebus_unrealize(DeviceState *qdev, Error **errp)
|
||||
{
|
||||
IDEBus *bus = DO_UPCAST(IDEBus, qbus, qdev->parent_bus);
|
||||
|
||||
if (bus->vmstate) {
|
||||
qemu_del_vm_change_state_handler(bus->vmstate);
|
||||
}
|
||||
}
|
||||
|
||||
static const TypeInfo ide_bus_info = {
|
||||
.name = TYPE_IDE_BUS,
|
||||
.parent = TYPE_BUS,
|
||||
|
@ -345,6 +355,7 @@ static void ide_device_class_init(ObjectClass *klass, void *data)
|
|||
k->init = ide_qdev_init;
|
||||
set_bit(DEVICE_CATEGORY_STORAGE, k->categories);
|
||||
k->bus_type = TYPE_IDE_BUS;
|
||||
k->unrealize = idebus_unrealize;
|
||||
k->props = ide_props;
|
||||
}
|
||||
|
||||
|
|
|
@ -131,24 +131,20 @@ void isa_register_ioport(ISADevice *dev, MemoryRegion *io, uint16_t start)
|
|||
isa_init_ioport(dev, start);
|
||||
}
|
||||
|
||||
void isa_register_portio_list(ISADevice *dev, uint16_t start,
|
||||
void isa_register_portio_list(ISADevice *dev,
|
||||
PortioList *piolist, uint16_t start,
|
||||
const MemoryRegionPortio *pio_start,
|
||||
void *opaque, const char *name)
|
||||
{
|
||||
PortioList piolist;
|
||||
assert(piolist && !piolist->owner);
|
||||
|
||||
/* START is how we should treat DEV, regardless of the actual
|
||||
contents of the portio array. This is how the old code
|
||||
actually handled e.g. the FDC device. */
|
||||
isa_init_ioport(dev, start);
|
||||
|
||||
/* FIXME: the device should store created PortioList in its state. Note
|
||||
that DEV can be NULL here and that single device can register several
|
||||
portio lists. Current implementation is leaking memory allocated
|
||||
in portio_list_init. The leak is not critical because it happens only
|
||||
at initialization time. */
|
||||
portio_list_init(&piolist, OBJECT(dev), pio_start, opaque, name);
|
||||
portio_list_add(&piolist, isabus->address_space_io, start);
|
||||
portio_list_init(piolist, OBJECT(dev), pio_start, opaque, name);
|
||||
portio_list_add(piolist, isabus->address_space_io, start);
|
||||
}
|
||||
|
||||
static void isa_device_init(Object *obj)
|
||||
|
|
|
@ -859,7 +859,7 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp)
|
|||
pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY,
|
||||
&s->ivshmem_mmio);
|
||||
|
||||
if (!s->not_legacy_32bit) {
|
||||
if (s->not_legacy_32bit) {
|
||||
attr |= PCI_BASE_ADDRESS_MEM_TYPE_64;
|
||||
}
|
||||
|
||||
|
@ -1045,6 +1045,7 @@ static void ivshmem_plain_init(Object *obj)
|
|||
ivshmem_check_memdev_is_busy,
|
||||
OBJ_PROP_LINK_UNREF_ON_RELEASE,
|
||||
&error_abort);
|
||||
s->not_legacy_32bit = 1;
|
||||
}
|
||||
|
||||
static void ivshmem_plain_realize(PCIDevice *dev, Error **errp)
|
||||
|
@ -1116,6 +1117,7 @@ static void ivshmem_doorbell_init(Object *obj)
|
|||
|
||||
s->features |= (1 << IVSHMEM_MSI);
|
||||
s->legacy_size = SIZE_MAX; /* whatever the server sends */
|
||||
s->not_legacy_32bit = 1;
|
||||
}
|
||||
|
||||
static void ivshmem_doorbell_realize(PCIDevice *dev, Error **errp)
|
||||
|
|
|
@ -2350,7 +2350,7 @@ static void rtl8139_cplus_transmit(RTL8139State *s)
|
|||
{
|
||||
int txcount = 0;
|
||||
|
||||
while (rtl8139_cplus_transmit_one(s))
|
||||
while (txcount < 64 && rtl8139_cplus_transmit_one(s))
|
||||
{
|
||||
++txcount;
|
||||
}
|
||||
|
|
|
@ -1904,6 +1904,7 @@ static void virtio_net_class_init(ObjectClass *klass, void *data)
|
|||
vdc->guest_notifier_pending = virtio_net_guest_notifier_pending;
|
||||
vdc->load = virtio_net_load_device;
|
||||
vdc->save = virtio_net_save_device;
|
||||
vdc->legacy_features |= (0x1 << VIRTIO_NET_F_GSO);
|
||||
}
|
||||
|
||||
static const TypeInfo virtio_net_info = {
|
||||
|
|
|
@ -141,7 +141,8 @@ out_err:
|
|||
int css_create_css_image(uint8_t cssid, bool default_image)
|
||||
{
|
||||
trace_css_new_image(cssid, default_image ? "(default)" : "");
|
||||
if (cssid > MAX_CSSID) {
|
||||
/* 255 is reserved */
|
||||
if (cssid == 255) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (channel_subsys.css[cssid]) {
|
||||
|
@ -1267,7 +1268,7 @@ bool css_schid_final(int m, uint8_t cssid, uint8_t ssid, uint16_t schid)
|
|||
uint8_t real_cssid;
|
||||
|
||||
real_cssid = (!m && (cssid == 0)) ? channel_subsys.default_cssid : cssid;
|
||||
if (real_cssid > MAX_CSSID || ssid > MAX_SSID ||
|
||||
if (ssid > MAX_SSID ||
|
||||
!channel_subsys.css[real_cssid] ||
|
||||
!channel_subsys.css[real_cssid]->sch_set[ssid]) {
|
||||
return true;
|
||||
|
@ -1282,9 +1283,6 @@ static int css_add_virtual_chpid(uint8_t cssid, uint8_t chpid, uint8_t type)
|
|||
CssImage *css;
|
||||
|
||||
trace_css_chpid_add(cssid, chpid, type);
|
||||
if (cssid > MAX_CSSID) {
|
||||
return -EINVAL;
|
||||
}
|
||||
css = channel_subsys.css[cssid];
|
||||
if (!css) {
|
||||
return -EINVAL;
|
||||
|
|
|
@ -330,6 +330,8 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
|
|||
if (!ccw.cda) {
|
||||
ret = -EFAULT;
|
||||
} else {
|
||||
VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
|
||||
|
||||
features.index = address_space_ldub(&address_space_memory,
|
||||
ccw.cda
|
||||
+ sizeof(features.features),
|
||||
|
@ -339,7 +341,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
|
|||
if (dev->revision >= 1) {
|
||||
/* Don't offer legacy features for modern devices. */
|
||||
features.features = (uint32_t)
|
||||
(vdev->host_features & ~VIRTIO_LEGACY_FEATURES);
|
||||
(vdev->host_features & ~vdc->legacy_features);
|
||||
} else {
|
||||
features.features = (uint32_t)vdev->host_features;
|
||||
}
|
||||
|
|
|
@ -1981,7 +1981,11 @@ static void megasas_handle_frame(MegasasState *s, uint64_t frame_addr,
|
|||
break;
|
||||
}
|
||||
if (frame_status != MFI_STAT_INVALID_STATUS) {
|
||||
cmd->frame->header.cmd_status = frame_status;
|
||||
if (cmd->frame) {
|
||||
cmd->frame->header.cmd_status = frame_status;
|
||||
} else {
|
||||
megasas_frame_set_cmd_status(s, frame_addr, frame_status);
|
||||
}
|
||||
megasas_unmap_frame(s, cmd);
|
||||
megasas_complete_frame(s, cmd->context);
|
||||
}
|
||||
|
|
|
@ -158,7 +158,7 @@ static size_t mptsas_config_pack(uint8_t **data, const char *fmt, ...)
|
|||
va_end(ap);
|
||||
|
||||
if (data) {
|
||||
assert(ret < 256 && (ret % 4) == 0);
|
||||
assert(ret / 4 < 256 && (ret % 4) == 0);
|
||||
stb_p(*data + 1, ret / 4);
|
||||
}
|
||||
return ret;
|
||||
|
@ -203,7 +203,7 @@ size_t mptsas_config_manufacturing_1(MPTSASState *s, uint8_t **data, int address
|
|||
{
|
||||
/* VPD - all zeros */
|
||||
return MPTSAS_CONFIG_PACK(1, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00,
|
||||
"s256");
|
||||
"*s256");
|
||||
}
|
||||
|
||||
static
|
||||
|
@ -328,7 +328,7 @@ size_t mptsas_config_ioc_0(MPTSASState *s, uint8_t **data, int address)
|
|||
return MPTSAS_CONFIG_PACK(0, MPI_CONFIG_PAGETYPE_IOC, 0x01,
|
||||
"*l*lwwb*b*b*blww",
|
||||
pcic->vendor_id, pcic->device_id, pcic->revision,
|
||||
pcic->subsystem_vendor_id,
|
||||
pcic->class_id, pcic->subsystem_vendor_id,
|
||||
pcic->subsystem_id);
|
||||
}
|
||||
|
||||
|
|
|
@ -304,7 +304,7 @@ static int mptsas_process_scsi_io_request(MPTSASState *s,
|
|||
goto bad;
|
||||
}
|
||||
|
||||
req = g_new(MPTSASRequest, 1);
|
||||
req = g_new0(MPTSASRequest, 1);
|
||||
QTAILQ_INSERT_TAIL(&s->pending, req, next);
|
||||
req->scsi_io = *scsi_io;
|
||||
req->dev = s;
|
||||
|
|
|
@ -341,6 +341,7 @@ static void scsi_do_read(SCSIDiskReq *r, int ret)
|
|||
r->req.resid -= r->req.sg->size;
|
||||
r->req.aiocb = dma_blk_io(blk_get_aio_context(s->qdev.conf.blk),
|
||||
r->req.sg, r->sector << BDRV_SECTOR_BITS,
|
||||
BDRV_SECTOR_SIZE,
|
||||
sdc->dma_readv, r, scsi_dma_complete, r,
|
||||
DMA_DIRECTION_FROM_DEVICE);
|
||||
} else {
|
||||
|
@ -396,7 +397,7 @@ static void scsi_read_data(SCSIRequest *req)
|
|||
return;
|
||||
}
|
||||
|
||||
if (s->tray_open) {
|
||||
if (!blk_is_available(req->dev->conf.blk)) {
|
||||
scsi_read_complete(r, -ENOMEDIUM);
|
||||
return;
|
||||
}
|
||||
|
@ -519,7 +520,7 @@ static void scsi_write_data(SCSIRequest *req)
|
|||
scsi_write_complete_noio(r, 0);
|
||||
return;
|
||||
}
|
||||
if (s->tray_open) {
|
||||
if (!blk_is_available(req->dev->conf.blk)) {
|
||||
scsi_write_complete_noio(r, -ENOMEDIUM);
|
||||
return;
|
||||
}
|
||||
|
@ -539,6 +540,7 @@ static void scsi_write_data(SCSIRequest *req)
|
|||
r->req.resid -= r->req.sg->size;
|
||||
r->req.aiocb = dma_blk_io(blk_get_aio_context(s->qdev.conf.blk),
|
||||
r->req.sg, r->sector << BDRV_SECTOR_BITS,
|
||||
BDRV_SECTOR_SIZE,
|
||||
sdc->dma_writev, r, scsi_dma_complete, r,
|
||||
DMA_DIRECTION_TO_DEVICE);
|
||||
} else {
|
||||
|
@ -599,8 +601,8 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
|
|||
}
|
||||
|
||||
l = strlen(s->serial);
|
||||
if (l > 20) {
|
||||
l = 20;
|
||||
if (l > 36) {
|
||||
l = 36;
|
||||
}
|
||||
|
||||
DPRINTF("Inquiry EVPD[Serial number] "
|
||||
|
@ -792,10 +794,7 @@ static inline bool media_is_dvd(SCSIDiskState *s)
|
|||
if (s->qdev.type != TYPE_ROM) {
|
||||
return false;
|
||||
}
|
||||
if (!blk_is_inserted(s->qdev.conf.blk)) {
|
||||
return false;
|
||||
}
|
||||
if (s->tray_open) {
|
||||
if (!blk_is_available(s->qdev.conf.blk)) {
|
||||
return false;
|
||||
}
|
||||
blk_get_geometry(s->qdev.conf.blk, &nb_sectors);
|
||||
|
@ -808,10 +807,7 @@ static inline bool media_is_cd(SCSIDiskState *s)
|
|||
if (s->qdev.type != TYPE_ROM) {
|
||||
return false;
|
||||
}
|
||||
if (!blk_is_inserted(s->qdev.conf.blk)) {
|
||||
return false;
|
||||
}
|
||||
if (s->tray_open) {
|
||||
if (!blk_is_available(s->qdev.conf.blk)) {
|
||||
return false;
|
||||
}
|
||||
blk_get_geometry(s->qdev.conf.blk, &nb_sectors);
|
||||
|
@ -875,7 +871,7 @@ static int scsi_read_dvd_structure(SCSIDiskState *s, SCSIDiskReq *r,
|
|||
}
|
||||
|
||||
if (format != 0xff) {
|
||||
if (s->tray_open || !blk_is_inserted(s->qdev.conf.blk)) {
|
||||
if (!blk_is_available(s->qdev.conf.blk)) {
|
||||
scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
|
||||
return -1;
|
||||
}
|
||||
|
@ -1857,7 +1853,7 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
|
|||
break;
|
||||
|
||||
default:
|
||||
if (s->tray_open || !blk_is_inserted(s->qdev.conf.blk)) {
|
||||
if (!blk_is_available(s->qdev.conf.blk)) {
|
||||
scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
|
||||
return 0;
|
||||
}
|
||||
|
@ -1886,7 +1882,7 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
|
|||
memset(outbuf, 0, r->buflen);
|
||||
switch (req->cmd.buf[0]) {
|
||||
case TEST_UNIT_READY:
|
||||
assert(!s->tray_open && blk_is_inserted(s->qdev.conf.blk));
|
||||
assert(blk_is_available(s->qdev.conf.blk));
|
||||
break;
|
||||
case INQUIRY:
|
||||
buflen = scsi_disk_emulate_inquiry(req, outbuf);
|
||||
|
@ -2126,7 +2122,7 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf)
|
|||
|
||||
command = buf[0];
|
||||
|
||||
if (s->tray_open || !blk_is_inserted(s->qdev.conf.blk)) {
|
||||
if (!blk_is_available(s->qdev.conf.blk)) {
|
||||
scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -236,6 +236,13 @@ static void virtio_scsi_cancel_notify(Notifier *notifier, void *data)
|
|||
g_free(n);
|
||||
}
|
||||
|
||||
static inline void virtio_scsi_ctx_check(VirtIOSCSI *s, SCSIDevice *d)
|
||||
{
|
||||
if (s->dataplane_started && d && blk_is_available(d->conf.blk)) {
|
||||
assert(blk_get_aio_context(d->conf.blk) == s->ctx);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return 0 if the request is ready to be completed and return to guest;
|
||||
* -EINPROGRESS if the request is submitted and will be completed later, in the
|
||||
* case of async cancellation. */
|
||||
|
@ -247,9 +254,7 @@ static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req)
|
|||
int target;
|
||||
int ret = 0;
|
||||
|
||||
if (s->dataplane_started && d) {
|
||||
assert(blk_get_aio_context(d->conf.blk) == s->ctx);
|
||||
}
|
||||
virtio_scsi_ctx_check(s, d);
|
||||
/* Here VIRTIO_SCSI_S_OK means "FUNCTION COMPLETE". */
|
||||
req->resp.tmf.response = VIRTIO_SCSI_S_OK;
|
||||
|
||||
|
@ -539,9 +544,7 @@ static bool virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req
|
|||
virtio_scsi_complete_cmd_req(req);
|
||||
return false;
|
||||
}
|
||||
if (s->dataplane_started) {
|
||||
assert(blk_get_aio_context(d->conf.blk) == s->ctx);
|
||||
}
|
||||
virtio_scsi_ctx_check(s, d);
|
||||
req->sreq = scsi_req_new(d, req->req.cmd.tag,
|
||||
virtio_scsi_get_lun(req->req.cmd.lun),
|
||||
req->req.cmd.cdb, req);
|
||||
|
|
|
@ -152,7 +152,7 @@ pvscsi_log2(uint32_t input)
|
|||
return log;
|
||||
}
|
||||
|
||||
static int
|
||||
static void
|
||||
pvscsi_ring_init_data(PVSCSIRingInfo *m, PVSCSICmdDescSetupRings *ri)
|
||||
{
|
||||
int i;
|
||||
|
@ -160,10 +160,6 @@ pvscsi_ring_init_data(PVSCSIRingInfo *m, PVSCSICmdDescSetupRings *ri)
|
|||
uint32_t req_ring_size, cmp_ring_size;
|
||||
m->rs_pa = ri->ringsStatePPN << VMW_PAGE_SHIFT;
|
||||
|
||||
if ((ri->reqRingNumPages > PVSCSI_SETUP_RINGS_MAX_NUM_PAGES)
|
||||
|| (ri->cmpRingNumPages > PVSCSI_SETUP_RINGS_MAX_NUM_PAGES)) {
|
||||
return -1;
|
||||
}
|
||||
req_ring_size = ri->reqRingNumPages * PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE;
|
||||
cmp_ring_size = ri->cmpRingNumPages * PVSCSI_MAX_NUM_CMP_ENTRIES_PER_PAGE;
|
||||
txr_len_log2 = pvscsi_log2(req_ring_size - 1);
|
||||
|
@ -195,8 +191,6 @@ pvscsi_ring_init_data(PVSCSIRingInfo *m, PVSCSICmdDescSetupRings *ri)
|
|||
|
||||
/* Flush ring state page changes */
|
||||
smp_wmb();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -251,8 +245,11 @@ static hwaddr
|
|||
pvscsi_ring_pop_req_descr(PVSCSIRingInfo *mgr)
|
||||
{
|
||||
uint32_t ready_ptr = RS_GET_FIELD(mgr, reqProdIdx);
|
||||
uint32_t ring_size = PVSCSI_MAX_NUM_PAGES_REQ_RING
|
||||
* PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE;
|
||||
|
||||
if (ready_ptr != mgr->consumed_ptr) {
|
||||
if (ready_ptr != mgr->consumed_ptr
|
||||
&& ready_ptr - mgr->consumed_ptr < ring_size) {
|
||||
uint32_t next_ready_ptr =
|
||||
mgr->consumed_ptr++ & mgr->txr_len_mask;
|
||||
uint32_t next_ready_page =
|
||||
|
@ -746,7 +743,7 @@ pvscsi_dbg_dump_tx_rings_config(PVSCSICmdDescSetupRings *rc)
|
|||
|
||||
trace_pvscsi_tx_rings_num_pages("Confirm Ring", rc->cmpRingNumPages);
|
||||
for (i = 0; i < rc->cmpRingNumPages; i++) {
|
||||
trace_pvscsi_tx_rings_ppn("Confirm Ring", rc->reqRingPPNs[i]);
|
||||
trace_pvscsi_tx_rings_ppn("Confirm Ring", rc->cmpRingPPNs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -779,11 +776,16 @@ pvscsi_on_cmd_setup_rings(PVSCSIState *s)
|
|||
|
||||
trace_pvscsi_on_cmd_arrived("PVSCSI_CMD_SETUP_RINGS");
|
||||
|
||||
pvscsi_dbg_dump_tx_rings_config(rc);
|
||||
if (pvscsi_ring_init_data(&s->rings, rc) < 0) {
|
||||
if (!rc->reqRingNumPages
|
||||
|| rc->reqRingNumPages > PVSCSI_SETUP_RINGS_MAX_NUM_PAGES
|
||||
|| !rc->cmpRingNumPages
|
||||
|| rc->cmpRingNumPages > PVSCSI_SETUP_RINGS_MAX_NUM_PAGES) {
|
||||
return PVSCSI_COMMAND_PROCESSING_FAILED;
|
||||
}
|
||||
|
||||
pvscsi_dbg_dump_tx_rings_config(rc);
|
||||
pvscsi_ring_init_data(&s->rings, rc);
|
||||
|
||||
s->rings_info_valid = TRUE;
|
||||
return PVSCSI_COMMAND_PROCESSING_SUCCEEDED;
|
||||
}
|
||||
|
|
|
@ -723,12 +723,11 @@ int vfio_region_mmap(VFIORegion *region)
|
|||
|
||||
name = g_strdup_printf("%s mmaps[%d]",
|
||||
memory_region_name(region->mem), i);
|
||||
memory_region_init_ram_ptr(®ion->mmaps[i].mem,
|
||||
memory_region_owner(region->mem),
|
||||
name, region->mmaps[i].size,
|
||||
region->mmaps[i].mmap);
|
||||
memory_region_init_ram_device_ptr(®ion->mmaps[i].mem,
|
||||
memory_region_owner(region->mem),
|
||||
name, region->mmaps[i].size,
|
||||
region->mmaps[i].mmap);
|
||||
g_free(name);
|
||||
memory_region_set_skip_dump(®ion->mmaps[i].mem);
|
||||
memory_region_add_subregion(region->mem, region->mmaps[i].offset,
|
||||
®ion->mmaps[i].mem);
|
||||
|
||||
|
|
|
@ -898,7 +898,7 @@ static uint64_t vfio_rtl8168_quirk_data_read(void *opaque,
|
|||
{
|
||||
VFIOrtl8168Quirk *rtl = opaque;
|
||||
VFIOPCIDevice *vdev = rtl->vdev;
|
||||
uint64_t data = vfio_region_read(&vdev->bars[2].region, addr + 0x74, size);
|
||||
uint64_t data = vfio_region_read(&vdev->bars[2].region, addr + 0x70, size);
|
||||
|
||||
if (rtl->enabled && (vdev->pdev.cap_present & QEMU_PCI_CAP_MSIX)) {
|
||||
hwaddr offset = rtl->addr & 0xfff;
|
||||
|
|
|
@ -496,7 +496,9 @@ static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr,
|
|||
vfio_update_kvm_msi_virq(vector, *msg, pdev);
|
||||
}
|
||||
} else {
|
||||
vfio_add_kvm_msi_virq(vdev, vector, nr, true);
|
||||
if (msg) {
|
||||
vfio_add_kvm_msi_virq(vdev, vector, nr, true);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -25,7 +25,7 @@ static bool vfio_prereg_listener_skipped_section(MemoryRegionSection *section)
|
|||
}
|
||||
|
||||
return !memory_region_is_ram(section->mr) ||
|
||||
memory_region_is_skip_dump(section->mr);
|
||||
memory_region_is_ram_device(section->mr);
|
||||
}
|
||||
|
||||
static void *vfio_prereg_gpa_to_vaddr(MemoryRegionSection *section, hwaddr gpa)
|
||||
|
|
|
@ -421,32 +421,73 @@ static inline void vhost_dev_log_resize(struct vhost_dev *dev, uint64_t size)
|
|||
dev->log_size = size;
|
||||
}
|
||||
|
||||
|
||||
static int vhost_verify_ring_part_mapping(void *part,
|
||||
uint64_t part_addr,
|
||||
uint64_t part_size,
|
||||
uint64_t start_addr,
|
||||
uint64_t size)
|
||||
{
|
||||
hwaddr l;
|
||||
void *p;
|
||||
int r = 0;
|
||||
|
||||
if (!ranges_overlap(start_addr, size, part_addr, part_size)) {
|
||||
return 0;
|
||||
}
|
||||
l = part_size;
|
||||
p = cpu_physical_memory_map(part_addr, &l, 1);
|
||||
if (!p || l != part_size) {
|
||||
r = -ENOMEM;
|
||||
}
|
||||
if (p != part) {
|
||||
r = -EBUSY;
|
||||
}
|
||||
cpu_physical_memory_unmap(p, l, 0, 0);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int vhost_verify_ring_mappings(struct vhost_dev *dev,
|
||||
uint64_t start_addr,
|
||||
uint64_t size)
|
||||
{
|
||||
int i;
|
||||
int i, j;
|
||||
int r = 0;
|
||||
const char *part_name[] = {
|
||||
"descriptor table",
|
||||
"available ring",
|
||||
"used ring"
|
||||
};
|
||||
|
||||
for (i = 0; !r && i < dev->nvqs; ++i) {
|
||||
for (i = 0; i < dev->nvqs; ++i) {
|
||||
struct vhost_virtqueue *vq = dev->vqs + i;
|
||||
hwaddr l;
|
||||
void *p;
|
||||
|
||||
if (!ranges_overlap(start_addr, size, vq->ring_phys, vq->ring_size)) {
|
||||
continue;
|
||||
j = 0;
|
||||
r = vhost_verify_ring_part_mapping(vq->desc, vq->desc_phys,
|
||||
vq->desc_size, start_addr, size);
|
||||
if (!r) {
|
||||
break;
|
||||
}
|
||||
l = vq->ring_size;
|
||||
p = cpu_physical_memory_map(vq->ring_phys, &l, 1);
|
||||
if (!p || l != vq->ring_size) {
|
||||
error_report("Unable to map ring buffer for ring %d", i);
|
||||
r = -ENOMEM;
|
||||
|
||||
j++;
|
||||
r = vhost_verify_ring_part_mapping(vq->avail, vq->avail_phys,
|
||||
vq->avail_size, start_addr, size);
|
||||
if (!r) {
|
||||
break;
|
||||
}
|
||||
if (p != vq->ring) {
|
||||
error_report("Ring buffer relocated for ring %d", i);
|
||||
r = -EBUSY;
|
||||
|
||||
j++;
|
||||
r = vhost_verify_ring_part_mapping(vq->used, vq->used_phys,
|
||||
vq->used_size, start_addr, size);
|
||||
if (!r) {
|
||||
break;
|
||||
}
|
||||
cpu_physical_memory_unmap(p, l, 0, 0);
|
||||
}
|
||||
|
||||
if (r == -ENOMEM) {
|
||||
error_report("Unable to map %s for ring %d", part_name[j], i);
|
||||
} else if (r == -EBUSY) {
|
||||
error_report("%s relocated for ring %d", part_name[j], i);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
@ -857,15 +898,15 @@ static int vhost_virtqueue_start(struct vhost_dev *dev,
|
|||
}
|
||||
}
|
||||
|
||||
s = l = virtio_queue_get_desc_size(vdev, idx);
|
||||
a = virtio_queue_get_desc_addr(vdev, idx);
|
||||
vq->desc_size = s = l = virtio_queue_get_desc_size(vdev, idx);
|
||||
vq->desc_phys = a = virtio_queue_get_desc_addr(vdev, idx);
|
||||
vq->desc = cpu_physical_memory_map(a, &l, 0);
|
||||
if (!vq->desc || l != s) {
|
||||
r = -ENOMEM;
|
||||
goto fail_alloc_desc;
|
||||
}
|
||||
s = l = virtio_queue_get_avail_size(vdev, idx);
|
||||
a = virtio_queue_get_avail_addr(vdev, idx);
|
||||
vq->avail_size = s = l = virtio_queue_get_avail_size(vdev, idx);
|
||||
vq->avail_phys = a = virtio_queue_get_avail_addr(vdev, idx);
|
||||
vq->avail = cpu_physical_memory_map(a, &l, 0);
|
||||
if (!vq->avail || l != s) {
|
||||
r = -ENOMEM;
|
||||
|
@ -879,14 +920,6 @@ static int vhost_virtqueue_start(struct vhost_dev *dev,
|
|||
goto fail_alloc_used;
|
||||
}
|
||||
|
||||
vq->ring_size = s = l = virtio_queue_get_ring_size(vdev, idx);
|
||||
vq->ring_phys = a = virtio_queue_get_ring_addr(vdev, idx);
|
||||
vq->ring = cpu_physical_memory_map(a, &l, 1);
|
||||
if (!vq->ring || l != s) {
|
||||
r = -ENOMEM;
|
||||
goto fail_alloc_ring;
|
||||
}
|
||||
|
||||
r = vhost_virtqueue_set_addr(dev, vq, vhost_vq_index, dev->log_enabled);
|
||||
if (r < 0) {
|
||||
r = -errno;
|
||||
|
@ -916,9 +949,6 @@ static int vhost_virtqueue_start(struct vhost_dev *dev,
|
|||
|
||||
fail_kick:
|
||||
fail_alloc:
|
||||
cpu_physical_memory_unmap(vq->ring, virtio_queue_get_ring_size(vdev, idx),
|
||||
0, 0);
|
||||
fail_alloc_ring:
|
||||
cpu_physical_memory_unmap(vq->used, virtio_queue_get_used_size(vdev, idx),
|
||||
0, 0);
|
||||
fail_alloc_used:
|
||||
|
@ -959,8 +989,6 @@ static void vhost_virtqueue_stop(struct vhost_dev *dev,
|
|||
vhost_vq_index);
|
||||
}
|
||||
|
||||
cpu_physical_memory_unmap(vq->ring, virtio_queue_get_ring_size(vdev, idx),
|
||||
0, virtio_queue_get_ring_size(vdev, idx));
|
||||
cpu_physical_memory_unmap(vq->used, virtio_queue_get_used_size(vdev, idx),
|
||||
1, virtio_queue_get_used_size(vdev, idx));
|
||||
cpu_physical_memory_unmap(vq->avail, virtio_queue_get_avail_size(vdev, idx),
|
||||
|
|
|
@ -463,6 +463,7 @@ static void virtio_balloon_device_reset(VirtIODevice *vdev)
|
|||
VirtIOBalloon *s = VIRTIO_BALLOON(vdev);
|
||||
|
||||
if (s->stats_vq_elem != NULL) {
|
||||
virtqueue_discard(s->svq, s->stats_vq_elem, 0);
|
||||
g_free(s->stats_vq_elem);
|
||||
s->stats_vq_elem = NULL;
|
||||
}
|
||||
|
|
|
@ -1192,7 +1192,9 @@ static uint64_t virtio_pci_common_read(void *opaque, hwaddr addr,
|
|||
break;
|
||||
case VIRTIO_PCI_COMMON_DF:
|
||||
if (proxy->dfselect <= 1) {
|
||||
val = (vdev->host_features & ~VIRTIO_LEGACY_FEATURES) >>
|
||||
VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
|
||||
|
||||
val = (vdev->host_features & ~vdc->legacy_features) >>
|
||||
(32 * proxy->dfselect);
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -822,6 +822,7 @@ void virtio_reset(void *opaque)
|
|||
vdev->vq[i].signalled_used_valid = false;
|
||||
vdev->vq[i].notification = true;
|
||||
vdev->vq[i].vring.num = vdev->vq[i].vring.num_default;
|
||||
vdev->vq[i].inuse = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1965,12 +1966,15 @@ static Property virtio_properties[] = {
|
|||
static void virtio_device_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
/* Set the default value here. */
|
||||
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = virtio_device_realize;
|
||||
dc->unrealize = virtio_device_unrealize;
|
||||
dc->bus_type = TYPE_VIRTIO_BUS;
|
||||
dc->props = virtio_properties;
|
||||
|
||||
vdc->legacy_features |= VIRTIO_LEGACY_FEATURES;
|
||||
}
|
||||
|
||||
static const TypeInfo virtio_device_info = {
|
||||
|
|
|
@ -336,6 +336,7 @@ int bdrv_inactivate_all(void);
|
|||
/* Ensure contents are flushed to disk. */
|
||||
int bdrv_flush(BlockDriverState *bs);
|
||||
int coroutine_fn bdrv_co_flush(BlockDriverState *bs);
|
||||
int bdrv_flush_all(void);
|
||||
void bdrv_close_all(void);
|
||||
void bdrv_drain(BlockDriverState *bs);
|
||||
void coroutine_fn bdrv_co_drain(BlockDriverState *bs);
|
||||
|
|
|
@ -188,7 +188,7 @@ struct MemoryRegion {
|
|||
void (*destructor)(MemoryRegion *mr);
|
||||
uint64_t align;
|
||||
bool terminates;
|
||||
bool skip_dump;
|
||||
bool ram_device;
|
||||
bool enabled;
|
||||
bool warning_printed; /* For reservations */
|
||||
uint8_t vga_logging_count;
|
||||
|
@ -425,6 +425,30 @@ void memory_region_init_ram_ptr(MemoryRegion *mr,
|
|||
uint64_t size,
|
||||
void *ptr);
|
||||
|
||||
/**
|
||||
* memory_region_init_ram_device_ptr: Initialize RAM device memory region from
|
||||
* a user-provided pointer.
|
||||
*
|
||||
* A RAM device represents a mapping to a physical device, such as to a PCI
|
||||
* MMIO BAR of an vfio-pci assigned device. The memory region may be mapped
|
||||
* into the VM address space and access to the region will modify memory
|
||||
* directly. However, the memory region should not be included in a memory
|
||||
* dump (device may not be enabled/mapped at the time of the dump), and
|
||||
* operations incompatible with manipulating MMIO should be avoided. Replaces
|
||||
* skip_dump flag.
|
||||
*
|
||||
* @mr: the #MemoryRegion to be initialized.
|
||||
* @owner: the object that tracks the region's reference count
|
||||
* @name: the name of the region.
|
||||
* @size: size of the region.
|
||||
* @ptr: memory to be mapped; must contain at least @size bytes.
|
||||
*/
|
||||
void memory_region_init_ram_device_ptr(MemoryRegion *mr,
|
||||
struct Object *owner,
|
||||
const char *name,
|
||||
uint64_t size,
|
||||
void *ptr);
|
||||
|
||||
/**
|
||||
* memory_region_init_alias: Initialize a memory region that aliases all or a
|
||||
* part of another memory region.
|
||||
|
@ -551,22 +575,13 @@ static inline bool memory_region_is_ram(MemoryRegion *mr)
|
|||
}
|
||||
|
||||
/**
|
||||
* memory_region_is_skip_dump: check whether a memory region should not be
|
||||
* dumped
|
||||
* memory_region_is_ram_device: check whether a memory region is a ram device
|
||||
*
|
||||
* Returns %true is a memory region should not be dumped(e.g. VFIO BAR MMAP).
|
||||
* Returns %true is a memory region is a device backed ram region
|
||||
*
|
||||
* @mr: the memory region being queried
|
||||
*/
|
||||
bool memory_region_is_skip_dump(MemoryRegion *mr);
|
||||
|
||||
/**
|
||||
* memory_region_set_skip_dump: Set skip_dump flag, dump will ignore this memory
|
||||
* region
|
||||
*
|
||||
* @mr: the memory region being queried
|
||||
*/
|
||||
void memory_region_set_skip_dump(MemoryRegion *mr);
|
||||
bool memory_region_is_ram_device(MemoryRegion *mr);
|
||||
|
||||
/**
|
||||
* memory_region_is_romd: check whether a memory region is in ROMD mode
|
||||
|
@ -1431,9 +1446,11 @@ void *qemu_map_ram_ptr(RAMBlock *ram_block, ram_addr_t addr);
|
|||
static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write)
|
||||
{
|
||||
if (is_write) {
|
||||
return memory_region_is_ram(mr) && !mr->readonly;
|
||||
return memory_region_is_ram(mr) &&
|
||||
!mr->readonly && !memory_region_is_ram_device(mr);
|
||||
} else {
|
||||
return memory_region_is_ram(mr) || memory_region_is_romd(mr);
|
||||
return (memory_region_is_ram(mr) && !memory_region_is_ram_device(mr)) ||
|
||||
memory_region_is_romd(mr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -480,6 +480,9 @@ struct IDEBus {
|
|||
uint8_t retry_unit;
|
||||
int64_t retry_sector_num;
|
||||
uint32_t retry_nsector;
|
||||
PortioList portio_list;
|
||||
PortioList portio2_list;
|
||||
VMChangeStateEntry *vmstate;
|
||||
};
|
||||
|
||||
#define TYPE_IDE_DEVICE "ide-device"
|
||||
|
|
|
@ -36,6 +36,8 @@ typedef struct I8257State {
|
|||
QEMUBH *dma_bh;
|
||||
bool dma_bh_scheduled;
|
||||
int running;
|
||||
PortioList portio_page;
|
||||
PortioList portio_pageh;
|
||||
} I8257State;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -134,12 +134,15 @@ void isa_register_ioport(ISADevice *dev, MemoryRegion *io, uint16_t start);
|
|||
* device and use the legacy portio routines.
|
||||
*
|
||||
* @dev: the ISADevice against which these are registered; may be NULL.
|
||||
* @piolist: the PortioList associated with the io ports
|
||||
* @start: the base I/O port against which the portio->offset is applied.
|
||||
* @portio: the ports, sorted by offset.
|
||||
* @opaque: passed into the portio callbacks.
|
||||
* @name: passed into memory_region_init_io.
|
||||
*/
|
||||
void isa_register_portio_list(ISADevice *dev, uint16_t start,
|
||||
void isa_register_portio_list(ISADevice *dev,
|
||||
PortioList *piolist,
|
||||
uint16_t start,
|
||||
const MemoryRegionPortio *portio,
|
||||
void *opaque, const char *name);
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#define MAX_DEVNO 65535
|
||||
#define MAX_SCHID 65535
|
||||
#define MAX_SSID 3
|
||||
#define MAX_CSSID 254 /* 255 is reserved */
|
||||
#define MAX_CSSID 255
|
||||
#define MAX_CHPID 255
|
||||
|
||||
#define MAX_CIWS 62
|
||||
|
|
|
@ -14,11 +14,12 @@ struct vhost_virtqueue {
|
|||
void *avail;
|
||||
void *used;
|
||||
int num;
|
||||
unsigned long long desc_phys;
|
||||
unsigned desc_size;
|
||||
unsigned long long avail_phys;
|
||||
unsigned avail_size;
|
||||
unsigned long long used_phys;
|
||||
unsigned used_size;
|
||||
void *ring;
|
||||
unsigned long long ring_phys;
|
||||
unsigned ring_size;
|
||||
EventNotifier masked_notifier;
|
||||
};
|
||||
|
||||
|
|
|
@ -112,6 +112,11 @@ typedef struct VirtioDeviceClass {
|
|||
void (*set_config)(VirtIODevice *vdev, const uint8_t *config);
|
||||
void (*reset)(VirtIODevice *vdev);
|
||||
void (*set_status)(VirtIODevice *vdev, uint8_t val);
|
||||
/* For transitional devices, this is a bitmap of features
|
||||
* that are only exposed on the legacy interface but not
|
||||
* the modern one.
|
||||
*/
|
||||
uint64_t legacy_features;
|
||||
/* Test and clear event pending status.
|
||||
* Should be called after unmask to avoid losing events.
|
||||
* If backend does not support masking,
|
||||
|
|
|
@ -149,7 +149,6 @@ BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf,
|
|||
int blk_co_pdiscard(BlockBackend *blk, int64_t offset, int count);
|
||||
int blk_co_flush(BlockBackend *blk);
|
||||
int blk_flush(BlockBackend *blk);
|
||||
int blk_flush_all(void);
|
||||
int blk_commit_all(void);
|
||||
void blk_drain(BlockBackend *blk);
|
||||
void blk_drain_all(void);
|
||||
|
|
|
@ -199,14 +199,14 @@ typedef BlockAIOCB *DMAIOFunc(int64_t offset, QEMUIOVector *iov,
|
|||
void *opaque);
|
||||
|
||||
BlockAIOCB *dma_blk_io(AioContext *ctx,
|
||||
QEMUSGList *sg, uint64_t offset,
|
||||
QEMUSGList *sg, uint64_t offset, uint32_t align,
|
||||
DMAIOFunc *io_func, void *io_func_opaque,
|
||||
BlockCompletionFunc *cb, void *opaque, DMADirection dir);
|
||||
BlockAIOCB *dma_blk_read(BlockBackend *blk,
|
||||
QEMUSGList *sg, uint64_t offset,
|
||||
QEMUSGList *sg, uint64_t offset, uint32_t align,
|
||||
BlockCompletionFunc *cb, void *opaque);
|
||||
BlockAIOCB *dma_blk_write(BlockBackend *blk,
|
||||
QEMUSGList *sg, uint64_t offset,
|
||||
QEMUSGList *sg, uint64_t offset, uint32_t align,
|
||||
BlockCompletionFunc *cb, void *opaque);
|
||||
uint64_t dma_buf_read(uint8_t *ptr, int32_t len, QEMUSGList *sg);
|
||||
uint64_t dma_buf_write(uint8_t *ptr, int32_t len, QEMUSGList *sg);
|
||||
|
|
|
@ -35,5 +35,6 @@ typedef struct {
|
|||
|
||||
char *iothread_get_id(IOThread *iothread);
|
||||
AioContext *iothread_get_aio_context(IOThread *iothread);
|
||||
void iothread_stop_all(void);
|
||||
|
||||
#endif /* IOTHREAD_H */
|
||||
|
|
24
iothread.c
24
iothread.c
|
@ -54,16 +54,25 @@ static void *iothread_run(void *opaque)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void iothread_instance_finalize(Object *obj)
|
||||
static int iothread_stop(Object *object, void *opaque)
|
||||
{
|
||||
IOThread *iothread = IOTHREAD(obj);
|
||||
IOThread *iothread;
|
||||
|
||||
if (!iothread->ctx) {
|
||||
return;
|
||||
iothread = (IOThread *)object_dynamic_cast(object, TYPE_IOTHREAD);
|
||||
if (!iothread || !iothread->ctx) {
|
||||
return 0;
|
||||
}
|
||||
iothread->stopping = true;
|
||||
aio_notify(iothread->ctx);
|
||||
qemu_thread_join(&iothread->thread);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void iothread_instance_finalize(Object *obj)
|
||||
{
|
||||
IOThread *iothread = IOTHREAD(obj);
|
||||
|
||||
iothread_stop(obj, NULL);
|
||||
qemu_cond_destroy(&iothread->init_done_cond);
|
||||
qemu_mutex_destroy(&iothread->init_done_lock);
|
||||
aio_context_unref(iothread->ctx);
|
||||
|
@ -174,3 +183,10 @@ IOThreadInfoList *qmp_query_iothreads(Error **errp)
|
|||
object_child_foreach(container, query_one_iothread, &prev);
|
||||
return head;
|
||||
}
|
||||
|
||||
void iothread_stop_all(void)
|
||||
{
|
||||
Object *container = object_get_objects_root();
|
||||
|
||||
object_child_foreach(container, iothread_stop, NULL);
|
||||
}
|
||||
|
|
80
memory.c
80
memory.c
|
@ -1132,6 +1132,71 @@ const MemoryRegionOps unassigned_mem_ops = {
|
|||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static uint64_t memory_region_ram_device_read(void *opaque,
|
||||
hwaddr addr, unsigned size)
|
||||
{
|
||||
MemoryRegion *mr = opaque;
|
||||
uint64_t data = (uint64_t)~0;
|
||||
|
||||
switch (size) {
|
||||
case 1:
|
||||
data = *(uint8_t *)(mr->ram_block->host + addr);
|
||||
break;
|
||||
case 2:
|
||||
data = *(uint16_t *)(mr->ram_block->host + addr);
|
||||
break;
|
||||
case 4:
|
||||
data = *(uint32_t *)(mr->ram_block->host + addr);
|
||||
break;
|
||||
case 8:
|
||||
data = *(uint64_t *)(mr->ram_block->host + addr);
|
||||
break;
|
||||
}
|
||||
|
||||
trace_memory_region_ram_device_read(get_cpu_index(), mr, addr, data, size);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static void memory_region_ram_device_write(void *opaque, hwaddr addr,
|
||||
uint64_t data, unsigned size)
|
||||
{
|
||||
MemoryRegion *mr = opaque;
|
||||
|
||||
trace_memory_region_ram_device_write(get_cpu_index(), mr, addr, data, size);
|
||||
|
||||
switch (size) {
|
||||
case 1:
|
||||
*(uint8_t *)(mr->ram_block->host + addr) = (uint8_t)data;
|
||||
break;
|
||||
case 2:
|
||||
*(uint16_t *)(mr->ram_block->host + addr) = (uint16_t)data;
|
||||
break;
|
||||
case 4:
|
||||
*(uint32_t *)(mr->ram_block->host + addr) = (uint32_t)data;
|
||||
break;
|
||||
case 8:
|
||||
*(uint64_t *)(mr->ram_block->host + addr) = data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps ram_device_mem_ops = {
|
||||
.read = memory_region_ram_device_read,
|
||||
.write = memory_region_ram_device_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 8,
|
||||
.unaligned = true,
|
||||
},
|
||||
.impl = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 8,
|
||||
.unaligned = true,
|
||||
},
|
||||
};
|
||||
|
||||
bool memory_region_access_valid(MemoryRegion *mr,
|
||||
hwaddr addr,
|
||||
unsigned size,
|
||||
|
@ -1359,9 +1424,16 @@ void memory_region_init_ram_ptr(MemoryRegion *mr,
|
|||
mr->ram_block = qemu_ram_alloc_from_ptr(size, ptr, mr, &error_fatal);
|
||||
}
|
||||
|
||||
void memory_region_set_skip_dump(MemoryRegion *mr)
|
||||
void memory_region_init_ram_device_ptr(MemoryRegion *mr,
|
||||
Object *owner,
|
||||
const char *name,
|
||||
uint64_t size,
|
||||
void *ptr)
|
||||
{
|
||||
mr->skip_dump = true;
|
||||
memory_region_init_ram_ptr(mr, owner, name, size, ptr);
|
||||
mr->ram_device = true;
|
||||
mr->ops = &ram_device_mem_ops;
|
||||
mr->opaque = mr;
|
||||
}
|
||||
|
||||
void memory_region_init_alias(MemoryRegion *mr,
|
||||
|
@ -1494,9 +1566,9 @@ const char *memory_region_name(const MemoryRegion *mr)
|
|||
return mr->name;
|
||||
}
|
||||
|
||||
bool memory_region_is_skip_dump(MemoryRegion *mr)
|
||||
bool memory_region_is_ram_device(MemoryRegion *mr)
|
||||
{
|
||||
return mr->skip_dump;
|
||||
return mr->ram_device;
|
||||
}
|
||||
|
||||
uint8_t memory_region_get_dirty_log_mask(MemoryRegion *mr)
|
||||
|
|
|
@ -206,7 +206,7 @@ static void guest_phys_blocks_region_add(MemoryListener *listener,
|
|||
|
||||
/* we only care about RAM */
|
||||
if (!memory_region_is_ram(section->mr) ||
|
||||
memory_region_is_skip_dump(section->mr)) {
|
||||
memory_region_is_ram_device(section->mr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1648,9 +1648,8 @@ int net_fill_rstate(SocketReadState *rs, const uint8_t *buf, int size)
|
|||
if (rs->index >= rs->packet_len) {
|
||||
rs->index = 0;
|
||||
rs->state = 0;
|
||||
if (rs->finalize) {
|
||||
rs->finalize(rs);
|
||||
}
|
||||
assert(rs->finalize);
|
||||
rs->finalize(rs);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -522,6 +522,7 @@ static int net_socket_listen_init(NetClientState *peer,
|
|||
s->fd = -1;
|
||||
s->listen_fd = fd;
|
||||
s->nc.link_down = true;
|
||||
net_socket_rs_init(&s->rs, net_socket_rs_finalize);
|
||||
|
||||
qemu_set_fd_handler(s->listen_fd, net_socket_accept, NULL, s);
|
||||
return 0;
|
||||
|
|
|
@ -338,6 +338,12 @@ static void qmp_input_type_any(Visitor *v, const char *name, QObject **obj,
|
|||
QmpInputVisitor *qiv = to_qiv(v);
|
||||
QObject *qobj = qmp_input_get_object(qiv, name, true);
|
||||
|
||||
if (!qobj) {
|
||||
error_setg(errp, QERR_MISSING_PARAMETER, name ? name : "null");
|
||||
*obj = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
qobject_incref(qobj);
|
||||
*obj = qobj;
|
||||
}
|
||||
|
@ -347,6 +353,11 @@ static void qmp_input_type_null(Visitor *v, const char *name, Error **errp)
|
|||
QmpInputVisitor *qiv = to_qiv(v);
|
||||
QObject *qobj = qmp_input_get_object(qiv, name, true);
|
||||
|
||||
if (!qobj) {
|
||||
error_setg(errp, QERR_MISSING_PARAMETER, name ? name : "null");
|
||||
return;
|
||||
}
|
||||
|
||||
if (qobject_type(qobj) != QTYPE_QNULL) {
|
||||
error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
|
||||
"null");
|
||||
|
|
|
@ -1223,6 +1223,9 @@ static CharDriverState *qemu_chr_open_stdio(const char *id,
|
|||
sigaction(SIGCONT, &act, NULL);
|
||||
|
||||
chr = qemu_chr_open_fd(0, 1, common, errp);
|
||||
if (!chr) {
|
||||
return NULL;
|
||||
}
|
||||
chr->chr_close = qemu_chr_close_stdio;
|
||||
chr->chr_set_echo = qemu_chr_set_echo_stdio;
|
||||
if (opts->has_signal) {
|
||||
|
@ -1679,6 +1682,9 @@ static CharDriverState *qemu_chr_open_tty_fd(int fd,
|
|||
|
||||
tty_serial_init(fd, 115200, 'N', 8, 1);
|
||||
chr = qemu_chr_open_fd(fd, fd, backend, errp);
|
||||
if (!chr) {
|
||||
return NULL;
|
||||
}
|
||||
chr->chr_ioctl = tty_serial_ioctl;
|
||||
chr->chr_close = qemu_chr_close_tty;
|
||||
return chr;
|
||||
|
@ -3090,6 +3096,7 @@ static void tcp_chr_tls_init(CharDriverState *chr)
|
|||
if (tioc == NULL) {
|
||||
error_free(err);
|
||||
tcp_chr_disconnect(chr);
|
||||
return;
|
||||
}
|
||||
object_unref(OBJECT(s->ioc));
|
||||
s->ioc = QIO_CHANNEL(tioc);
|
||||
|
|
8
qmp.c
8
qmp.c
|
@ -654,7 +654,7 @@ void qmp_add_client(const char *protocol, const char *fdname,
|
|||
void qmp_object_add(const char *type, const char *id,
|
||||
bool has_props, QObject *props, Error **errp)
|
||||
{
|
||||
const QDict *pdict = NULL;
|
||||
QDict *pdict;
|
||||
Visitor *v;
|
||||
Object *obj;
|
||||
|
||||
|
@ -664,14 +664,18 @@ void qmp_object_add(const char *type, const char *id,
|
|||
error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "props", "dict");
|
||||
return;
|
||||
}
|
||||
QINCREF(pdict);
|
||||
} else {
|
||||
pdict = qdict_new();
|
||||
}
|
||||
|
||||
v = qmp_input_visitor_new(props, true);
|
||||
v = qmp_input_visitor_new(QOBJECT(pdict), true);
|
||||
obj = user_creatable_add_type(type, id, pdict, v, errp);
|
||||
visit_free(v);
|
||||
if (obj) {
|
||||
object_unref(obj);
|
||||
}
|
||||
QDECREF(pdict);
|
||||
}
|
||||
|
||||
void qmp_object_del(const char *id, Error **errp)
|
||||
|
|
|
@ -92,7 +92,7 @@ module-common.o: CFLAGS += $(DSO_OBJ_CFLAGS)
|
|||
$(if $(findstring /,$@),$(call quiet-command,cp $@ $(subst /,-,$@), " CP $(subst /,-,$@)"))
|
||||
|
||||
|
||||
LD_REL := $(CC) -nostdlib -Wl,-r $(LD_REL_FLAGS)
|
||||
LD_REL := $(CC) -nostdlib -r $(LD_REL_FLAGS)
|
||||
|
||||
%.mo:
|
||||
$(call quiet-command,$(LD_REL) -o $@ $^," LD -r $(TARGET_DIR)$@")
|
||||
|
|
|
@ -66,6 +66,23 @@ void
|
|||
sofree(struct socket *so)
|
||||
{
|
||||
Slirp *slirp = so->slirp;
|
||||
struct mbuf *ifm;
|
||||
|
||||
for (ifm = (struct mbuf *) slirp->if_fastq.qh_link;
|
||||
(struct quehead *) ifm != &slirp->if_fastq;
|
||||
ifm = ifm->ifq_next) {
|
||||
if (ifm->ifq_so == so) {
|
||||
ifm->ifq_so = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for (ifm = (struct mbuf *) slirp->if_batchq.qh_link;
|
||||
(struct quehead *) ifm != &slirp->if_batchq;
|
||||
ifm = ifm->ifq_next) {
|
||||
if (ifm->ifq_so == so) {
|
||||
ifm->ifq_so = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (so->so_emu==EMU_RSH && so->extra) {
|
||||
sofree(so->extra);
|
||||
|
|
|
@ -1164,6 +1164,12 @@ struct PowerPCCPU {
|
|||
int cpu_dt_id;
|
||||
uint32_t max_compat;
|
||||
uint32_t cpu_version;
|
||||
|
||||
/* fields used only during migration for compatibility hacks */
|
||||
target_ulong mig_msr_mask;
|
||||
uint64_t mig_insns_flags;
|
||||
uint64_t mig_insns_flags2;
|
||||
uint32_t mig_nb_BATs;
|
||||
};
|
||||
|
||||
static inline PowerPCCPU *ppc_env_get_cpu(CPUPPCState *env)
|
||||
|
|
|
@ -429,6 +429,7 @@ static void kvm_fixup_page_sizes(PowerPCCPU *cpu)
|
|||
CPUPPCState *env = &cpu->env;
|
||||
long rampagesize;
|
||||
int iq, ik, jq, jk;
|
||||
bool has_64k_pages = false;
|
||||
|
||||
/* We only handle page sizes for 64-bit server guests for now */
|
||||
if (!(env->mmu_model & POWERPC_MMU_64)) {
|
||||
|
@ -472,6 +473,9 @@ static void kvm_fixup_page_sizes(PowerPCCPU *cpu)
|
|||
ksps->enc[jk].page_shift)) {
|
||||
continue;
|
||||
}
|
||||
if (ksps->enc[jk].page_shift == 16) {
|
||||
has_64k_pages = true;
|
||||
}
|
||||
qsps->enc[jq].page_shift = ksps->enc[jk].page_shift;
|
||||
qsps->enc[jq].pte_enc = ksps->enc[jk].pte_enc;
|
||||
if (++jq >= PPC_PAGE_SIZES_MAX_SZ) {
|
||||
|
@ -486,6 +490,9 @@ static void kvm_fixup_page_sizes(PowerPCCPU *cpu)
|
|||
if (!(smmu_info.flags & KVM_PPC_1T_SEGMENTS)) {
|
||||
env->mmu_model &= ~POWERPC_MMU_1TSEG;
|
||||
}
|
||||
if (!has_64k_pages) {
|
||||
env->mmu_model &= ~POWERPC_MMU_64K;
|
||||
}
|
||||
}
|
||||
#else /* defined (TARGET_PPC64) */
|
||||
|
||||
|
|
|
@ -141,6 +141,21 @@ static void cpu_pre_save(void *opaque)
|
|||
PowerPCCPU *cpu = opaque;
|
||||
CPUPPCState *env = &cpu->env;
|
||||
int i;
|
||||
uint64_t insns_compat_mask =
|
||||
PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB
|
||||
| PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES
|
||||
| PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | PPC_FLOAT_FRSQRTES
|
||||
| PPC_FLOAT_STFIWX | PPC_FLOAT_EXT
|
||||
| PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ
|
||||
| PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC
|
||||
| PPC_64B | PPC_64BX | PPC_ALTIVEC
|
||||
| PPC_SEGMENT_64B | PPC_SLBI | PPC_POPCNTB | PPC_POPCNTWD;
|
||||
uint64_t insns_compat_mask2 = PPC2_VSX | PPC2_VSX207 | PPC2_DFP | PPC2_DBRX
|
||||
| PPC2_PERM_ISA206 | PPC2_DIVE_ISA206
|
||||
| PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206
|
||||
| PPC2_FP_TST_ISA206 | PPC2_BCTAR_ISA207
|
||||
| PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207
|
||||
| PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 | PPC2_TM;
|
||||
|
||||
env->spr[SPR_LR] = env->lr;
|
||||
env->spr[SPR_CTR] = env->ctr;
|
||||
|
@ -162,6 +177,12 @@ static void cpu_pre_save(void *opaque)
|
|||
env->spr[SPR_IBAT4U + 2*i] = env->IBAT[0][i+4];
|
||||
env->spr[SPR_IBAT4U + 2*i + 1] = env->IBAT[1][i+4];
|
||||
}
|
||||
|
||||
/* Hacks for migration compatibility between 2.6, 2.7 & 2.8 */
|
||||
cpu->mig_msr_mask = env->msr_mask;
|
||||
cpu->mig_insns_flags = env->insns_flags & insns_compat_mask;
|
||||
cpu->mig_insns_flags2 = env->insns_flags2 & insns_compat_mask2;
|
||||
cpu->mig_nb_BATs = env->nb_BATs;
|
||||
}
|
||||
|
||||
static int cpu_post_load(void *opaque, int version_id)
|
||||
|
@ -562,10 +583,10 @@ const VMStateDescription vmstate_ppc_cpu = {
|
|||
/* FIXME: access_type? */
|
||||
|
||||
/* Sanity checking */
|
||||
VMSTATE_UINTTL_EQUAL(env.msr_mask, PowerPCCPU),
|
||||
VMSTATE_UINT64_EQUAL(env.insns_flags, PowerPCCPU),
|
||||
VMSTATE_UINT64_EQUAL(env.insns_flags2, PowerPCCPU),
|
||||
VMSTATE_UINT32_EQUAL(env.nb_BATs, PowerPCCPU),
|
||||
VMSTATE_UINTTL(mig_msr_mask, PowerPCCPU),
|
||||
VMSTATE_UINT64(mig_insns_flags, PowerPCCPU),
|
||||
VMSTATE_UINT64(mig_insns_flags2, PowerPCCPU),
|
||||
VMSTATE_UINT32(mig_nb_BATs, PowerPCCPU),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
.subsections = (const VMStateDescription*[]) {
|
||||
|
|
|
@ -622,7 +622,7 @@ tests/usb-hcd-ehci-test$(EXESUF): tests/usb-hcd-ehci-test.o $(libqos-usb-obj-y)
|
|||
tests/usb-hcd-xhci-test$(EXESUF): tests/usb-hcd-xhci-test.o $(libqos-usb-obj-y)
|
||||
tests/pc-cpu-test$(EXESUF): tests/pc-cpu-test.o
|
||||
tests/postcopy-test$(EXESUF): tests/postcopy-test.o
|
||||
tests/vhost-user-test$(EXESUF): tests/vhost-user-test.o qemu-char.o qemu-timer.o $(qtest-obj-y) $(test-io-obj-y)
|
||||
tests/vhost-user-test$(EXESUF): tests/vhost-user-test.o qemu-char.o qemu-timer.o $(qtest-obj-y) $(test-io-obj-y) $(libqos-virtio-obj-y)
|
||||
tests/qemu-iotests/socket_scm_helper$(EXESUF): tests/qemu-iotests/socket_scm_helper.o
|
||||
tests/test-qemu-opts$(EXESUF): tests/test-qemu-opts.o $(test-util-obj-y)
|
||||
tests/test-write-threshold$(EXESUF): tests/test-write-threshold.o $(test-block-obj-y)
|
||||
|
|
|
@ -14,6 +14,7 @@ No errors were found on the image.
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: l1_update; errno: 5; imm: off; once: off; write
|
||||
Failed to flush the L2 table cache: Input/output error
|
||||
Failed to flush the refcount block cache: Input/output error
|
||||
write failed: Input/output error
|
||||
|
||||
|
@ -22,6 +23,7 @@ This means waste of disk space, but no harm to data.
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: l1_update; errno: 5; imm: off; once: off; write -b
|
||||
Failed to flush the L2 table cache: Input/output error
|
||||
Failed to flush the refcount block cache: Input/output error
|
||||
write failed: Input/output error
|
||||
|
||||
|
@ -40,6 +42,7 @@ No errors were found on the image.
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: l1_update; errno: 28; imm: off; once: off; write
|
||||
Failed to flush the L2 table cache: No space left on device
|
||||
Failed to flush the refcount block cache: No space left on device
|
||||
write failed: No space left on device
|
||||
|
||||
|
@ -48,6 +51,7 @@ This means waste of disk space, but no harm to data.
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: l1_update; errno: 28; imm: off; once: off; write -b
|
||||
Failed to flush the L2 table cache: No space left on device
|
||||
Failed to flush the refcount block cache: No space left on device
|
||||
write failed: No space left on device
|
||||
|
||||
|
@ -286,12 +290,14 @@ No errors were found on the image.
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: refblock_load; errno: 5; imm: off; once: off; write
|
||||
Failed to flush the L2 table cache: Input/output error
|
||||
Failed to flush the refcount block cache: Input/output error
|
||||
write failed: Input/output error
|
||||
No errors were found on the image.
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: refblock_load; errno: 5; imm: off; once: off; write -b
|
||||
Failed to flush the L2 table cache: Input/output error
|
||||
Failed to flush the refcount block cache: Input/output error
|
||||
write failed: Input/output error
|
||||
No errors were found on the image.
|
||||
|
@ -308,12 +314,14 @@ No errors were found on the image.
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: refblock_load; errno: 28; imm: off; once: off; write
|
||||
Failed to flush the L2 table cache: No space left on device
|
||||
Failed to flush the refcount block cache: No space left on device
|
||||
write failed: No space left on device
|
||||
No errors were found on the image.
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: refblock_load; errno: 28; imm: off; once: off; write -b
|
||||
Failed to flush the L2 table cache: No space left on device
|
||||
Failed to flush the refcount block cache: No space left on device
|
||||
write failed: No space left on device
|
||||
No errors were found on the image.
|
||||
|
@ -330,12 +338,14 @@ No errors were found on the image.
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: refblock_update_part; errno: 5; imm: off; once: off; write
|
||||
Failed to flush the L2 table cache: Input/output error
|
||||
Failed to flush the refcount block cache: Input/output error
|
||||
write failed: Input/output error
|
||||
No errors were found on the image.
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: refblock_update_part; errno: 5; imm: off; once: off; write -b
|
||||
Failed to flush the L2 table cache: Input/output error
|
||||
Failed to flush the refcount block cache: Input/output error
|
||||
write failed: Input/output error
|
||||
No errors were found on the image.
|
||||
|
@ -352,12 +362,14 @@ No errors were found on the image.
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: refblock_update_part; errno: 28; imm: off; once: off; write
|
||||
Failed to flush the L2 table cache: No space left on device
|
||||
Failed to flush the refcount block cache: No space left on device
|
||||
write failed: No space left on device
|
||||
No errors were found on the image.
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: refblock_update_part; errno: 28; imm: off; once: off; write -b
|
||||
Failed to flush the L2 table cache: No space left on device
|
||||
Failed to flush the refcount block cache: No space left on device
|
||||
write failed: No space left on device
|
||||
No errors were found on the image.
|
||||
|
@ -374,12 +386,14 @@ No errors were found on the image.
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: refblock_alloc; errno: 5; imm: off; once: off; write
|
||||
Failed to flush the L2 table cache: Input/output error
|
||||
Failed to flush the refcount block cache: Input/output error
|
||||
write failed: Input/output error
|
||||
No errors were found on the image.
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: refblock_alloc; errno: 5; imm: off; once: off; write -b
|
||||
Failed to flush the L2 table cache: Input/output error
|
||||
Failed to flush the refcount block cache: Input/output error
|
||||
write failed: Input/output error
|
||||
No errors were found on the image.
|
||||
|
@ -396,12 +410,14 @@ No errors were found on the image.
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: refblock_alloc; errno: 28; imm: off; once: off; write
|
||||
Failed to flush the L2 table cache: No space left on device
|
||||
Failed to flush the refcount block cache: No space left on device
|
||||
write failed: No space left on device
|
||||
No errors were found on the image.
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: refblock_alloc; errno: 28; imm: off; once: off; write -b
|
||||
Failed to flush the L2 table cache: No space left on device
|
||||
Failed to flush the refcount block cache: No space left on device
|
||||
write failed: No space left on device
|
||||
No errors were found on the image.
|
||||
|
@ -513,6 +529,7 @@ No errors were found on the image.
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: refblock_alloc_write_blocks; errno: 28; imm: off; once: off; write
|
||||
Failed to flush the L2 table cache: No space left on device
|
||||
Failed to flush the refcount block cache: No space left on device
|
||||
write failed: No space left on device
|
||||
|
||||
|
@ -521,6 +538,7 @@ This means waste of disk space, but no harm to data.
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: refblock_alloc_write_blocks; errno: 28; imm: off; once: off; write -b
|
||||
Failed to flush the L2 table cache: No space left on device
|
||||
Failed to flush the refcount block cache: No space left on device
|
||||
write failed: No space left on device
|
||||
|
||||
|
@ -539,6 +557,7 @@ No errors were found on the image.
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: refblock_alloc_write_table; errno: 28; imm: off; once: off; write
|
||||
Failed to flush the L2 table cache: No space left on device
|
||||
Failed to flush the refcount block cache: No space left on device
|
||||
write failed: No space left on device
|
||||
|
||||
|
@ -547,6 +566,7 @@ This means waste of disk space, but no harm to data.
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: refblock_alloc_write_table; errno: 28; imm: off; once: off; write -b
|
||||
Failed to flush the L2 table cache: No space left on device
|
||||
Failed to flush the refcount block cache: No space left on device
|
||||
write failed: No space left on device
|
||||
|
||||
|
@ -611,6 +631,7 @@ No errors were found on the image.
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: l1_grow_write_table; errno: 5; imm: off; once: off
|
||||
Failed to flush the L2 table cache: Input/output error
|
||||
Failed to flush the refcount block cache: Input/output error
|
||||
write failed: Input/output error
|
||||
No errors were found on the image.
|
||||
|
@ -622,6 +643,7 @@ No errors were found on the image.
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: l1_grow_write_table; errno: 28; imm: off; once: off
|
||||
Failed to flush the L2 table cache: No space left on device
|
||||
Failed to flush the refcount block cache: No space left on device
|
||||
write failed: No space left on device
|
||||
No errors were found on the image.
|
||||
|
|
|
@ -14,6 +14,7 @@ No errors were found on the image.
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: l1_update; errno: 5; imm: off; once: off; write
|
||||
Failed to flush the L2 table cache: Input/output error
|
||||
Failed to flush the refcount block cache: Input/output error
|
||||
write failed: Input/output error
|
||||
|
||||
|
@ -22,6 +23,7 @@ This means waste of disk space, but no harm to data.
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: l1_update; errno: 5; imm: off; once: off; write -b
|
||||
Failed to flush the L2 table cache: Input/output error
|
||||
Failed to flush the refcount block cache: Input/output error
|
||||
write failed: Input/output error
|
||||
|
||||
|
@ -40,6 +42,7 @@ No errors were found on the image.
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: l1_update; errno: 28; imm: off; once: off; write
|
||||
Failed to flush the L2 table cache: No space left on device
|
||||
Failed to flush the refcount block cache: No space left on device
|
||||
write failed: No space left on device
|
||||
|
||||
|
@ -48,6 +51,7 @@ This means waste of disk space, but no harm to data.
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: l1_update; errno: 28; imm: off; once: off; write -b
|
||||
Failed to flush the L2 table cache: No space left on device
|
||||
Failed to flush the refcount block cache: No space left on device
|
||||
write failed: No space left on device
|
||||
|
||||
|
@ -294,12 +298,14 @@ No errors were found on the image.
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: refblock_load; errno: 5; imm: off; once: off; write
|
||||
Failed to flush the L2 table cache: Input/output error
|
||||
Failed to flush the refcount block cache: Input/output error
|
||||
write failed: Input/output error
|
||||
No errors were found on the image.
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: refblock_load; errno: 5; imm: off; once: off; write -b
|
||||
Failed to flush the L2 table cache: Input/output error
|
||||
Failed to flush the refcount block cache: Input/output error
|
||||
write failed: Input/output error
|
||||
No errors were found on the image.
|
||||
|
@ -316,12 +322,14 @@ No errors were found on the image.
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: refblock_load; errno: 28; imm: off; once: off; write
|
||||
Failed to flush the L2 table cache: No space left on device
|
||||
Failed to flush the refcount block cache: No space left on device
|
||||
write failed: No space left on device
|
||||
No errors were found on the image.
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: refblock_load; errno: 28; imm: off; once: off; write -b
|
||||
Failed to flush the L2 table cache: No space left on device
|
||||
Failed to flush the refcount block cache: No space left on device
|
||||
write failed: No space left on device
|
||||
No errors were found on the image.
|
||||
|
@ -338,12 +346,14 @@ No errors were found on the image.
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: refblock_update_part; errno: 5; imm: off; once: off; write
|
||||
Failed to flush the L2 table cache: Input/output error
|
||||
Failed to flush the refcount block cache: Input/output error
|
||||
write failed: Input/output error
|
||||
No errors were found on the image.
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: refblock_update_part; errno: 5; imm: off; once: off; write -b
|
||||
Failed to flush the L2 table cache: Input/output error
|
||||
Failed to flush the refcount block cache: Input/output error
|
||||
write failed: Input/output error
|
||||
No errors were found on the image.
|
||||
|
@ -360,12 +370,14 @@ No errors were found on the image.
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: refblock_update_part; errno: 28; imm: off; once: off; write
|
||||
Failed to flush the L2 table cache: No space left on device
|
||||
Failed to flush the refcount block cache: No space left on device
|
||||
write failed: No space left on device
|
||||
No errors were found on the image.
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: refblock_update_part; errno: 28; imm: off; once: off; write -b
|
||||
Failed to flush the L2 table cache: No space left on device
|
||||
Failed to flush the refcount block cache: No space left on device
|
||||
write failed: No space left on device
|
||||
No errors were found on the image.
|
||||
|
@ -382,12 +394,14 @@ No errors were found on the image.
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: refblock_alloc; errno: 5; imm: off; once: off; write
|
||||
Failed to flush the L2 table cache: Input/output error
|
||||
Failed to flush the refcount block cache: Input/output error
|
||||
write failed: Input/output error
|
||||
No errors were found on the image.
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: refblock_alloc; errno: 5; imm: off; once: off; write -b
|
||||
Failed to flush the L2 table cache: Input/output error
|
||||
Failed to flush the refcount block cache: Input/output error
|
||||
write failed: Input/output error
|
||||
No errors were found on the image.
|
||||
|
@ -404,12 +418,14 @@ No errors were found on the image.
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: refblock_alloc; errno: 28; imm: off; once: off; write
|
||||
Failed to flush the L2 table cache: No space left on device
|
||||
Failed to flush the refcount block cache: No space left on device
|
||||
write failed: No space left on device
|
||||
No errors were found on the image.
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: refblock_alloc; errno: 28; imm: off; once: off; write -b
|
||||
Failed to flush the L2 table cache: No space left on device
|
||||
Failed to flush the refcount block cache: No space left on device
|
||||
write failed: No space left on device
|
||||
No errors were found on the image.
|
||||
|
@ -521,6 +537,7 @@ No errors were found on the image.
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: refblock_alloc_write_blocks; errno: 28; imm: off; once: off; write
|
||||
Failed to flush the L2 table cache: No space left on device
|
||||
Failed to flush the refcount block cache: No space left on device
|
||||
write failed: No space left on device
|
||||
|
||||
|
@ -529,6 +546,7 @@ This means waste of disk space, but no harm to data.
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: refblock_alloc_write_blocks; errno: 28; imm: off; once: off; write -b
|
||||
Failed to flush the L2 table cache: No space left on device
|
||||
Failed to flush the refcount block cache: No space left on device
|
||||
write failed: No space left on device
|
||||
|
||||
|
@ -547,6 +565,7 @@ No errors were found on the image.
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: refblock_alloc_write_table; errno: 28; imm: off; once: off; write
|
||||
Failed to flush the L2 table cache: No space left on device
|
||||
Failed to flush the refcount block cache: No space left on device
|
||||
write failed: No space left on device
|
||||
|
||||
|
@ -555,6 +574,7 @@ This means waste of disk space, but no harm to data.
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: refblock_alloc_write_table; errno: 28; imm: off; once: off; write -b
|
||||
Failed to flush the L2 table cache: No space left on device
|
||||
Failed to flush the refcount block cache: No space left on device
|
||||
write failed: No space left on device
|
||||
|
||||
|
@ -619,6 +639,7 @@ No errors were found on the image.
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: l1_grow_write_table; errno: 5; imm: off; once: off
|
||||
Failed to flush the L2 table cache: Input/output error
|
||||
Failed to flush the refcount block cache: Input/output error
|
||||
write failed: Input/output error
|
||||
No errors were found on the image.
|
||||
|
@ -630,6 +651,7 @@ No errors were found on the image.
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
Event: l1_grow_write_table; errno: 28; imm: off; once: off
|
||||
Failed to flush the L2 table cache: No space left on device
|
||||
Failed to flush the refcount block cache: No space left on device
|
||||
write failed: No space left on device
|
||||
No errors were found on the image.
|
||||
|
|
|
@ -86,5 +86,7 @@ read failed: Input/output error
|
|||
{"return": ""}
|
||||
{"return": {}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"}
|
||||
QEMU_PROG: Failed to flush the L2 table cache: Input/output error
|
||||
QEMU_PROG: Failed to flush the refcount block cache: Input/output error
|
||||
|
||||
*** done
|
||||
|
|
|
@ -53,7 +53,7 @@ class ThrottleTestCase(iotests.QMPTestCase):
|
|||
result = self.vm.qmp("block_set_io_throttle", conv_keys=False, **params)
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
def do_test_throttle(self, ndrives, seconds, params):
|
||||
def do_test_throttle(self, ndrives, seconds, params, first_drive = 0):
|
||||
def check_limit(limit, num):
|
||||
# IO throttling algorithm is discrete, allow 10% error so the test
|
||||
# is more robust
|
||||
|
@ -85,12 +85,14 @@ class ThrottleTestCase(iotests.QMPTestCase):
|
|||
# Send I/O requests to all drives
|
||||
for i in range(rd_nr):
|
||||
for drive in range(0, ndrives):
|
||||
self.vm.hmp_qemu_io("drive%d" % drive, "aio_read %d %d" %
|
||||
idx = first_drive + drive
|
||||
self.vm.hmp_qemu_io("drive%d" % idx, "aio_read %d %d" %
|
||||
(i * rq_size, rq_size))
|
||||
|
||||
for i in range(wr_nr):
|
||||
for drive in range(0, ndrives):
|
||||
self.vm.hmp_qemu_io("drive%d" % drive, "aio_write %d %d" %
|
||||
idx = first_drive + drive
|
||||
self.vm.hmp_qemu_io("drive%d" % idx, "aio_write %d %d" %
|
||||
(i * rq_size, rq_size))
|
||||
|
||||
# We'll store the I/O stats for each drive in these arrays
|
||||
|
@ -105,15 +107,17 @@ class ThrottleTestCase(iotests.QMPTestCase):
|
|||
|
||||
# Read the stats before advancing the clock
|
||||
for i in range(0, ndrives):
|
||||
idx = first_drive + i
|
||||
start_rd_bytes[i], start_rd_iops[i], start_wr_bytes[i], \
|
||||
start_wr_iops[i] = self.blockstats('drive%d' % i)
|
||||
start_wr_iops[i] = self.blockstats('drive%d' % idx)
|
||||
|
||||
self.vm.qtest("clock_step %d" % ns)
|
||||
|
||||
# Read the stats after advancing the clock
|
||||
for i in range(0, ndrives):
|
||||
idx = first_drive + i
|
||||
end_rd_bytes[i], end_rd_iops[i], end_wr_bytes[i], \
|
||||
end_wr_iops[i] = self.blockstats('drive%d' % i)
|
||||
end_wr_iops[i] = self.blockstats('drive%d' % idx)
|
||||
|
||||
# Check that the I/O is within the limits and evenly distributed
|
||||
for i in range(0, ndrives):
|
||||
|
@ -129,6 +133,7 @@ class ThrottleTestCase(iotests.QMPTestCase):
|
|||
self.assertTrue(check_limit(params['iops_rd'], rd_iops))
|
||||
self.assertTrue(check_limit(params['iops_wr'], wr_iops))
|
||||
|
||||
# Connect N drives to a VM and test I/O in all of them
|
||||
def test_all(self):
|
||||
params = {"bps": 4096,
|
||||
"bps_rd": 4096,
|
||||
|
@ -146,6 +151,24 @@ class ThrottleTestCase(iotests.QMPTestCase):
|
|||
self.configure_throttle(ndrives, limits)
|
||||
self.do_test_throttle(ndrives, 5, limits)
|
||||
|
||||
# Connect N drives to a VM and test I/O in just one of them a time
|
||||
def test_one(self):
|
||||
params = {"bps": 4096,
|
||||
"bps_rd": 4096,
|
||||
"bps_wr": 4096,
|
||||
"iops": 10,
|
||||
"iops_rd": 10,
|
||||
"iops_wr": 10,
|
||||
}
|
||||
# Repeat the test for each one of the drives
|
||||
for drive in range(0, self.max_drives):
|
||||
# Pick each out of all possible params and test
|
||||
for tk in params:
|
||||
limits = dict([(k, 0) for k in params])
|
||||
limits[tk] = params[tk] * self.max_drives
|
||||
self.configure_throttle(self.max_drives, limits)
|
||||
self.do_test_throttle(1, 5, limits, drive)
|
||||
|
||||
def test_burst(self):
|
||||
params = {"bps": 4096,
|
||||
"bps_rd": 4096,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
.....
|
||||
.......
|
||||
----------------------------------------------------------------------
|
||||
Ran 5 tests
|
||||
Ran 7 tests
|
||||
|
||||
OK
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Test encrypted read/write using backing files
|
||||
#
|
||||
# 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=berrange@redhat.com
|
||||
|
||||
seq=`basename $0`
|
||||
echo "QA output created by $seq"
|
||||
|
||||
here=`pwd`
|
||||
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 qcow2
|
||||
_supported_proto generic
|
||||
_supported_os Linux
|
||||
|
||||
|
||||
size=128M
|
||||
TEST_IMG_BASE=$TEST_IMG.base
|
||||
|
||||
TEST_IMG_SAVE=$TEST_IMG
|
||||
TEST_IMG=$TEST_IMG_BASE
|
||||
echo "== create base =="
|
||||
IMGOPTS="encryption=on" _make_test_img $size
|
||||
TEST_IMG=$TEST_IMG_SAVE
|
||||
|
||||
echo
|
||||
echo "== writing whole image =="
|
||||
echo "astrochicken" | $QEMU_IO -c "write -P 0xa 0 $size" "$TEST_IMG_BASE" | _filter_qemu_io | _filter_testdir
|
||||
|
||||
echo
|
||||
echo "== verify pattern =="
|
||||
echo "astrochicken" | $QEMU_IO -c "read -P 0xa 0 $size" "$TEST_IMG_BASE" | _filter_qemu_io | _filter_testdir
|
||||
|
||||
echo "== create overlay =="
|
||||
IMGOPTS="encryption=on" _make_test_img -b "$TEST_IMG_BASE" $size
|
||||
|
||||
echo
|
||||
echo "== writing part of a cluster =="
|
||||
echo "astrochicken" | $QEMU_IO -c "write -P 0xe 0 1024" "$TEST_IMG" | _filter_qemu_io | _filter_testdir
|
||||
|
||||
echo
|
||||
echo "== verify pattern =="
|
||||
echo "astrochicken" | $QEMU_IO -c "read -P 0xe 0 1024" "$TEST_IMG" | _filter_qemu_io | _filter_testdir
|
||||
echo
|
||||
echo "== verify pattern =="
|
||||
echo "astrochicken" | $QEMU_IO -c "read -P 0xa 1024 64512" "$TEST_IMG" | _filter_qemu_io | _filter_testdir
|
||||
|
||||
|
||||
# success, all done
|
||||
echo "*** done"
|
||||
rm -f $seq.full
|
||||
status=0
|
|
@ -0,0 +1,36 @@
|
|||
QA output created by 158
|
||||
== create base ==
|
||||
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 encryption=on
|
||||
|
||||
== writing whole image ==
|
||||
Disk image 'TEST_DIR/t.qcow2.base' is encrypted.
|
||||
password:
|
||||
wrote 134217728/134217728 bytes at offset 0
|
||||
128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
|
||||
== verify pattern ==
|
||||
Disk image 'TEST_DIR/t.qcow2.base' is encrypted.
|
||||
password:
|
||||
read 134217728/134217728 bytes at offset 0
|
||||
128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
== create overlay ==
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base encryption=on
|
||||
|
||||
== writing part of a cluster ==
|
||||
Disk image 'TEST_DIR/t.qcow2' is encrypted.
|
||||
password:
|
||||
wrote 1024/1024 bytes at offset 0
|
||||
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
|
||||
== verify pattern ==
|
||||
Disk image 'TEST_DIR/t.qcow2' is encrypted.
|
||||
password:
|
||||
read 1024/1024 bytes at offset 0
|
||||
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
|
||||
== verify pattern ==
|
||||
Disk image 'TEST_DIR/t.qcow2' is encrypted.
|
||||
password:
|
||||
read 64512/64512 bytes at offset 1024
|
||||
63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
*** done
|
|
@ -157,4 +157,5 @@
|
|||
155 rw auto
|
||||
156 rw auto quick
|
||||
157 auto
|
||||
158 rw auto quick
|
||||
162 auto quick
|
||||
|
|
|
@ -370,6 +370,17 @@ static QCryptoCipherTestData test_data[] = {
|
|||
"eb4a427d1923ce3ff262735779a418f2"
|
||||
"0a282df920147beabe421ee5319d0568",
|
||||
},
|
||||
{
|
||||
/* Bad config - cast5-128 has 8 byte block size
|
||||
* which is incompatible with XTS
|
||||
*/
|
||||
.path = "/crypto/cipher/cast5-xts-128",
|
||||
.alg = QCRYPTO_CIPHER_ALG_CAST5_128,
|
||||
.mode = QCRYPTO_CIPHER_MODE_XTS,
|
||||
.key =
|
||||
"27182818284590452353602874713526"
|
||||
"31415926535897932384626433832795",
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -432,15 +443,23 @@ static void test_cipher(const void *opaque)
|
|||
const QCryptoCipherTestData *data = opaque;
|
||||
|
||||
QCryptoCipher *cipher;
|
||||
uint8_t *key, *iv, *ciphertext, *plaintext, *outtext;
|
||||
size_t nkey, niv, nciphertext, nplaintext;
|
||||
char *outtexthex;
|
||||
uint8_t *key, *iv = NULL, *ciphertext = NULL,
|
||||
*plaintext = NULL, *outtext = NULL;
|
||||
size_t nkey, niv = 0, nciphertext = 0, nplaintext = 0;
|
||||
char *outtexthex = NULL;
|
||||
size_t ivsize, keysize, blocksize;
|
||||
Error *err = NULL;
|
||||
|
||||
nkey = unhex_string(data->key, &key);
|
||||
niv = unhex_string(data->iv, &iv);
|
||||
nciphertext = unhex_string(data->ciphertext, &ciphertext);
|
||||
nplaintext = unhex_string(data->plaintext, &plaintext);
|
||||
if (data->iv) {
|
||||
niv = unhex_string(data->iv, &iv);
|
||||
}
|
||||
if (data->ciphertext) {
|
||||
nciphertext = unhex_string(data->ciphertext, &ciphertext);
|
||||
}
|
||||
if (data->plaintext) {
|
||||
nplaintext = unhex_string(data->plaintext, &plaintext);
|
||||
}
|
||||
|
||||
g_assert(nciphertext == nplaintext);
|
||||
|
||||
|
@ -449,8 +468,15 @@ static void test_cipher(const void *opaque)
|
|||
cipher = qcrypto_cipher_new(
|
||||
data->alg, data->mode,
|
||||
key, nkey,
|
||||
&error_abort);
|
||||
g_assert(cipher != NULL);
|
||||
&err);
|
||||
if (data->plaintext) {
|
||||
g_assert(err == NULL);
|
||||
g_assert(cipher != NULL);
|
||||
} else {
|
||||
error_free_or_abort(&err);
|
||||
g_assert(cipher == NULL);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
keysize = qcrypto_cipher_get_key_len(data->alg);
|
||||
blocksize = qcrypto_cipher_get_block_len(data->alg);
|
||||
|
@ -498,6 +524,7 @@ static void test_cipher(const void *opaque)
|
|||
|
||||
g_assert_cmpstr(outtexthex, ==, data->plaintext);
|
||||
|
||||
cleanup:
|
||||
g_free(outtext);
|
||||
g_free(outtexthex);
|
||||
g_free(key);
|
||||
|
|
|
@ -193,6 +193,50 @@ static void test_validate_fail_struct_nested(TestInputVisitorData *data,
|
|||
g_assert(!udp);
|
||||
}
|
||||
|
||||
static void test_validate_fail_struct_missing(TestInputVisitorData *data,
|
||||
const void *unused)
|
||||
{
|
||||
Error *err = NULL;
|
||||
Visitor *v;
|
||||
QObject *any;
|
||||
GenericAlternate *alt;
|
||||
bool present;
|
||||
int en;
|
||||
int64_t i64;
|
||||
uint32_t u32;
|
||||
int8_t i8;
|
||||
char *str;
|
||||
double dbl;
|
||||
|
||||
v = validate_test_init(data, "{}");
|
||||
visit_start_struct(v, NULL, NULL, 0, &error_abort);
|
||||
visit_start_struct(v, "struct", NULL, 0, &err);
|
||||
error_free_or_abort(&err);
|
||||
visit_start_list(v, "list", NULL, 0, &err);
|
||||
error_free_or_abort(&err);
|
||||
visit_start_alternate(v, "alternate", &alt, sizeof(*alt), false, &err);
|
||||
error_free_or_abort(&err);
|
||||
visit_optional(v, "optional", &present);
|
||||
g_assert(!present);
|
||||
visit_type_enum(v, "enum", &en, EnumOne_lookup, &err);
|
||||
error_free_or_abort(&err);
|
||||
visit_type_int(v, "i64", &i64, &err);
|
||||
error_free_or_abort(&err);
|
||||
visit_type_uint32(v, "u32", &u32, &err);
|
||||
error_free_or_abort(&err);
|
||||
visit_type_int8(v, "i8", &i8, &err);
|
||||
error_free_or_abort(&err);
|
||||
visit_type_str(v, "i8", &str, &err);
|
||||
error_free_or_abort(&err);
|
||||
visit_type_number(v, "dbl", &dbl, &err);
|
||||
error_free_or_abort(&err);
|
||||
visit_type_any(v, "any", &any, &err);
|
||||
error_free_or_abort(&err);
|
||||
visit_type_null(v, "null", &err);
|
||||
error_free_or_abort(&err);
|
||||
visit_end_struct(v, NULL);
|
||||
}
|
||||
|
||||
static void test_validate_fail_list(TestInputVisitorData *data,
|
||||
const void *unused)
|
||||
{
|
||||
|
@ -316,6 +360,8 @@ int main(int argc, char **argv)
|
|||
&testdata, test_validate_fail_struct);
|
||||
validate_test_add("/visitor/input-strict/fail/struct-nested",
|
||||
&testdata, test_validate_fail_struct_nested);
|
||||
validate_test_add("/visitor/input-strict/fail/struct-missing",
|
||||
&testdata, test_validate_fail_struct_missing);
|
||||
validate_test_add("/visitor/input-strict/fail/list",
|
||||
&testdata, test_validate_fail_list);
|
||||
validate_test_add("/visitor/input-strict/fail/union-flat",
|
||||
|
|
|
@ -16,8 +16,13 @@
|
|||
#include "qemu/sockets.h"
|
||||
#include "sysemu/char.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "libqos/libqos.h"
|
||||
#include "libqos/pci-pc.h"
|
||||
#include "libqos/virtio-pci.h"
|
||||
|
||||
#include <linux/vhost.h>
|
||||
#include <linux/virtio_ids.h>
|
||||
#include <linux/virtio_net.h>
|
||||
#include <sys/vfs.h>
|
||||
|
||||
/* GLIB version compatibility flags */
|
||||
|
@ -29,14 +34,13 @@
|
|||
#define HAVE_MONOTONIC_TIME
|
||||
#endif
|
||||
|
||||
#define QEMU_CMD_ACCEL " -machine accel=tcg"
|
||||
#define QEMU_CMD_MEM " -m %d -object memory-backend-file,id=mem,size=%dM,"\
|
||||
"mem-path=%s,share=on -numa node,memdev=mem"
|
||||
#define QEMU_CMD_CHR " -chardev socket,id=%s,path=%s%s"
|
||||
#define QEMU_CMD_NETDEV " -netdev vhost-user,id=net0,chardev=%s,vhostforce"
|
||||
#define QEMU_CMD_NET " -device virtio-net-pci,netdev=net0,romfile=./pc-bios/pxe-virtio.rom"
|
||||
#define QEMU_CMD_NET " -device virtio-net-pci,netdev=net0"
|
||||
|
||||
#define QEMU_CMD QEMU_CMD_ACCEL QEMU_CMD_MEM QEMU_CMD_CHR \
|
||||
#define QEMU_CMD QEMU_CMD_MEM QEMU_CMD_CHR \
|
||||
QEMU_CMD_NETDEV QEMU_CMD_NET
|
||||
|
||||
#define HUGETLBFS_MAGIC 0x958458f6
|
||||
|
@ -136,6 +140,30 @@ typedef struct TestServer {
|
|||
static const char *tmpfs;
|
||||
static const char *root;
|
||||
|
||||
static void init_virtio_dev(TestServer *s)
|
||||
{
|
||||
QPCIBus *bus;
|
||||
QVirtioPCIDevice *dev;
|
||||
uint32_t features;
|
||||
|
||||
bus = qpci_init_pc();
|
||||
g_assert_nonnull(bus);
|
||||
|
||||
dev = qvirtio_pci_device_find(bus, VIRTIO_ID_NET);
|
||||
g_assert_nonnull(dev);
|
||||
|
||||
qvirtio_pci_device_enable(dev);
|
||||
qvirtio_reset(&qvirtio_pci, &dev->vdev);
|
||||
qvirtio_set_acknowledge(&qvirtio_pci, &dev->vdev);
|
||||
qvirtio_set_driver(&qvirtio_pci, &dev->vdev);
|
||||
|
||||
features = qvirtio_get_features(&qvirtio_pci, &dev->vdev);
|
||||
features = features & VIRTIO_NET_F_MAC;
|
||||
qvirtio_set_features(&qvirtio_pci, &dev->vdev, features);
|
||||
|
||||
qvirtio_set_driver_ok(&qvirtio_pci, &dev->vdev);
|
||||
}
|
||||
|
||||
static void wait_for_fds(TestServer *s)
|
||||
{
|
||||
gint64 end_time;
|
||||
|
@ -548,6 +576,7 @@ static void test_migrate(void)
|
|||
from = qtest_start(cmd);
|
||||
g_free(cmd);
|
||||
|
||||
init_virtio_dev(s);
|
||||
wait_for_fds(s);
|
||||
size = get_log_size(s);
|
||||
g_assert_cmpint(size, ==, (2 * 1024 * 1024) / (VHOST_LOG_PAGE * 8));
|
||||
|
@ -662,6 +691,7 @@ static void test_reconnect_subprocess(void)
|
|||
qtest_start(cmd);
|
||||
g_free(cmd);
|
||||
|
||||
init_virtio_dev(s);
|
||||
wait_for_fds(s);
|
||||
wait_for_rings_started(s, 2);
|
||||
|
||||
|
@ -728,6 +758,7 @@ int main(int argc, char **argv)
|
|||
|
||||
s = qtest_start(qemu_cmd);
|
||||
g_free(qemu_cmd);
|
||||
init_virtio_dev(server);
|
||||
|
||||
qtest_add_data_func("/vhost-user/read-guest-mem", server, read_guest_mem);
|
||||
qtest_add_func("/vhost-user/migrate", test_migrate);
|
||||
|
|
|
@ -139,6 +139,8 @@ memory_region_subpage_read(int cpu_index, void *mr, uint64_t offset, uint64_t va
|
|||
memory_region_subpage_write(int cpu_index, void *mr, uint64_t offset, uint64_t value, unsigned size) "cpu %d mr %p offset %#"PRIx64" value %#"PRIx64" size %u"
|
||||
memory_region_tb_read(int cpu_index, uint64_t addr, uint64_t value, unsigned size) "cpu %d addr %#"PRIx64" value %#"PRIx64" size %u"
|
||||
memory_region_tb_write(int cpu_index, uint64_t addr, uint64_t value, unsigned size) "cpu %d addr %#"PRIx64" value %#"PRIx64" size %u"
|
||||
memory_region_ram_device_read(int cpu_index, void *mr, uint64_t addr, uint64_t value, unsigned size) "cpu %d mr %p addr %#"PRIx64" value %#"PRIx64" size %u"
|
||||
memory_region_ram_device_write(int cpu_index, void *mr, uint64_t addr, uint64_t value, unsigned size) "cpu %d mr %p addr %#"PRIx64" value %#"PRIx64" size %u"
|
||||
|
||||
### Guest events, keep at bottom
|
||||
|
||||
|
|
8
ui/gtk.c
8
ui/gtk.c
|
@ -1559,6 +1559,9 @@ static void gd_change_page(GtkNotebook *nb, gpointer arg1, guint arg2,
|
|||
TRUE);
|
||||
}
|
||||
gtk_widget_set_sensitive(s->grab_item, on_vga);
|
||||
#ifdef CONFIG_VTE
|
||||
gtk_widget_set_sensitive(s->copy_item, vc->type == GD_VC_VTE);
|
||||
#endif
|
||||
|
||||
gd_update_windowsize(vc);
|
||||
gd_update_cursor(vc);
|
||||
|
@ -2230,6 +2233,11 @@ void gtk_display_init(DisplayState *ds, bool full_screen, bool grab_on_hover)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_VTE
|
||||
gtk_widget_set_sensitive(s->copy_item,
|
||||
gd_vc_find_current(s)->type == GD_VC_VTE);
|
||||
#endif
|
||||
|
||||
if (full_screen) {
|
||||
gtk_menu_item_activate(GTK_MENU_ITEM(s->full_screen_item));
|
||||
}
|
||||
|
|
4
ui/vnc.c
4
ui/vnc.c
|
@ -911,6 +911,10 @@ static void vnc_dpy_copy(DisplayChangeListener *dcl,
|
|||
}
|
||||
}
|
||||
|
||||
if (!vd->server) {
|
||||
/* no client connected */
|
||||
return;
|
||||
}
|
||||
/* do bitblit op on the local surface too */
|
||||
pitch = vnc_server_fb_stride(vd);
|
||||
src_row = vnc_server_fb_ptr(vd, src_x, src_y);
|
||||
|
|
55
util/qht.c
55
util/qht.c
|
@ -133,7 +133,8 @@ struct qht_map {
|
|||
/* trigger a resize when n_added_buckets > n_buckets / div */
|
||||
#define QHT_NR_ADDED_BUCKETS_THRESHOLD_DIV 8
|
||||
|
||||
static void qht_do_resize(struct qht *ht, struct qht_map *new);
|
||||
static void qht_do_resize_reset(struct qht *ht, struct qht_map *new,
|
||||
bool reset);
|
||||
static void qht_grow_maybe(struct qht *ht);
|
||||
|
||||
#ifdef QHT_DEBUG
|
||||
|
@ -408,12 +409,21 @@ void qht_reset(struct qht *ht)
|
|||
qht_map_unlock_buckets(map);
|
||||
}
|
||||
|
||||
static inline void qht_do_resize(struct qht *ht, struct qht_map *new)
|
||||
{
|
||||
qht_do_resize_reset(ht, new, false);
|
||||
}
|
||||
|
||||
static inline void qht_do_resize_and_reset(struct qht *ht, struct qht_map *new)
|
||||
{
|
||||
qht_do_resize_reset(ht, new, true);
|
||||
}
|
||||
|
||||
bool qht_reset_size(struct qht *ht, size_t n_elems)
|
||||
{
|
||||
struct qht_map *new;
|
||||
struct qht_map *new = NULL;
|
||||
struct qht_map *map;
|
||||
size_t n_buckets;
|
||||
bool resize = false;
|
||||
|
||||
n_buckets = qht_elems_to_buckets(n_elems);
|
||||
|
||||
|
@ -421,18 +431,11 @@ bool qht_reset_size(struct qht *ht, size_t n_elems)
|
|||
map = ht->map;
|
||||
if (n_buckets != map->n_buckets) {
|
||||
new = qht_map_create(n_buckets);
|
||||
resize = true;
|
||||
}
|
||||
|
||||
qht_map_lock_buckets(map);
|
||||
qht_map_reset__all_locked(map);
|
||||
if (resize) {
|
||||
qht_do_resize(ht, new);
|
||||
}
|
||||
qht_map_unlock_buckets(map);
|
||||
qht_do_resize_and_reset(ht, new);
|
||||
qemu_mutex_unlock(&ht->lock);
|
||||
|
||||
return resize;
|
||||
return !!new;
|
||||
}
|
||||
|
||||
static inline
|
||||
|
@ -561,9 +564,7 @@ static __attribute__((noinline)) void qht_grow_maybe(struct qht *ht)
|
|||
if (qht_map_needs_resize(map)) {
|
||||
struct qht_map *new = qht_map_create(map->n_buckets * 2);
|
||||
|
||||
qht_map_lock_buckets(map);
|
||||
qht_do_resize(ht, new);
|
||||
qht_map_unlock_buckets(map);
|
||||
}
|
||||
qemu_mutex_unlock(&ht->lock);
|
||||
}
|
||||
|
@ -739,24 +740,31 @@ static void qht_map_copy(struct qht *ht, void *p, uint32_t hash, void *userp)
|
|||
}
|
||||
|
||||
/*
|
||||
* Call with ht->lock and all bucket locks held.
|
||||
*
|
||||
* Creating the @new map here would add unnecessary delay while all the locks
|
||||
* are held--holding up the bucket locks is particularly bad, since no writes
|
||||
* can occur while these are held. Thus, we let callers create the new map,
|
||||
* hopefully without the bucket locks held.
|
||||
* Atomically perform a resize and/or reset.
|
||||
* Call with ht->lock held.
|
||||
*/
|
||||
static void qht_do_resize(struct qht *ht, struct qht_map *new)
|
||||
static void qht_do_resize_reset(struct qht *ht, struct qht_map *new, bool reset)
|
||||
{
|
||||
struct qht_map *old;
|
||||
|
||||
old = ht->map;
|
||||
g_assert_cmpuint(new->n_buckets, !=, old->n_buckets);
|
||||
qht_map_lock_buckets(old);
|
||||
|
||||
if (reset) {
|
||||
qht_map_reset__all_locked(old);
|
||||
}
|
||||
|
||||
if (new == NULL) {
|
||||
qht_map_unlock_buckets(old);
|
||||
return;
|
||||
}
|
||||
|
||||
g_assert_cmpuint(new->n_buckets, !=, old->n_buckets);
|
||||
qht_map_iter__all_locked(ht, old, qht_map_copy, new);
|
||||
qht_map_debug__all_locked(new);
|
||||
|
||||
atomic_rcu_set(&ht->map, new);
|
||||
qht_map_unlock_buckets(old);
|
||||
call_rcu(old, qht_map_destroy, rcu);
|
||||
}
|
||||
|
||||
|
@ -768,12 +776,9 @@ bool qht_resize(struct qht *ht, size_t n_elems)
|
|||
qemu_mutex_lock(&ht->lock);
|
||||
if (n_buckets != ht->map->n_buckets) {
|
||||
struct qht_map *new;
|
||||
struct qht_map *old = ht->map;
|
||||
|
||||
new = qht_map_create(n_buckets);
|
||||
qht_map_lock_buckets(old);
|
||||
qht_do_resize(ht, new);
|
||||
qht_map_unlock_buckets(old);
|
||||
ret = true;
|
||||
}
|
||||
qemu_mutex_unlock(&ht->lock);
|
||||
|
|
15
vl.c
15
vl.c
|
@ -121,6 +121,7 @@ int main(int argc, char **argv)
|
|||
#include "crypto/init.h"
|
||||
#include "sysemu/replay.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "sysemu/iothread.h"
|
||||
|
||||
#define MAX_VIRTIO_CONSOLES 1
|
||||
#define MAX_SCLP_CONSOLES 1
|
||||
|
@ -2810,6 +2811,19 @@ static bool object_create_initial(const char *type)
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Memory allocation by backends needs to be done
|
||||
* after configure_accelerator() (due to the tcg_enabled()
|
||||
* checks at memory_region_init_*()).
|
||||
*
|
||||
* Also, allocation of large amounts of memory may delay
|
||||
* chardev initialization for too long, and trigger timeouts
|
||||
* on software that waits for a monitor socket to be created
|
||||
* (e.g. libvirt).
|
||||
*/
|
||||
if (g_str_has_prefix(type, "memory-backend-")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -4603,6 +4617,7 @@ int main(int argc, char **argv, char **envp)
|
|||
trace_init_vcpu_events();
|
||||
main_loop();
|
||||
replay_disable_events();
|
||||
iothread_stop_all();
|
||||
|
||||
bdrv_close_all();
|
||||
pause_all_vcpus();
|
||||
|
|
Loading…
Reference in New Issue