summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--block.c108
-rw-r--r--block/bochs.c23
-rw-r--r--block/cow.c2
-rw-r--r--block/curl.c153
-rw-r--r--block/dmg.c8
-rw-r--r--block/mirror.c11
-rw-r--r--block/qapi.c3
-rw-r--r--block/qcow.c3
-rw-r--r--block/qcow2-cluster.c33
-rw-r--r--block/qcow2-refcount.c12
-rw-r--r--block/qcow2.c12
-rw-r--r--block/raw-posix.c5
-rw-r--r--block/raw-win32.c3
-rw-r--r--block/sheepdog.c6
-rw-r--r--block/vdi.c28
-rw-r--r--docs/specs/standard-vga.txt13
-rw-r--r--hw/display/cirrus_vga.c4
-rw-r--r--hw/display/qxl.c2
-rw-r--r--hw/display/vga-isa-mm.c2
-rw-r--r--hw/display/vga-isa.c2
-rw-r--r--hw/display/vga-pci.c63
-rw-r--r--hw/display/vga.c8
-rw-r--r--hw/display/vga_int.h2
-rw-r--r--hw/display/vmware_vga.c2
-rw-r--r--hw/intc/openpic_kvm.c8
-rw-r--r--hw/intc/xics_kvm.c8
-rw-r--r--include/block/block.h1
-rw-r--r--include/block/block_int.h1
-rw-r--r--include/sysemu/kvm.h30
-rw-r--r--qemu-img.c26
-rw-r--r--target-ppc/kvm.c21
-rw-r--r--target-s390x/kvm.c4
-rw-r--r--tests/Makefile5
-rw-r--r--tests/display-vga-test.c52
-rwxr-xr-xtests/qemu-iotests/0192
-rwxr-xr-xtests/qemu-iotests/0868
-rwxr-xr-xtests/qemu-iotests/09061
-rw-r--r--tests/qemu-iotests/090.out12
-rw-r--r--tests/qemu-iotests/common.rc4
-rw-r--r--tests/qemu-iotests/group1
40 files changed, 536 insertions, 216 deletions
diff --git a/block.c b/block.c
index 4745712d22..b749d31ad4 100644
--- a/block.c
+++ b/block.c
@@ -774,6 +774,45 @@ void bdrv_disable_copy_on_read(BlockDriverState *bs)
bs->copy_on_read--;
}
+/*
+ * Returns the flags that bs->file should get, based on the given flags for
+ * the parent BDS
+ */
+static int bdrv_inherited_flags(int flags)
+{
+ /* Enable protocol handling, disable format probing for bs->file */
+ flags |= BDRV_O_PROTOCOL;
+
+ /* Our block drivers take care to send flushes and respect unmap policy,
+ * so we can enable both unconditionally on lower layers. */
+ flags |= BDRV_O_CACHE_WB | BDRV_O_UNMAP;
+
+ /* The backing file of a temporary snapshot is read-only */
+ if (flags & BDRV_O_SNAPSHOT) {
+ flags &= ~BDRV_O_RDWR;
+ }
+
+ /* Clear flags that only apply to the top layer */
+ flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | BDRV_O_COPY_ON_READ);
+
+ return flags;
+}
+
+/*
+ * Returns the flags that bs->backing_hd should get, based on the given flags
+ * for the parent BDS
+ */
+static int bdrv_backing_flags(int flags)
+{
+ /* backing files always opened read-only */
+ flags &= ~(BDRV_O_RDWR | BDRV_O_COPY_ON_READ);
+
+ /* snapshot=on is handled on the top layer */
+ flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_TEMPORARY);
+
+ return flags;
+}
+
static int bdrv_open_flags(BlockDriverState *bs, int flags)
{
int open_flags = flags | BDRV_O_CACHE_WB;
@@ -792,7 +831,7 @@ static int bdrv_open_flags(BlockDriverState *bs, int flags)
/*
* Snapshots should be writable.
*/
- if (bs->is_temporary) {
+ if (flags & BDRV_O_TEMPORARY) {
open_flags |= BDRV_O_RDWR;
}
@@ -951,13 +990,6 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
bdrv_refresh_limits(bs);
assert(bdrv_opt_mem_align(bs) != 0);
assert((bs->request_alignment != 0) || bs->sg);
-
-#ifndef _WIN32
- if (bs->is_temporary) {
- assert(bs->filename[0] != '\0');
- unlink(bs->filename);
- }
-#endif
return 0;
free_and_fail:
@@ -1069,7 +1101,7 @@ fail:
int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
{
char *backing_filename = g_malloc0(PATH_MAX);
- int back_flags, ret = 0;
+ int ret = 0;
BlockDriver *back_drv = NULL;
Error *local_err = NULL;
@@ -1097,14 +1129,10 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
back_drv = bdrv_find_format(bs->backing_format);
}
- /* backing files always opened read-only */
- back_flags = bs->open_flags & ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT |
- BDRV_O_COPY_ON_READ);
-
assert(bs->backing_hd == NULL);
ret = bdrv_open(&bs->backing_hd,
*backing_filename ? backing_filename : NULL, NULL, options,
- back_flags, back_drv, &local_err);
+ bdrv_backing_flags(bs->open_flags), back_drv, &local_err);
if (ret < 0) {
bs->backing_hd = NULL;
bs->open_flags |= BDRV_O_NO_BACKING;
@@ -1232,10 +1260,10 @@ void bdrv_append_temp_snapshot(BlockDriverState *bs, Error **errp)
qstring_from_str(tmp_filename));
bs_snapshot = bdrv_new("", &error_abort);
- bs_snapshot->is_temporary = 1;
ret = bdrv_open(&bs_snapshot, NULL, NULL, snapshot_options,
- bs->open_flags & ~BDRV_O_SNAPSHOT, bdrv_qcow2, &local_err);
+ (bs->open_flags & ~BDRV_O_SNAPSHOT) | BDRV_O_TEMPORARY,
+ bdrv_qcow2, &local_err);
if (ret < 0) {
error_propagate(errp, local_err);
goto out;
@@ -1333,10 +1361,10 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
assert(file == NULL);
ret = bdrv_open_image(&file, filename, options, "file",
- bdrv_open_flags(bs, flags | BDRV_O_UNMAP) |
- BDRV_O_PROTOCOL, true, &local_err);
+ bdrv_inherited_flags(flags),
+ true, &local_err);
if (ret < 0) {
- goto unlink_and_fail;
+ goto fail;
}
/* Find the right image format driver */
@@ -1347,7 +1375,7 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
if (!drv) {
error_setg(errp, "Invalid driver: '%s'", drvname);
ret = -EINVAL;
- goto unlink_and_fail;
+ goto fail;
}
}
@@ -1357,18 +1385,18 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
} else {
error_setg(errp, "Must specify either driver or file");
ret = -EINVAL;
- goto unlink_and_fail;
+ goto fail;
}
}
if (!drv) {
- goto unlink_and_fail;
+ goto fail;
}
/* Open the image */
ret = bdrv_open_common(bs, file, options, flags, drv, &local_err);
if (ret < 0) {
- goto unlink_and_fail;
+ goto fail;
}
if (file && (bs->file != file)) {
@@ -1430,14 +1458,10 @@ done:
*pbs = bs;
return 0;
-unlink_and_fail:
+fail:
if (file != NULL) {
bdrv_unref(file);
}
- if (bs->is_temporary) {
- unlink(filename);
- }
-fail:
QDECREF(bs->options);
QDECREF(options);
bs->options = NULL;
@@ -1501,8 +1525,11 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
QSIMPLEQ_INIT(bs_queue);
}
+ /* bdrv_open() masks this flag out */
+ flags &= ~BDRV_O_PROTOCOL;
+
if (bs->file) {
- bdrv_reopen_queue(bs_queue, bs->file, flags);
+ bdrv_reopen_queue(bs_queue, bs->file, bdrv_inherited_flags(flags));
}
bs_entry = g_new0(BlockReopenQueueEntry, 1);
@@ -1717,11 +1744,6 @@ void bdrv_close(BlockDriverState *bs)
}
bs->drv->bdrv_close(bs);
g_free(bs->opaque);
-#ifdef _WIN32
- if (bs->is_temporary) {
- unlink(bs->filename);
- }
-#endif
bs->opaque = NULL;
bs->drv = NULL;
bs->copy_on_read = 0;
@@ -1845,7 +1867,6 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest,
BlockDriverState *bs_src)
{
/* move some fields that need to stay attached to the device */
- bs_dest->open_flags = bs_src->open_flags;
/* dev info */
bs_dest->dev_ops = bs_src->dev_ops;
@@ -3601,10 +3622,25 @@ void bdrv_iterate_format(void (*it)(void *opaque, const char *name),
void *opaque)
{
BlockDriver *drv;
+ int count = 0;
+ const char **formats = NULL;
QLIST_FOREACH(drv, &bdrv_drivers, list) {
- it(opaque, drv->format_name);
+ if (drv->format_name) {
+ bool found = false;
+ int i = count;
+ while (formats && i && !found) {
+ found = !strcmp(formats[--i], drv->format_name);
+ }
+
+ if (!found) {
+ formats = g_realloc(formats, (count + 1) * sizeof(char *));
+ formats[count++] = drv->format_name;
+ it(opaque, drv->format_name);
+ }
+ }
}
+ g_free(formats);
}
/* This function is to find block backend bs */
diff --git a/block/bochs.c b/block/bochs.c
index eacf956e7d..eba23df335 100644
--- a/block/bochs.c
+++ b/block/bochs.c
@@ -187,13 +187,14 @@ static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
uint64_t offset = sector_num * 512;
uint64_t extent_index, extent_offset, bitmap_offset;
char bitmap_entry;
+ int ret;
// seek to sector
extent_index = offset / s->extent_size;
extent_offset = (offset % s->extent_size) / 512;
if (s->catalog_bitmap[extent_index] == 0xffffffff) {
- return -1; /* not allocated */
+ return 0; /* not allocated */
}
bitmap_offset = s->data_offset +
@@ -201,13 +202,14 @@ static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
(s->extent_blocks + s->bitmap_blocks));
/* read in bitmap for current extent */
- if (bdrv_pread(bs->file, bitmap_offset + (extent_offset / 8),
- &bitmap_entry, 1) != 1) {
- return -1;
+ ret = bdrv_pread(bs->file, bitmap_offset + (extent_offset / 8),
+ &bitmap_entry, 1);
+ if (ret < 0) {
+ return ret;
}
if (!((bitmap_entry >> (extent_offset % 8)) & 1)) {
- return -1; /* not allocated */
+ return 0; /* not allocated */
}
return bitmap_offset + (512 * (s->bitmap_blocks + extent_offset));
@@ -220,13 +222,16 @@ static int bochs_read(BlockDriverState *bs, int64_t sector_num,
while (nb_sectors > 0) {
int64_t block_offset = seek_to_sector(bs, sector_num);
- if (block_offset >= 0) {
+ if (block_offset < 0) {
+ return block_offset;
+ } else if (block_offset > 0) {
ret = bdrv_pread(bs->file, block_offset, buf, 512);
- if (ret != 512) {
- return -1;
+ if (ret < 0) {
+ return ret;
}
- } else
+ } else {
memset(buf, 0, 512);
+ }
nb_sectors--;
sector_num++;
buf += 512;
diff --git a/block/cow.c b/block/cow.c
index 30deb88deb..164759f3a3 100644
--- a/block/cow.c
+++ b/block/cow.c
@@ -82,7 +82,7 @@ static int cow_open(BlockDriverState *bs, QDict *options, int flags,
if (be32_to_cpu(cow_header.version) != COW_VERSION) {
char version[64];
snprintf(version, sizeof(version),
- "COW version %d", cow_header.version);
+ "COW version %" PRIu32, cow_header.version);
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
bs->device_name, "cow", version);
ret = -ENOTSUP;
diff --git a/block/curl.c b/block/curl.c
index 6731d2891f..d2f1084b91 100644
--- a/block/curl.c
+++ b/block/curl.c
@@ -71,6 +71,7 @@ typedef struct CURLState
struct BDRVCURLState *s;
CURLAIOCB *acb[CURL_NUM_ACB];
CURL *curl;
+ curl_socket_t sock_fd;
char *orig_buf;
size_t buf_start;
size_t buf_off;
@@ -92,6 +93,7 @@ typedef struct BDRVCURLState {
static void curl_clean_state(CURLState *s);
static void curl_multi_do(void *arg);
+static void curl_multi_read(void *arg);
#ifdef NEED_CURL_TIMER_CALLBACK
static int curl_timer_cb(CURLM *multi, long timeout_ms, void *opaque)
@@ -113,16 +115,20 @@ static int curl_timer_cb(CURLM *multi, long timeout_ms, void *opaque)
static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
void *s, void *sp)
{
+ CURLState *state = NULL;
+ curl_easy_getinfo(curl, CURLINFO_PRIVATE, (char **)&state);
+ state->sock_fd = fd;
+
DPRINTF("CURL (AIO): Sock action %d on fd %d\n", action, fd);
switch (action) {
case CURL_POLL_IN:
- qemu_aio_set_fd_handler(fd, curl_multi_do, NULL, s);
+ qemu_aio_set_fd_handler(fd, curl_multi_read, NULL, state);
break;
case CURL_POLL_OUT:
- qemu_aio_set_fd_handler(fd, NULL, curl_multi_do, s);
+ qemu_aio_set_fd_handler(fd, NULL, curl_multi_do, state);
break;
case CURL_POLL_INOUT:
- qemu_aio_set_fd_handler(fd, curl_multi_do, curl_multi_do, s);
+ qemu_aio_set_fd_handler(fd, curl_multi_read, curl_multi_do, state);
break;
case CURL_POLL_REMOVE:
qemu_aio_set_fd_handler(fd, NULL, NULL, NULL);
@@ -155,7 +161,7 @@ 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)
- goto read_end;
+ return 0;
if (s->buf_off >= s->buf_len) {
/* buffer full, read nothing */
@@ -180,7 +186,6 @@ static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
}
}
-read_end:
return realsize;
}
@@ -215,7 +220,8 @@ static int curl_find_buf(BDRVCURLState *s, size_t start, size_t len,
}
// Wait for unfinished chunks
- if ((start >= state->buf_start) &&
+ if (state->in_use &&
+ (start >= state->buf_start) &&
(start <= buf_fend) &&
(end >= state->buf_start) &&
(end <= buf_fend))
@@ -237,68 +243,69 @@ static int curl_find_buf(BDRVCURLState *s, size_t start, size_t len,
return FIND_RET_NONE;
}
-static void curl_multi_read(BDRVCURLState *s)
+static void curl_multi_check_completion(BDRVCURLState *s)
{
int msgs_in_queue;
/* Try to find done transfers, so we can free the easy
* handle again. */
- do {
+ for (;;) {
CURLMsg *msg;
msg = curl_multi_info_read(s->multi, &msgs_in_queue);
+ /* Quit when there are no more completions */
if (!msg)
break;
- if (msg->msg == CURLMSG_NONE)
- break;
- switch (msg->msg) {
- case CURLMSG_DONE:
- {
- CURLState *state = NULL;
- curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, (char**)&state);
-
- /* ACBs for successful messages get completed in curl_read_cb */
- if (msg->data.result != CURLE_OK) {
- int i;
- for (i = 0; i < CURL_NUM_ACB; i++) {
- CURLAIOCB *acb = state->acb[i];
-
- if (acb == NULL) {
- continue;
- }
-
- acb->common.cb(acb->common.opaque, -EIO);
- qemu_aio_release(acb);
- state->acb[i] = NULL;
+ if (msg->msg == CURLMSG_DONE) {
+ CURLState *state = NULL;
+ curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE,
+ (char **)&state);
+
+ /* ACBs for successful messages get completed in curl_read_cb */
+ if (msg->data.result != CURLE_OK) {
+ int i;
+ for (i = 0; i < CURL_NUM_ACB; i++) {
+ CURLAIOCB *acb = state->acb[i];
+
+ if (acb == NULL) {
+ continue;
}
- }
- curl_clean_state(state);
- break;
+ acb->common.cb(acb->common.opaque, -EIO);
+ qemu_aio_release(acb);
+ state->acb[i] = NULL;
+ }
}
- default:
- msgs_in_queue = 0;
- break;
+
+ curl_clean_state(state);
+ break;
}
- } while(msgs_in_queue);
+ }
}
static void curl_multi_do(void *arg)
{
- BDRVCURLState *s = (BDRVCURLState *)arg;
+ CURLState *s = (CURLState *)arg;
int running;
int r;
- if (!s->multi) {
+ if (!s->s->multi) {
return;
}
do {
- r = curl_multi_socket_all(s->multi, &running);
+ r = curl_multi_socket_action(s->s->multi, s->sock_fd, 0, &running);
} while(r == CURLM_CALL_MULTI_PERFORM);
- curl_multi_read(s);
+}
+
+static void curl_multi_read(void *arg)
+{
+ CURLState *s = (CURLState *)arg;
+
+ curl_multi_do(arg);
+ curl_multi_check_completion(s->s);
}
static void curl_multi_timeout_do(void *arg)
@@ -313,7 +320,7 @@ static void curl_multi_timeout_do(void *arg)
curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running);
- curl_multi_read(s);
+ curl_multi_check_completion(s);
#else
abort();
#endif
@@ -337,44 +344,42 @@ static CURLState *curl_init_state(BDRVCURLState *s)
break;
}
if (!state) {
- g_usleep(100);
- curl_multi_do(s);
+ qemu_aio_wait();
}
} while(!state);
- if (state->curl)
- goto has_curl;
-
- state->curl = curl_easy_init();
- if (!state->curl)
- return NULL;
- curl_easy_setopt(state->curl, CURLOPT_URL, s->url);
- curl_easy_setopt(state->curl, CURLOPT_TIMEOUT, 5);
- curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION, (void *)curl_read_cb);
- curl_easy_setopt(state->curl, CURLOPT_WRITEDATA, (void *)state);
- curl_easy_setopt(state->curl, CURLOPT_PRIVATE, (void *)state);
- curl_easy_setopt(state->curl, CURLOPT_AUTOREFERER, 1);
- curl_easy_setopt(state->curl, CURLOPT_FOLLOWLOCATION, 1);
- curl_easy_setopt(state->curl, CURLOPT_NOSIGNAL, 1);
- curl_easy_setopt(state->curl, CURLOPT_ERRORBUFFER, state->errmsg);
- curl_easy_setopt(state->curl, CURLOPT_FAILONERROR, 1);
-
- /* Restrict supported protocols to avoid security issues in the more
- * obscure protocols. For example, do not allow POP3/SMTP/IMAP see
- * CVE-2013-0249.
- *
- * Restricting protocols is only supported from 7.19.4 upwards.
- */
+ if (!state->curl) {
+ state->curl = curl_easy_init();
+ if (!state->curl) {
+ return NULL;
+ }
+ curl_easy_setopt(state->curl, CURLOPT_URL, s->url);
+ curl_easy_setopt(state->curl, CURLOPT_TIMEOUT, 5);
+ curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION,
+ (void *)curl_read_cb);
+ curl_easy_setopt(state->curl, CURLOPT_WRITEDATA, (void *)state);
+ curl_easy_setopt(state->curl, CURLOPT_PRIVATE, (void *)state);
+ curl_easy_setopt(state->curl, CURLOPT_AUTOREFERER, 1);
+ curl_easy_setopt(state->curl, CURLOPT_FOLLOWLOCATION, 1);
+ curl_easy_setopt(state->curl, CURLOPT_NOSIGNAL, 1);
+ curl_easy_setopt(state->curl, CURLOPT_ERRORBUFFER, state->errmsg);
+ curl_easy_setopt(state->curl, CURLOPT_FAILONERROR, 1);
+
+ /* Restrict supported protocols to avoid security issues in the more
+ * obscure protocols. For example, do not allow POP3/SMTP/IMAP see
+ * CVE-2013-0249.
+ *
+ * Restricting protocols is only supported from 7.19.4 upwards.
+ */
#if LIBCURL_VERSION_NUM >= 0x071304
- curl_easy_setopt(state->curl, CURLOPT_PROTOCOLS, PROTOCOLS);
- curl_easy_setopt(state->curl, CURLOPT_REDIR_PROTOCOLS, PROTOCOLS);
+ curl_easy_setopt(state->curl, CURLOPT_PROTOCOLS, PROTOCOLS);
+ curl_easy_setopt(state->curl, CURLOPT_REDIR_PROTOCOLS, PROTOCOLS);
#endif
#ifdef DEBUG_VERBOSE
- curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1);
+ curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1);
#endif
-
-has_curl:
+ }
state->s = s;
@@ -531,13 +536,11 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
// initialize the multi interface!
s->multi = curl_multi_init();
- curl_multi_setopt(s->multi, CURLMOPT_SOCKETDATA, s);
curl_multi_setopt(s->multi, CURLMOPT_SOCKETFUNCTION, curl_sock_cb);
#ifdef NEED_CURL_TIMER_CALLBACK
curl_multi_setopt(s->multi, CURLMOPT_TIMERDATA, s);
curl_multi_setopt(s->multi, CURLMOPT_TIMERFUNCTION, curl_timer_cb);
#endif
- curl_multi_do(s);
qemu_opts_del(opts);
return 0;
@@ -566,6 +569,7 @@ static const AIOCBInfo curl_aiocb_info = {
static void curl_readv_bh_cb(void *p)
{
CURLState *state;
+ int running;
CURLAIOCB *acb = p;
BDRVCURLState *s = acb->common.bs->opaque;
@@ -614,8 +618,9 @@ static void curl_readv_bh_cb(void *p)
curl_easy_setopt(state->curl, CURLOPT_RANGE, state->range);
curl_multi_add_handle(s->multi, state->curl);
- curl_multi_do(s);
+ /* Tell curl it needs to kick things off */
+ curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running);
}
static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs,
diff --git a/block/dmg.c b/block/dmg.c
index 856402e1f2..1e153cd76d 100644
--- a/block/dmg.c
+++ b/block/dmg.c
@@ -248,8 +248,8 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
offset += 8;
if (s->sectorcounts[i] > DMG_SECTORCOUNTS_MAX) {
- error_report("sector count %" PRIu64 " for chunk %u is "
- "larger than max (%u)",
+ error_report("sector count %" PRIu64 " for chunk %" PRIu32
+ " is larger than max (%u)",
s->sectorcounts[i], i, DMG_SECTORCOUNTS_MAX);
ret = -EINVAL;
goto fail;
@@ -269,8 +269,8 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
offset += 8;
if (s->lengths[i] > DMG_LENGTHS_MAX) {
- error_report("length %" PRIu64 " for chunk %u is larger "
- "than max (%u)",
+ error_report("length %" PRIu64 " for chunk %" PRIu32
+ " is larger than max (%u)",
s->lengths[i], i, DMG_LENGTHS_MAX);
ret = -EINVAL;
goto fail;
diff --git a/block/mirror.c b/block/mirror.c
index 36f4f8e8bd..1c38aa8f77 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -325,11 +325,11 @@ static void coroutine_fn mirror_run(void *opaque)
s->common.len = bdrv_getlength(bs);
if (s->common.len <= 0) {
- block_job_completed(&s->common, s->common.len);
- return;
+ ret = s->common.len;
+ goto immediate_exit;
}
- length = (bdrv_getlength(bs) + s->granularity - 1) / s->granularity;
+ length = DIV_ROUND_UP(s->common.len, s->granularity);
s->in_flight_bitmap = bitmap_new(length);
/* If we have no backing file yet in the destination, we cannot let
@@ -339,7 +339,10 @@ static void coroutine_fn mirror_run(void *opaque)
bdrv_get_backing_filename(s->target, backing_filename,
sizeof(backing_filename));
if (backing_filename[0] && !s->target->backing_hd) {
- bdrv_get_info(s->target, &bdi);
+ ret = bdrv_get_info(s->target, &bdi);
+ if (ret < 0) {
+ goto immediate_exit;
+ }
if (s->granularity < bdi.cluster_size) {
s->buf_size = MAX(s->buf_size, bdi.cluster_size);
s->cow_bitmap = bitmap_new(length);
diff --git a/block/qapi.c b/block/qapi.c
index 8f2b4dbe7d..af114452e0 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -532,12 +532,11 @@ static void dump_qdict(fprintf_function func_fprintf, void *f, int indentation,
void bdrv_image_info_specific_dump(fprintf_function func_fprintf, void *f,
ImageInfoSpecific *info_spec)
{
- Error *local_err = NULL;
QmpOutputVisitor *ov = qmp_output_visitor_new();
QObject *obj, *data;
visit_type_ImageInfoSpecific(qmp_output_get_visitor(ov), &info_spec, NULL,
- &local_err);
+ &error_abort);
obj = qmp_output_get_qobject(ov);
assert(qobject_type(obj) == QTYPE_QDICT);
data = qdict_get(qobject_to_qdict(obj), "data");
diff --git a/block/qcow.c b/block/qcow.c
index d5a7d5fd1e..937dd6dd1c 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -119,7 +119,8 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
}
if (header.version != QCOW_VERSION) {
char version[64];
- snprintf(version, sizeof(version), "QCOW version %d", header.version);
+ snprintf(version, sizeof(version), "QCOW version %" PRIu32,
+ header.version);
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
bs->device_name, "qcow", version);
ret = -ENOTSUP;
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 331ab08022..76d2bcf63a 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -42,6 +42,13 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
if (min_size <= s->l1_size)
return 0;
+ /* Do a sanity check on min_size before trying to calculate new_l1_size
+ * (this prevents overflows during the while loop for the calculation of
+ * new_l1_size) */
+ if (min_size > INT_MAX / sizeof(uint64_t)) {
+ return -EFBIG;
+ }
+
if (exact_size) {
new_l1_size = min_size;
} else {
@@ -1360,9 +1367,9 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
for (i = 0; i < nb_clusters; i++) {
- uint64_t old_offset;
+ uint64_t old_l2_entry;
- old_offset = be64_to_cpu(l2_table[l2_index + i]);
+ old_l2_entry = be64_to_cpu(l2_table[l2_index + i]);
/*
* Make sure that a discarded area reads back as zeroes for v3 images
@@ -1373,12 +1380,22 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
* TODO We might want to use bdrv_get_block_status(bs) here, but we're
* holding s->lock, so that doesn't work today.
*/
- if (old_offset & QCOW_OFLAG_ZERO) {
- continue;
- }
+ switch (qcow2_get_cluster_type(old_l2_entry)) {
+ case QCOW2_CLUSTER_UNALLOCATED:
+ if (!bs->backing_hd) {
+ continue;
+ }
+ break;
- if ((old_offset & L2E_OFFSET_MASK) == 0 && !bs->backing_hd) {
- continue;
+ case QCOW2_CLUSTER_ZERO:
+ continue;
+
+ case QCOW2_CLUSTER_NORMAL:
+ case QCOW2_CLUSTER_COMPRESSED:
+ break;
+
+ default:
+ abort();
}
/* First remove L2 entries */
@@ -1390,7 +1407,7 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
}
/* Then decrease the refcount */
- qcow2_free_any_clusters(bs, old_offset, 1, type);
+ qcow2_free_any_clusters(bs, old_l2_entry, 1, type);
}
ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index a37ee45016..e79895d11d 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -653,6 +653,13 @@ retry:
goto retry;
}
}
+
+ /* Make sure that all offsets in the "allocated" range are representable
+ * in an int64_t */
+ if (s->free_cluster_index - 1 > (INT64_MAX >> s->cluster_bits)) {
+ return -EFBIG;
+ }
+
#ifdef DEBUG_ALLOC2
fprintf(stderr, "alloc_clusters: size=%" PRId64 " -> %" PRId64 "\n",
size,
@@ -1480,6 +1487,11 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
int ret;
size = bdrv_getlength(bs->file);
+ if (size < 0) {
+ res->check_errors++;
+ return size;
+ }
+
nb_clusters = size_to_clusters(s, size);
if (nb_clusters > INT_MAX) {
res->check_errors++;
diff --git a/block/qcow2.c b/block/qcow2.c
index e903d971c3..a4b97e8263 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -124,8 +124,9 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
case QCOW2_EXT_MAGIC_BACKING_FORMAT:
if (ext.len >= sizeof(bs->backing_format)) {
- error_setg(errp, "ERROR: ext_backing_format: len=%u too large"
- " (>=%zu)", ext.len, sizeof(bs->backing_format));
+ error_setg(errp, "ERROR: ext_backing_format: len=%" PRIu32
+ " too large (>=%zu)", ext.len,
+ sizeof(bs->backing_format));
return 2;
}
ret = bdrv_pread(bs->file, offset, bs->backing_format, ext.len);
@@ -483,7 +484,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
goto fail;
}
if (header.version < 2 || header.version > 3) {
- report_unsupported(bs, errp, "QCOW version %d", header.version);
+ report_unsupported(bs, errp, "QCOW version %" PRIu32, header.version);
ret = -ENOTSUP;
goto fail;
}
@@ -493,7 +494,8 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
/* Initialise cluster size */
if (header.cluster_bits < MIN_CLUSTER_BITS ||
header.cluster_bits > MAX_CLUSTER_BITS) {
- error_setg(errp, "Unsupported cluster size: 2^%i", header.cluster_bits);
+ error_setg(errp, "Unsupported cluster size: 2^%" PRIu32,
+ header.cluster_bits);
ret = -EINVAL;
goto fail;
}
@@ -591,7 +593,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
s->refcount_order = header.refcount_order;
if (header.crypt_method > QCOW_CRYPT_AES) {
- error_setg(errp, "Unsupported encryption method: %i",
+ error_setg(errp, "Unsupported encryption method: %" PRIu32,
header.crypt_method);
ret = -EINVAL;
goto fail;
diff --git a/block/raw-posix.c b/block/raw-posix.c
index 1688e16c64..3ce026db58 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -366,7 +366,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
BDRVRawState *s = bs->opaque;
QemuOpts *opts;
Error *local_err = NULL;
- const char *filename;
+ const char *filename = NULL;
int fd, ret;
struct stat st;
@@ -446,6 +446,9 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
ret = 0;
fail:
+ if (filename && (bdrv_flags & BDRV_O_TEMPORARY)) {
+ unlink(filename);
+ }
qemu_opts_del(opts);
return ret;
}
diff --git a/block/raw-win32.c b/block/raw-win32.c
index 48cb2c2258..064ea3123c 100644
--- a/block/raw-win32.c
+++ b/block/raw-win32.c
@@ -390,6 +390,9 @@ static void raw_close(BlockDriverState *bs)
{
BDRVRawState *s = bs->opaque;
CloseHandle(s->hfile);
+ if (bs->open_flags & BDRV_O_TEMPORARY) {
+ unlink(bs->filename);
+ }
}
static int raw_truncate(BlockDriverState *bs, int64_t offset)
diff --git a/block/sheepdog.c b/block/sheepdog.c
index 0eb33ee80e..2c3fb016a8 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -1099,7 +1099,7 @@ static int find_vdi_name(BDRVSheepdogState *s, const char *filename,
}
if (rsp->result != SD_RES_SUCCESS) {
- error_report("cannot get vdi info, %s, %s %d %s",
+ error_report("cannot get vdi info, %s, %s %" PRIu32 " %s",
sd_strerror(rsp->result), filename, snapid, tag);
if (rsp->result == SD_RES_NO_VDI) {
ret = -ENOENT;
@@ -2316,8 +2316,8 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
sn_tab[found].vm_state_size = inode.vm_state_size;
sn_tab[found].vm_clock_nsec = inode.vm_clock_nsec;
- snprintf(sn_tab[found].id_str, sizeof(sn_tab[found].id_str), "%u",
- inode.snap_id);
+ snprintf(sn_tab[found].id_str, sizeof(sn_tab[found].id_str),
+ "%" PRIu32, inode.snap_id);
pstrcpy(sn_tab[found].name,
MIN(sizeof(sn_tab[found].name), sizeof(inode.tag)),
inode.tag);
diff --git a/block/vdi.c b/block/vdi.c
index 820cd376b3..27737af555 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -408,34 +408,35 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
}
if (header.signature != VDI_SIGNATURE) {
- error_setg(errp, "Image not in VDI format (bad signature %08x)", header.signature);
+ error_setg(errp, "Image not in VDI format (bad signature %08" PRIx32
+ ")", header.signature);
ret = -EINVAL;
goto fail;
} else if (header.version != VDI_VERSION_1_1) {
- error_setg(errp, "unsupported VDI image (version %u.%u)",
- header.version >> 16, header.version & 0xffff);
+ error_setg(errp, "unsupported VDI image (version %" PRIu32 ".%" PRIu32
+ ")", header.version >> 16, header.version & 0xffff);
ret = -ENOTSUP;
goto fail;
} else if (header.offset_bmap % SECTOR_SIZE != 0) {
/* We only support block maps which start on a sector boundary. */
error_setg(errp, "unsupported VDI image (unaligned block map offset "
- "0x%x)", header.offset_bmap);
+ "0x%" PRIx32 ")", header.offset_bmap);
ret = -ENOTSUP;
goto fail;
} else if (header.offset_data % SECTOR_SIZE != 0) {
/* We only support data blocks which start on a sector boundary. */
- error_setg(errp, "unsupported VDI image (unaligned data offset 0x%x)",
- header.offset_data);
+ error_setg(errp, "unsupported VDI image (unaligned data offset 0x%"
+ PRIx32 ")", header.offset_data);
ret = -ENOTSUP;
goto fail;
} else if (header.sector_size != SECTOR_SIZE) {
- error_setg(errp, "unsupported VDI image (sector size %u is not %u)",
- header.sector_size, SECTOR_SIZE);
+ error_setg(errp, "unsupported VDI image (sector size %" PRIu32
+ " is not %u)", header.sector_size, SECTOR_SIZE);
ret = -ENOTSUP;
goto fail;
} else if (header.block_size != DEFAULT_CLUSTER_SIZE) {
- error_setg(errp, "unsupported VDI image (block size %u is not %u)",
- header.block_size, DEFAULT_CLUSTER_SIZE);
+ error_setg(errp, "unsupported VDI image (block size %" PRIu32
+ " is not %u)", header.block_size, DEFAULT_CLUSTER_SIZE);
ret = -ENOTSUP;
goto fail;
} else if (header.disk_size >
@@ -755,6 +756,7 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options,
vdi_header_to_le(&header);
if (write(fd, &header, sizeof(header)) < 0) {
result = -errno;
+ goto close_and_exit;
}
if (bmap_size > 0) {
@@ -768,6 +770,8 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options,
}
if (write(fd, bmap, bmap_size) < 0) {
result = -errno;
+ g_free(bmap);
+ goto close_and_exit;
}
g_free(bmap);
}
@@ -775,10 +779,12 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options,
if (image_type == VDI_TYPE_STATIC) {
if (ftruncate(fd, sizeof(header) + bmap_size + blocks * block_size)) {
result = -errno;
+ goto close_and_exit;
}
}
- if (close(fd) < 0) {
+close_and_exit:
+ if ((close(fd) < 0) && !result) {
result = -errno;
}
diff --git a/docs/specs/standard-vga.txt b/docs/specs/standard-vga.txt
index 8a4c1e93cd..f82773e677 100644
--- a/docs/specs/standard-vga.txt
+++ b/docs/specs/standard-vga.txt
@@ -5,9 +5,10 @@ QEMU Standard VGA
Exists in two variants, for isa and pci.
command line switches:
- -vga std [ picks isa for -M isapc, otherwise pci ]
- -device VGA [ pci variant ]
- -device isa-vga [ isa variant ]
+ -vga std [ picks isa for -M isapc, otherwise pci ]
+ -device VGA [ pci variant ]
+ -device isa-vga [ isa variant ]
+ -device secondary-vga [ legacy-free pci variant ]
PCI spec
@@ -31,9 +32,15 @@ PCI ROM Region:
Holds the vgabios (qemu 0.14+).
+The legacy-free variant has no ROM and has PCI_CLASS_DISPLAY_OTHER
+instead of PCI_CLASS_DISPLAY_VGA.
+
+
IO ports used
-------------
+Doesn't apply to the legacy-free pci variant, use the MMIO bar instead.
+
03c0 - 03df : standard vga ports
01ce : bochs vbe interface index port
01cf : bochs vbe interface data port (x86 only)
diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c
index 0d3127da21..d1afc765fb 100644
--- a/hw/display/cirrus_vga.c
+++ b/hw/display/cirrus_vga.c
@@ -2913,7 +2913,7 @@ static void isa_cirrus_vga_realizefn(DeviceState *dev, Error **errp)
ISACirrusVGAState *d = ISA_CIRRUS_VGA(dev);
VGACommonState *s = &d->cirrus_vga.vga;
- vga_common_init(s, OBJECT(dev));
+ vga_common_init(s, OBJECT(dev), true);
cirrus_init_common(&d->cirrus_vga, OBJECT(dev), CIRRUS_ID_CLGD5430, 0,
isa_address_space(isadev),
isa_address_space_io(isadev));
@@ -2960,7 +2960,7 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev)
int16_t device_id = pc->device_id;
/* setup VGA */
- vga_common_init(&s->vga, OBJECT(dev));
+ vga_common_init(&s->vga, OBJECT(dev), true);
cirrus_init_common(s, OBJECT(dev), device_id, 1, pci_address_space(dev),
pci_address_space_io(dev));
s->vga.con = graphic_console_init(DEVICE(dev), 0, s->vga.hw_ops, &s->vga);
diff --git a/hw/display/qxl.c b/hw/display/qxl.c
index 47bbf1f1fe..e9c54d7399 100644
--- a/hw/display/qxl.c
+++ b/hw/display/qxl.c
@@ -2061,7 +2061,7 @@ static int qxl_init_primary(PCIDevice *dev)
qxl->id = 0;
qxl_init_ramsize(qxl);
vga->vram_size_mb = qxl->vga.vram_size >> 20;
- vga_common_init(vga, OBJECT(dev));
+ vga_common_init(vga, OBJECT(dev), true);
vga_init(vga, OBJECT(dev),
pci_address_space(dev), pci_address_space_io(dev), false);
portio_list_init(qxl_vga_port_list, OBJECT(dev), qxl_vga_portio_list,
diff --git a/hw/display/vga-isa-mm.c b/hw/display/vga-isa-mm.c
index afc46b8c9d..4efc222789 100644
--- a/hw/display/vga-isa-mm.c
+++ b/hw/display/vga-isa-mm.c
@@ -132,7 +132,7 @@ int isa_vga_mm_init(hwaddr vram_base,
s = g_malloc0(sizeof(*s));
s->vga.vram_size_mb = VGA_RAM_SIZE >> 20;
- vga_common_init(&s->vga, NULL);
+ vga_common_init(&s->vga, NULL, true);
vga_mm_init(s, vram_base, ctrl_base, it_shift, address_space);
s->vga.con = graphic_console_init(NULL, 0, s->vga.hw_ops, s);
diff --git a/hw/display/vga-isa.c b/hw/display/vga-isa.c
index 1d9ea6b51d..2b480bd44d 100644
--- a/hw/display/vga-isa.c
+++ b/hw/display/vga-isa.c
@@ -56,7 +56,7 @@ static void vga_isa_realizefn(DeviceState *dev, Error **errp)
MemoryRegion *vga_io_memory;
const MemoryRegionPortio *vga_ports, *vbe_ports;
- vga_common_init(s, OBJECT(dev));
+ 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");
diff --git a/hw/display/vga-pci.c b/hw/display/vga-pci.c
index 574ea0e7f9..0865dc490e 100644
--- a/hw/display/vga-pci.c
+++ b/hw/display/vga-pci.c
@@ -147,7 +147,7 @@ static int pci_std_vga_initfn(PCIDevice *dev)
VGACommonState *s = &d->vga;
/* vga + console init */
- vga_common_init(s, OBJECT(dev));
+ vga_common_init(s, OBJECT(dev), true);
vga_init(s, OBJECT(dev), pci_address_space(dev), pci_address_space_io(dev),
true);
@@ -179,12 +179,51 @@ static int pci_std_vga_initfn(PCIDevice *dev)
return 0;
}
+static int pci_secondary_vga_initfn(PCIDevice *dev)
+{
+ PCIVGAState *d = DO_UPCAST(PCIVGAState, dev, dev);
+ VGACommonState *s = &d->vga;
+
+ /* vga + console init */
+ vga_common_init(s, OBJECT(dev), false);
+ s->con = graphic_console_init(DEVICE(dev), 0, s->hw_ops, s);
+
+ /* mmio bar */
+ memory_region_init(&d->mmio, OBJECT(dev), "vga.mmio", 4096);
+ memory_region_init_io(&d->ioport, OBJECT(dev), &pci_vga_ioport_ops, d,
+ "vga ioports remapped", PCI_VGA_IOPORT_SIZE);
+ memory_region_init_io(&d->bochs, OBJECT(dev), &pci_vga_bochs_ops, d,
+ "bochs dispi interface", PCI_VGA_BOCHS_SIZE);
+
+ memory_region_add_subregion(&d->mmio, PCI_VGA_IOPORT_OFFSET,
+ &d->ioport);
+ memory_region_add_subregion(&d->mmio, PCI_VGA_BOCHS_OFFSET,
+ &d->bochs);
+
+ pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram);
+ pci_register_bar(&d->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio);
+
+ return 0;
+}
+
+static void pci_secondary_vga_reset(DeviceState *dev)
+{
+ PCIVGAState *d = DO_UPCAST(PCIVGAState, dev.qdev, dev);
+
+ vga_common_reset(&d->vga);
+}
+
static Property vga_pci_properties[] = {
DEFINE_PROP_UINT32("vgamem_mb", PCIVGAState, vga.vram_size_mb, 16),
DEFINE_PROP_BIT("mmio", PCIVGAState, flags, PCI_VGA_FLAG_ENABLE_MMIO, true),
DEFINE_PROP_END_OF_LIST(),
};
+static Property secondary_pci_properties[] = {
+ DEFINE_PROP_UINT32("vgamem_mb", PCIVGAState, vga.vram_size_mb, 16),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
static void vga_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -201,6 +240,20 @@ static void vga_class_init(ObjectClass *klass, void *data)
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
}
+static void secondary_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = pci_secondary_vga_initfn;
+ k->vendor_id = PCI_VENDOR_ID_QEMU;
+ k->device_id = PCI_DEVICE_ID_QEMU_VGA;
+ k->class_id = PCI_CLASS_DISPLAY_OTHER;
+ dc->vmsd = &vmstate_vga_pci;
+ dc->props = secondary_pci_properties;
+ dc->reset = pci_secondary_vga_reset;
+}
+
static const TypeInfo vga_info = {
.name = "VGA",
.parent = TYPE_PCI_DEVICE,
@@ -208,9 +261,17 @@ static const TypeInfo vga_info = {
.class_init = vga_class_init,
};
+static const TypeInfo secondary_info = {
+ .name = "secondary-vga",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIVGAState),
+ .class_init = secondary_class_init,
+};
+
static void vga_register_types(void)
{
type_register_static(&vga_info);
+ type_register_static(&secondary_info);
}
type_init(vga_register_types)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 063319d34d..c4c3238d5f 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -171,6 +171,10 @@ static void vga_update_memory_access(VGACommonState *s)
MemoryRegion *region, *old_region = s->chain4_alias;
hwaddr base, offset, size;
+ if (s->legacy_address_space == NULL) {
+ return;
+ }
+
s->chain4_alias = NULL;
if ((s->sr[VGA_SEQ_PLANE_WRITE] & VGA_SR02_ALL_PLANES) ==
@@ -2252,7 +2256,7 @@ static const GraphicHwOps vga_ops = {
.text_update = vga_update_text,
};
-void vga_common_init(VGACommonState *s, Object *obj)
+void vga_common_init(VGACommonState *s, Object *obj, bool global_vmstate)
{
int i, j, v, b;
@@ -2289,7 +2293,7 @@ void vga_common_init(VGACommonState *s, Object *obj)
s->is_vbe_vmstate = 1;
memory_region_init_ram(&s->vram, obj, "vga.vram", s->vram_size);
- vmstate_register_ram_global(&s->vram);
+ vmstate_register_ram(&s->vram, global_vmstate ? NULL : DEVICE(obj));
xen_register_framebuffer(&s->vram);
s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
s->get_bpp = vga_get_bpp;
diff --git a/hw/display/vga_int.h b/hw/display/vga_int.h
index e6418906a7..d42ac926e3 100644
--- a/hw/display/vga_int.h
+++ b/hw/display/vga_int.h
@@ -177,7 +177,7 @@ static inline int c6_to_8(int v)
return (v << 2) | (b << 1) | b;
}
-void vga_common_init(VGACommonState *s, Object *obj);
+void vga_common_init(VGACommonState *s, Object *obj, bool global_vmstate);
void vga_init(VGACommonState *s, Object *obj, MemoryRegion *address_space,
MemoryRegion *address_space_io, bool init_vga_ports);
MemoryRegion *vga_init_io(VGACommonState *s, Object *obj,
diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c
index 6ae3348deb..9ba47e6c63 100644
--- a/hw/display/vmware_vga.c
+++ b/hw/display/vmware_vga.c
@@ -1207,7 +1207,7 @@ static void vmsvga_init(DeviceState *dev, struct vmsvga_state_s *s,
vmstate_register_ram_global(&s->fifo_ram);
s->fifo_ptr = memory_region_get_ram_ptr(&s->fifo_ram);
- vga_common_init(&s->vga, OBJECT(dev));
+ vga_common_init(&s->vga, OBJECT(dev), true);
vga_init(&s->vga, OBJECT(dev), address_space, io, true);
vmstate_register(NULL, 0, &vmstate_vga_common, &s->vga);
s->new_depth = 32;
diff --git a/hw/intc/openpic_kvm.c b/hw/intc/openpic_kvm.c
index 6635407b8b..585ab4ff20 100644
--- a/hw/intc/openpic_kvm.c
+++ b/hw/intc/openpic_kvm.c
@@ -234,13 +234,9 @@ static void kvm_openpic_realize(DeviceState *dev, Error **errp)
int kvm_openpic_connect_vcpu(DeviceState *d, CPUState *cs)
{
KVMOpenPICState *opp = KVM_OPENPIC(d);
- struct kvm_enable_cap encap = {};
- encap.cap = KVM_CAP_IRQ_MPIC;
- encap.args[0] = opp->fd;
- encap.args[1] = kvm_arch_vcpu_id(cs);
-
- return kvm_vcpu_ioctl(cs, KVM_ENABLE_CAP, &encap);
+ return kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_MPIC, 0, opp->fd,
+ kvm_arch_vcpu_id(cs));
}
static Property kvm_openpic_properties[] = {
diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c
index c93dae053d..09476ae34d 100644
--- a/hw/intc/xics_kvm.c
+++ b/hw/intc/xics_kvm.c
@@ -331,15 +331,11 @@ static void xics_kvm_cpu_setup(XICSState *icp, PowerPCCPU *cpu)
if (icpkvm->kernel_xics_fd != -1) {
int ret;
- struct kvm_enable_cap xics_enable_cap = {
- .cap = KVM_CAP_IRQ_XICS,
- .flags = 0,
- .args = {icpkvm->kernel_xics_fd, kvm_arch_vcpu_id(cs), 0, 0},
- };
ss->cs = cs;
- ret = kvm_vcpu_ioctl(ss->cs, KVM_ENABLE_CAP, &xics_enable_cap);
+ ret = kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_XICS, 0,
+ icpkvm->kernel_xics_fd, kvm_arch_vcpu_id(cs));
if (ret < 0) {
error_report("Unable to connect CPU%ld to kernel XICS: %s",
kvm_arch_vcpu_id(cs), strerror(errno));
diff --git a/include/block/block.h b/include/block/block.h
index c12808a252..467fb2ba0a 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -92,6 +92,7 @@ typedef enum {
#define BDRV_O_RDWR 0x0002
#define BDRV_O_SNAPSHOT 0x0008 /* open the file read only and save writes in a snapshot */
+#define BDRV_O_TEMPORARY 0x0010 /* delete the file after use */
#define BDRV_O_NOCACHE 0x0020 /* do not use the host page cache */
#define BDRV_O_CACHE_WB 0x0040 /* use write-back caching */
#define BDRV_O_NATIVE_AIO 0x0080 /* use native AIO instead of the thread pool */
diff --git a/include/block/block_int.h b/include/block/block_int.h
index cd5bc7308a..9ffcb698d0 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -299,7 +299,6 @@ struct BlockDriverState {
char backing_file[1024]; /* if non zero, the image is a diff of
this file image */
char backing_format[16]; /* if non-zero and backing_file exists */
- int is_temporary;
BlockDriverState *backing_hd;
BlockDriverState *file;
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index 0bee1e8996..192fe893b7 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -294,6 +294,36 @@ bool kvm_arch_stop_on_emulation_error(CPUState *cpu);
int kvm_check_extension(KVMState *s, unsigned int extension);
+#define kvm_vm_enable_cap(s, capability, cap_flags, ...) \
+ ({ \
+ struct kvm_enable_cap cap = { \
+ .cap = capability, \
+ .flags = cap_flags, \
+ }; \
+ uint64_t args_tmp[] = { __VA_ARGS__ }; \
+ int i; \
+ for (i = 0; i < ARRAY_SIZE(args_tmp) && \
+ i < ARRAY_SIZE(cap.args); i++) { \
+ cap.args[i] = args_tmp[i]; \
+ } \
+ kvm_vm_ioctl(s, KVM_ENABLE_CAP, &cap); \
+ })
+
+#define kvm_vcpu_enable_cap(cpu, capability, cap_flags, ...) \
+ ({ \
+ struct kvm_enable_cap cap = { \
+ .cap = capability, \
+ .flags = cap_flags, \
+ }; \
+ uint64_t args_tmp[] = { __VA_ARGS__ }; \
+ int i; \
+ for (i = 0; i < ARRAY_SIZE(args_tmp) && \
+ i < ARRAY_SIZE(cap.args); i++) { \
+ cap.args[i] = args_tmp[i]; \
+ } \
+ kvm_vcpu_ioctl(cpu, KVM_ENABLE_CAP, &cap); \
+ })
+
uint32_t kvm_arch_get_supported_cpuid(KVMState *env, uint32_t function,
uint32_t index, int reg);
diff --git a/qemu-img.c b/qemu-img.c
index 968b4c8e83..96f44638b7 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -33,6 +33,9 @@
#include "block/qapi.h"
#include <getopt.h>
+#define QEMU_IMG_VERSION "qemu-img version " QEMU_VERSION \
+ ", Copyright (c) 2004-2008 Fabrice Bellard\n"
+
typedef struct img_cmd_t {
const char *name;
int (*handler)(int argc, char **argv);
@@ -75,7 +78,7 @@ static void QEMU_NORETURN GCC_FMT_ATTR(1, 2) error_exit(const char *fmt, ...)
static void QEMU_NORETURN help(void)
{
const char *help_msg =
- "qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2008 Fabrice Bellard\n"
+ QEMU_IMG_VERSION
"usage: qemu-img command [command options]\n"
"QEMU disk image utility\n"
"\n"
@@ -2789,6 +2792,12 @@ int main(int argc, char **argv)
{
const img_cmd_t *cmd;
const char *cmdname;
+ int c;
+ static const struct option long_options[] = {
+ {"help", no_argument, 0, 'h'},
+ {"version", no_argument, 0, 'v'},
+ {0, 0, 0, 0}
+ };
#ifdef CONFIG_POSIX
signal(SIGPIPE, SIG_IGN);
@@ -2803,15 +2812,24 @@ int main(int argc, char **argv)
error_exit("Not enough arguments");
}
cmdname = argv[1];
- argc--; argv++;
/* find the command */
- for(cmd = img_cmds; cmd->name != NULL; cmd++) {
+ for (cmd = img_cmds; cmd->name != NULL; cmd++) {
if (!strcmp(cmdname, cmd->name)) {
- return cmd->handler(argc, argv);
+ return cmd->handler(argc - 1, argv + 1);
}
}
+ c = getopt_long(argc, argv, "h", long_options, NULL);
+
+ if (c == 'h') {
+ help();
+ }
+ if (c == 'v') {
+ printf(QEMU_IMG_VERSION);
+ return 0;
+ }
+
/* not found */
error_exit("Command not found: %s", cmdname);
}
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index 9974b10ccb..4b81e5f253 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -151,7 +151,6 @@ static int kvm_booke206_tlb_init(PowerPCCPU *cpu)
CPUState *cs = CPU(cpu);
struct kvm_book3e_206_tlb_params params = {};
struct kvm_config_tlb cfg = {};
- struct kvm_enable_cap encap = {};
unsigned int entries = 0;
int ret, i;
@@ -178,10 +177,7 @@ static int kvm_booke206_tlb_init(PowerPCCPU *cpu)
cfg.params = (uintptr_t)&params;
cfg.mmu_type = KVM_MMU_FSL_BOOKE_NOHV;
- encap.cap = KVM_CAP_SW_TLB;
- encap.args[0] = (uintptr_t)&cfg;
-
- ret = kvm_vcpu_ioctl(cs, KVM_ENABLE_CAP, &encap);
+ ret = kvm_vcpu_enable_cap(cs, KVM_CAP_SW_TLB, 0, (uintptr_t)&cfg);
if (ret < 0) {
fprintf(stderr, "%s: couldn't enable KVM_CAP_SW_TLB: %s\n",
__func__, strerror(-ret));
@@ -1292,7 +1288,6 @@ int kvmppc_set_tcr(PowerPCCPU *cpu)
int kvmppc_booke_watchdog_enable(PowerPCCPU *cpu)
{
CPUState *cs = CPU(cpu);
- struct kvm_enable_cap encap = {};
int ret;
if (!kvm_enabled()) {
@@ -1304,8 +1299,7 @@ int kvmppc_booke_watchdog_enable(PowerPCCPU *cpu)
return -1;
}
- encap.cap = KVM_CAP_PPC_BOOKE_WATCHDOG;
- ret = kvm_vcpu_ioctl(cs, KVM_ENABLE_CAP, &encap);
+ ret = kvm_vcpu_enable_cap(cs, KVM_CAP_PPC_BOOKE_WATCHDOG, 0);
if (ret < 0) {
fprintf(stderr, "%s: couldn't enable KVM_CAP_PPC_BOOKE_WATCHDOG: %s\n",
__func__, strerror(-ret));
@@ -1505,12 +1499,9 @@ int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len)
void kvmppc_set_papr(PowerPCCPU *cpu)
{
CPUState *cs = CPU(cpu);
- struct kvm_enable_cap cap = {};
int ret;
- cap.cap = KVM_CAP_PPC_PAPR;
- ret = kvm_vcpu_ioctl(cs, KVM_ENABLE_CAP, &cap);
-
+ ret = kvm_vcpu_enable_cap(cs, KVM_CAP_PPC_PAPR, 0);
if (ret) {
cpu_abort(cs, "This KVM version does not support PAPR\n");
}
@@ -1523,13 +1514,9 @@ void kvmppc_set_papr(PowerPCCPU *cpu)
void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy)
{
CPUState *cs = CPU(cpu);
- struct kvm_enable_cap cap = {};
int ret;
- cap.cap = KVM_CAP_PPC_EPR;
- cap.args[0] = mpic_proxy;
- ret = kvm_vcpu_ioctl(cs, KVM_ENABLE_CAP, &cap);
-
+ ret = kvm_vcpu_enable_cap(cs, KVM_CAP_PPC_EPR, 0, mpic_proxy);
if (ret && mpic_proxy) {
cpu_abort(cs, "This KVM version does not support EPR\n");
}
diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
index a30d1bc060..b7b0edc4f1 100644
--- a/target-s390x/kvm.c
+++ b/target-s390x/kvm.c
@@ -929,12 +929,10 @@ void kvm_s390_crw_mchk(S390CPU *cpu)
void kvm_s390_enable_css_support(S390CPU *cpu)
{
- struct kvm_enable_cap cap = {};
int r;
/* Activate host kernel channel subsystem support. */
- cap.cap = KVM_CAP_S390_CSS_SUPPORT;
- r = kvm_vcpu_ioctl(CPU(cpu), KVM_ENABLE_CAP, &cap);
+ r = kvm_vcpu_enable_cap(CPU(cpu), KVM_CAP_S390_CSS_SUPPORT, 0);
assert(r == 0);
}
diff --git a/tests/Makefile b/tests/Makefile
index 88f7105d02..c6b661472b 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -113,6 +113,10 @@ check-qtest-pci-y += tests/tpci200-test$(EXESUF)
gcov-files-pci-y += hw/ipack/tpci200.c
check-qtest-pci-y += $(check-qtest-ipack-y)
gcov-files-pci-y += $(gcov-files-ipack-y)
+check-qtest-pci-y += tests/display-vga-test$(EXESUF)
+gcov-files-pci-y += hw/display/vga.c
+gcov-files-pci-y += hw/display/cirrus_vga.c
+gcov-files-pci-y += hw/display/vga-pci.c
check-qtest-i386-y = tests/endianness-test$(EXESUF)
check-qtest-i386-y += tests/fdc-test$(EXESUF)
@@ -280,6 +284,7 @@ tests/virtio-9p-test$(EXESUF): tests/virtio-9p-test.o
tests/virtio-serial-test$(EXESUF): tests/virtio-serial-test.o
tests/virtio-console-test$(EXESUF): tests/virtio-console-test.o
tests/tpci200-test$(EXESUF): tests/tpci200-test.o
+tests/display-vga-test$(EXESUF): tests/display-vga-test.o
tests/ipoctal232-test$(EXESUF): tests/ipoctal232-test.o
tests/qom-test$(EXESUF): tests/qom-test.o
tests/blockdev-test$(EXESUF): tests/blockdev-test.o $(libqos-pc-obj-y)
diff --git a/tests/display-vga-test.c b/tests/display-vga-test.c
new file mode 100644
index 0000000000..17f59101e8
--- /dev/null
+++ b/tests/display-vga-test.c
@@ -0,0 +1,52 @@
+/*
+ * QTest testcase for vga cards
+ *
+ * Copyright (c) 2014 Red Hat, Inc
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <glib.h>
+#include <string.h>
+#include "libqtest.h"
+#include "qemu/osdep.h"
+
+static void pci_cirrus(void)
+{
+ qtest_start("-vga none -device cirrus-vga");
+ qtest_end();
+}
+
+static void pci_stdvga(void)
+{
+ qtest_start("-vga none -device VGA");
+ qtest_end();
+}
+
+static void pci_secondary(void)
+{
+ qtest_start("-vga none -device secondary-vga");
+ qtest_end();
+}
+
+static void pci_multihead(void)
+{
+ qtest_start("-vga none -device VGA -device secondary-vga");
+ qtest_end();
+}
+
+int main(int argc, char **argv)
+{
+ int ret;
+
+ g_test_init(&argc, &argv, NULL);
+
+ qtest_add_func("/display/pci/cirrus", pci_cirrus);
+ qtest_add_func("/display/pci/stdvga", pci_stdvga);
+ qtest_add_func("/display/pci/secondary", pci_secondary);
+ qtest_add_func("/display/pci/multihead", pci_multihead);
+ ret = g_test_run();
+
+ return ret;
+}
diff --git a/tests/qemu-iotests/019 b/tests/qemu-iotests/019
index e67445c754..f5ecbf5451 100755
--- a/tests/qemu-iotests/019
+++ b/tests/qemu-iotests/019
@@ -96,7 +96,7 @@ mv "$TEST_IMG" "$TEST_IMG.orig"
for backing_option in "-B " "-o backing_file="; do
echo
- echo Testing conversion with $backing_option$TEST_IMG.base | _filter_testdir | _filter_imgfmt
+ echo Testing conversion with $backing_option"$TEST_IMG.base" | _filter_testdir | _filter_imgfmt
echo
$QEMU_IMG convert -O $IMGFMT $backing_option"$TEST_IMG.base" "$TEST_IMG.orig" "$TEST_IMG"
diff --git a/tests/qemu-iotests/086 b/tests/qemu-iotests/086
index 48fe85bc43..d9a80cf863 100755
--- a/tests/qemu-iotests/086
+++ b/tests/qemu-iotests/086
@@ -51,10 +51,10 @@ function run_qemu_img()
size=128M
_make_test_img $size
-$QEMU_IO -c 'write 0 1M' $TEST_IMG | _filter_qemu_io
-$QEMU_IO -c 'write 2M 1M' $TEST_IMG | _filter_qemu_io
-$QEMU_IO -c 'write 4M 1M' $TEST_IMG | _filter_qemu_io
-$QEMU_IO -c 'write 32M 1M' $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c 'write 0 1M' "$TEST_IMG" | _filter_qemu_io
+$QEMU_IO -c 'write 2M 1M' "$TEST_IMG" | _filter_qemu_io
+$QEMU_IO -c 'write 4M 1M' "$TEST_IMG" | _filter_qemu_io
+$QEMU_IO -c 'write 32M 1M' "$TEST_IMG" | _filter_qemu_io
$QEMU_IMG convert -p -O $IMGFMT -f $IMGFMT "$TEST_IMG" "$TEST_IMG".base 2>&1 |\
_filter_testdir | sed -e 's/\r/\n/g'
diff --git a/tests/qemu-iotests/090 b/tests/qemu-iotests/090
new file mode 100755
index 0000000000..8d032f8111
--- /dev/null
+++ b/tests/qemu-iotests/090
@@ -0,0 +1,61 @@
+#!/bin/bash
+#
+# Test for discarding compressed clusters on qcow2 images
+#
+# Copyright (C) 2014 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=mreitz@redhat.com
+
+seq="$(basename $0)"
+echo "QA output created by $seq"
+
+here="$PWD"
+tmp=/tmp/$$
+status=1 # failure is the default!
+
+_cleanup()
+{
+ _cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt qcow2
+_supported_proto file
+_supported_os Linux
+
+IMG_SIZE=128K
+
+_make_test_img $IMG_SIZE
+
+$QEMU_IO -c 'write -c -P 42 0 64k' \
+ -c 'write -c -P 23 64k 64k' \
+ -c 'discard 64k 64k' \
+ "$TEST_IMG" | _filter_qemu_io
+
+$QEMU_IO -c 'read -P 0 64k 64k' "$TEST_IMG" | _filter_qemu_io
+
+_check_test_img
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/090.out b/tests/qemu-iotests/090.out
new file mode 100644
index 0000000000..2df93e0d97
--- /dev/null
+++ b/tests/qemu-iotests/090.out
@@ -0,0 +1,12 @@
+QA output created by 090
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072
+wrote 65536/65536 bytes at offset 0
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 65536/65536 bytes at offset 65536
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+discard 65536/65536 bytes at offset 65536
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 65536/65536 bytes at offset 65536
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+No errors were found on the image.
+*** done
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
index 7f00883cad..195c5646aa 100644
--- a/tests/qemu-iotests/common.rc
+++ b/tests/qemu-iotests/common.rc
@@ -178,10 +178,10 @@ _rm_test_img()
local img=$1
if [ "$IMGFMT" = "vmdk" ]; then
# Remove all the extents for vmdk
- $QEMU_IMG info $img 2>/dev/null | grep 'filename:' | cut -f 2 -d: \
+ "$QEMU_IMG" info "$img" 2>/dev/null | grep 'filename:' | cut -f 2 -d: \
| xargs -I {} rm -f "{}"
fi
- rm -f $img
+ rm -f "$img"
}
_cleanup_test_img()
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 864643d256..ae096638b8 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -95,3 +95,4 @@
086 rw auto quick
087 rw auto
088 rw auto
+090 rw auto quick