diff options
40 files changed, 536 insertions, 216 deletions
@@ -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)¶ms; 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 |