Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging

Block patches

# gpg: Signature made Wed 30 Apr 2014 19:19:32 BST using RSA key ID C88F2FD6
# gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>"

* remotes/kevin/tags/for-upstream: (31 commits)
  curl: Fix hang reading from slow connections
  curl: Ensure all informationals are checked for completion
  curl: Eliminate unnecessary use of curl_multi_socket_all
  curl: Remove unnecessary explicit calls to internal event handler
  curl: Remove erroneous sleep waiting for curl completion
  curl: Fix return from curl_read_cb with invalid state
  curl: Remove unnecessary use of goto
  curl: Fix long line
  block/vdi: Error out immediately in vdi_create()
  block/bochs: Fix error handling for seek_to_sector()
  qcow2: Check min_size in qcow2_grow_l1_table()
  qcow2: Catch bdrv_getlength() error
  block: Use correct width in format strings
  qcow2: Avoid overflow in alloc_clusters_noref()
  block: Use error_abort in bdrv_image_info_specific_dump()
  block: Fix open_flags in bdrv_reopen()
  Revert "block: another bdrv_append fix"
  block: Unlink temporary files in raw-posix/win32
  block: Remove BDRV_O_COPY_ON_READ for bs->file
  block: Create bdrv_backing_flags()
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
diff --git a/block.c b/block.c
index 4745712..b749d31 100644
--- a/block.c
+++ b/block.c
@@ -774,6 +774,45 @@
     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 @@
     /*
      * Snapshots should be writable.
      */
-    if (bs->is_temporary) {
+    if (flags & BDRV_O_TEMPORARY) {
         open_flags |= BDRV_O_RDWR;
     }
 
@@ -951,13 +990,6 @@
     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 @@
 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 @@
         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 @@
               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 @@
 
     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 @@
         if (!drv) {
             error_setg(errp, "Invalid driver: '%s'", drvname);
             ret = -EINVAL;
-            goto unlink_and_fail;
+            goto fail;
         }
     }
 
@@ -1357,18 +1385,18 @@
         } 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 @@
     *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 @@
         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 @@
         }
         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 @@
                                      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 *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 eacf956..eba23df 100644
--- a/block/bochs.c
+++ b/block/bochs.c
@@ -187,13 +187,14 @@
     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 @@
         (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 @@
 
     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 30deb88..164759f 100644
--- a/block/cow.c
+++ b/block/cow.c
@@ -82,7 +82,7 @@
     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 6731d28..d2f1084 100644
--- a/block/curl.c
+++ b/block/curl.c
@@ -71,6 +71,7 @@
     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 @@
 
 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_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 @@
     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 @@
         }
     }
 
-read_end:
     return realsize;
 }
 
@@ -215,7 +220,8 @@
         }
 
         // 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 @@
     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);
+        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];
+            /* 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 (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 @@
 
     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 @@
             break;
         }
         if (!state) {
-            g_usleep(100);
-            curl_multi_do(s);
+            qemu_aio_wait();
         }
     } while(!state);
 
-    if (state->curl)
-        goto has_curl;
+    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);
 
-    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.
-     */
+        /* 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 @@
     // 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 void curl_readv_bh_cb(void *p)
 {
     CURLState *state;
+    int running;
 
     CURLAIOCB *acb = p;
     BDRVCURLState *s = acb->common.bs->opaque;
@@ -614,8 +618,9 @@
     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 856402e..1e153cd 100644
--- a/block/dmg.c
+++ b/block/dmg.c
@@ -248,8 +248,8 @@
                 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 @@
                 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 36f4f8e..1c38aa8 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -325,11 +325,11 @@
 
     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 @@
     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 8f2b4db..af11445 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -532,12 +532,11 @@
 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 d5a7d5f..937dd6d 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -119,7 +119,8 @@
     }
     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 331ab08..76d2bcf 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -42,6 +42,13 @@
     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 @@
     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 @@
          * 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 @@
         }
 
         /* 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 a37ee45..e79895d 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -653,6 +653,13 @@
             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 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 e903d97..a4b97e8 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -124,8 +124,9 @@
 
         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 @@
         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 @@
     /* 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 @@
     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 1688e16..3ce026d 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -366,7 +366,7 @@
     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 @@
 
     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 48cb2c2..064ea31 100644
--- a/block/raw-win32.c
+++ b/block/raw-win32.c
@@ -390,6 +390,9 @@
 {
     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 0eb33ee..2c3fb01 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -1099,7 +1099,7 @@
     }
 
     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 @@
             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 820cd37..27737af 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -408,34 +408,35 @@
     }
 
     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 @@
     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 @@
         }
         if (write(fd, bmap, bmap_size) < 0) {
             result = -errno;
+            g_free(bmap);
+            goto close_and_exit;
         }
         g_free(bmap);
     }
@@ -775,10 +779,12 @@
     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/include/block/block.h b/include/block/block.h
index c12808a..467fb2b 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -92,6 +92,7 @@
 
 #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 cd5bc73..9ffcb69 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -299,7 +299,6 @@
     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/qemu-img.c b/qemu-img.c
index 968b4c8..96f4463 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 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 @@
 {
     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 @@
         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/tests/qemu-iotests/019 b/tests/qemu-iotests/019
index e67445c..f5ecbf5 100755
--- a/tests/qemu-iotests/019
+++ b/tests/qemu-iotests/019
@@ -96,7 +96,7 @@
 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 48fe85b..d9a80cf 100755
--- a/tests/qemu-iotests/086
+++ b/tests/qemu-iotests/086
@@ -51,10 +51,10 @@
 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 0000000..8d032f8
--- /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 0000000..2df93e0
--- /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 7f00883..195c564 100644
--- a/tests/qemu-iotests/common.rc
+++ b/tests/qemu-iotests/common.rc
@@ -178,10 +178,10 @@
     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 864643d..ae09663 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