qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Stefan Hajnoczi <stefanha@redhat.com>
To: qemu-devel@nongnu.org
Cc: Kevin Wolf <kwolf@redhat.com>,
	Peter Maydell <peter.maydell@linaro.org>,
	Max Reitz <mreitz@redhat.com>
Subject: [Qemu-devel] [PULL 21/69] qcow2: Helper for refcount array reallocation
Date: Fri, 27 Feb 2015 18:18:19 +0000	[thread overview]
Message-ID: <1425061147-1411-22-git-send-email-stefanha@redhat.com> (raw)
In-Reply-To: <1425061147-1411-1-git-send-email-stefanha@redhat.com>

From: Max Reitz <mreitz@redhat.com>

Add a helper function for reallocating a refcount array, independent of
the refcount order. The newly allocated space is zeroed and the function
handles failed reallocations gracefully.

The helper function will always align the buffer size to a cluster
boundary; if storing the refcounts in such an array in big endian byte
order, this makes it possible to write parts of the array directly as
refcount blocks into the image file.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block/qcow2-refcount.c | 128 ++++++++++++++++++++++++++++++-------------------
 1 file changed, 80 insertions(+), 48 deletions(-)

diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index e86a1d6..497364f 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -1095,6 +1095,63 @@ fail:
 /* refcount checking functions */
 
 
+static size_t refcount_array_byte_size(BDRVQcowState *s, uint64_t entries)
+{
+    /* This assertion holds because there is no way we can address more than
+     * 2^(64 - 9) clusters at once (with cluster size 512 = 2^9, and because
+     * offsets have to be representable in bytes); due to every cluster
+     * corresponding to one refcount entry, we are well below that limit */
+    assert(entries < (UINT64_C(1) << (64 - 9)));
+
+    /* Thanks to the assertion this will not overflow, because
+     * s->refcount_order < 7.
+     * (note: x << s->refcount_order == x * s->refcount_bits) */
+    return DIV_ROUND_UP(entries << s->refcount_order, 8);
+}
+
+/**
+ * Reallocates *array so that it can hold new_size entries. *size must contain
+ * the current number of entries in *array. If the reallocation fails, *array
+ * and *size will not be modified and -errno will be returned. If the
+ * reallocation is successful, *array will be set to the new buffer, *size
+ * will be set to new_size and 0 will be returned. The size of the reallocated
+ * refcount array buffer will be aligned to a cluster boundary, and the newly
+ * allocated area will be zeroed.
+ */
+static int realloc_refcount_array(BDRVQcowState *s, uint16_t **array,
+                                  int64_t *size, int64_t new_size)
+{
+    size_t old_byte_size, new_byte_size;
+    uint16_t *new_ptr;
+
+    /* Round to clusters so the array can be directly written to disk */
+    old_byte_size = size_to_clusters(s, refcount_array_byte_size(s, *size))
+                    * s->cluster_size;
+    new_byte_size = size_to_clusters(s, refcount_array_byte_size(s, new_size))
+                    * s->cluster_size;
+
+    if (new_byte_size == old_byte_size) {
+        *size = new_size;
+        return 0;
+    }
+
+    assert(new_byte_size > 0);
+
+    new_ptr = g_try_realloc(*array, new_byte_size);
+    if (!new_ptr) {
+        return -ENOMEM;
+    }
+
+    if (new_byte_size > old_byte_size) {
+        memset((void *)((uintptr_t)new_ptr + old_byte_size), 0,
+               new_byte_size - old_byte_size);
+    }
+
+    *array = new_ptr;
+    *size  = new_size;
+
+    return 0;
+}
 
 /*
  * Increases the refcount for a range of clusters in a given refcount table.
@@ -1111,6 +1168,7 @@ static int inc_refcounts(BlockDriverState *bs,
 {
     BDRVQcowState *s = bs->opaque;
     uint64_t start, last, cluster_offset, k;
+    int ret;
 
     if (size <= 0) {
         return 0;
@@ -1122,23 +1180,12 @@ static int inc_refcounts(BlockDriverState *bs,
         cluster_offset += s->cluster_size) {
         k = cluster_offset >> s->cluster_bits;
         if (k >= *refcount_table_size) {
-            int64_t old_refcount_table_size = *refcount_table_size;
-            uint16_t *new_refcount_table;
-
-            *refcount_table_size = k + 1;
-            new_refcount_table = g_try_realloc(*refcount_table,
-                                               *refcount_table_size *
-                                               sizeof(**refcount_table));
-            if (!new_refcount_table) {
-                *refcount_table_size = old_refcount_table_size;
+            ret = realloc_refcount_array(s, refcount_table,
+                                         refcount_table_size, k + 1);
+            if (ret < 0) {
                 res->check_errors++;
-                return -ENOMEM;
+                return ret;
             }
-            *refcount_table = new_refcount_table;
-
-            memset(*refcount_table + old_refcount_table_size, 0,
-                   (*refcount_table_size - old_refcount_table_size) *
-                   sizeof(**refcount_table));
         }
 
         if (++(*refcount_table)[k] == 0) {
@@ -1507,8 +1554,7 @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
                     fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR", i);
 
             if (fix & BDRV_FIX_ERRORS) {
-                int64_t old_nb_clusters = *nb_clusters;
-                uint16_t *new_refcount_table;
+                int64_t new_nb_clusters;
 
                 if (offset > INT64_MAX - s->cluster_size) {
                     ret = -EINVAL;
@@ -1525,22 +1571,15 @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
                     goto resize_fail;
                 }
 
-                *nb_clusters = size_to_clusters(s, size);
-                assert(*nb_clusters >= old_nb_clusters);
+                new_nb_clusters = size_to_clusters(s, size);
+                assert(new_nb_clusters >= *nb_clusters);
 
-                new_refcount_table = g_try_realloc(*refcount_table,
-                                                   *nb_clusters *
-                                                   sizeof(**refcount_table));
-                if (!new_refcount_table) {
-                    *nb_clusters = old_nb_clusters;
+                ret = realloc_refcount_array(s, refcount_table,
+                                             nb_clusters, new_nb_clusters);
+                if (ret < 0) {
                     res->check_errors++;
-                    return -ENOMEM;
+                    return ret;
                 }
-                *refcount_table = new_refcount_table;
-
-                memset(*refcount_table + old_nb_clusters, 0,
-                       (*nb_clusters - old_nb_clusters) *
-                       sizeof(**refcount_table));
 
                 if (cluster >= *nb_clusters) {
                     ret = -EINVAL;
@@ -1600,10 +1639,12 @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
     int ret;
 
     if (!*refcount_table) {
-        *refcount_table = g_try_new0(uint16_t, *nb_clusters);
-        if (*nb_clusters && *refcount_table == NULL) {
+        int64_t old_size = 0;
+        ret = realloc_refcount_array(s, refcount_table,
+                                     &old_size, *nb_clusters);
+        if (ret < 0) {
             res->check_errors++;
-            return -ENOMEM;
+            return ret;
         }
     }
 
@@ -1737,6 +1778,7 @@ static int64_t alloc_clusters_imrt(BlockDriverState *bs,
     int64_t cluster = *first_free_cluster, i;
     bool first_gap = true;
     int contiguous_free_clusters;
+    int ret;
 
     /* Starting at *first_free_cluster, find a range of at least cluster_count
      * continuously free clusters */
@@ -1766,28 +1808,18 @@ static int64_t alloc_clusters_imrt(BlockDriverState *bs,
     /* If no such range could be found, grow the in-memory refcount table
      * accordingly to append free clusters at the end of the image */
     if (contiguous_free_clusters < cluster_count) {
-        int64_t old_imrt_nb_clusters = *imrt_nb_clusters;
-        uint16_t *new_refcount_table;
-
         /* contiguous_free_clusters clusters are already empty at the image end;
          * we need cluster_count clusters; therefore, we have to allocate
          * cluster_count - contiguous_free_clusters new clusters at the end of
          * the image (which is the current value of cluster; note that cluster
          * may exceed old_imrt_nb_clusters if *first_free_cluster pointed beyond
          * the image end) */
-        *imrt_nb_clusters = cluster + cluster_count - contiguous_free_clusters;
-        new_refcount_table = g_try_realloc(*refcount_table,
-                                           *imrt_nb_clusters *
-                                           sizeof(**refcount_table));
-        if (!new_refcount_table) {
-            *imrt_nb_clusters = old_imrt_nb_clusters;
-            return -ENOMEM;
+        ret = realloc_refcount_array(s, refcount_table, imrt_nb_clusters,
+                                     cluster + cluster_count
+                                     - contiguous_free_clusters);
+        if (ret < 0) {
+            return ret;
         }
-        *refcount_table = new_refcount_table;
-
-        memset(*refcount_table + old_imrt_nb_clusters, 0,
-               (*imrt_nb_clusters - old_imrt_nb_clusters) *
-               sizeof(**refcount_table));
     }
 
     /* Go back to the first free cluster */
-- 
2.1.0

  parent reply	other threads:[~2015-02-27 18:20 UTC|newest]

Thread overview: 78+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-02-27 18:17 [Qemu-devel] [PULL 00/69] Block patches Stefan Hajnoczi
2015-02-27 18:17 ` [Qemu-devel] [PULL 01/69] coroutine: Fix use after free with qemu_coroutine_yield() Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 02/69] coroutine: Clean up qemu_coroutine_enter() Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 03/69] test-coroutine: Regression test for yield bug Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 04/69] vpc: Fix size in fixed image creation Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 05/69] vpc: Implement bdrv_co_get_block_status() Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 06/69] sheepdog: selectable object size support Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 07/69] block/raw-posix: fix compilation warning on OSX Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 08/69] qcow2: Remove unused struct QCowCreateState Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 09/69] virtio-blk: Check return value of blk_aio_ioctl Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 10/69] libqos: Change use of pointers to uint64_t in virtio Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 11/69] tests: Prepare virtio-blk-test for multi-arch implementation Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 12/69] libqos: Remove PCI assumptions in constants of virtio driver Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 13/69] libqos: Add malloc generic Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 14/69] libqos: Add virtio MMIO support Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 15/69] qcow2: Add two new fields to BDRVQcowState Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 16/69] qcow2: Add refcount_bits to format-specific info Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 17/69] qcow2: Do not return new value after refcount update Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 18/69] qcow2: Only return status from qcow2_get_refcount Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 19/69] qcow2: Use unsigned addend for update_refcount() Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 20/69] qcow2: Use 64 bits for refcount values Stefan Hajnoczi
2015-02-27 18:18 ` Stefan Hajnoczi [this message]
2015-02-27 18:18 ` [Qemu-devel] [PULL 22/69] qcow2: Helper function for refcount modification Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 23/69] qcow2: More helpers " Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 24/69] qcow2: Open images with refcount order != 4 Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 25/69] qcow2: refcount_order parameter for qcow2_create2 Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 26/69] qcow2: Use symbolic macros in qcow2_amend_options Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 27/69] iotests: Prepare for refcount_bits option Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 28/69] qcow2: Allow creation with refcount order != 4 Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 29/69] iotests: Add test for different refcount widths Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 30/69] blkdebug: fix "once" rule Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 31/69] block: add bdrv functions for geometry and blocksize Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 32/69] raw-posix: Factor block size detection out of raw_probe_alignment() Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 33/69] block: Add driver methods to probe blocksizes and geometry Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 34/69] block-backend: Add wrappers for blocksizes and geometry probing Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 35/69] BlockConf: Call backend functions to detect geometry and blocksizes Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 36/69] ide: start extracting ide_restart_dma out of bmdma_restart_dma Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 37/69] ide: prepare to move restart to common code Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 38/69] ide: introduce ide_register_restart_cb Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 39/69] ide: do not use BMDMA in restart callback Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 40/69] ide: pass IDEBus to the restart_cb Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 41/69] ide: move restart callback to common code Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 42/69] ide: remove restart_cb callback Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 43/69] ide: replace set_unit callback with more IDEBus state Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 44/69] ide: place initial state of the current request to IDEBus Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 45/69] ide: migrate initial request state via IDEBus Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 46/69] ide: commonize io_buffer_index initialization Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 47/69] ide: make more functions static Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 48/69] ide: support PIO restart for the ISA controller Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 49/69] ahci: Migrate IDEStatus Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 50/69] ahci: add support for restarting non-queued commands Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 51/69] ahci: Recompute cur_cmd on migrate post load Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 52/69] qtest/ide: Test flush / retry for ISA and PCI Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 53/69] libqos/ahci: Zero-fill AHCI headers Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 54/69] qtest/ahci: Add a macro bootup routine Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 55/69] libqos/ahci: add ahci command helpers Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 56/69] qtest/ahci: Add DMA test variants Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 57/69] qtest/ahci: Add PIO and LBA48 tests Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 58/69] qtest/ahci: add fragmented dma test Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 59/69] qtest/ahci: add qcow2 support to ahci-test Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 60/69] qtest/ahci: test different disk sectors Stefan Hajnoczi
2015-02-27 18:18 ` [Qemu-devel] [PULL 61/69] qtest/ahci: Add simple flush test Stefan Hajnoczi
2015-02-27 18:19 ` [Qemu-devel] [PULL 62/69] qtest/ahci: Allow override of default CLI options Stefan Hajnoczi
2015-02-27 18:19 ` [Qemu-devel] [PULL 63/69] libqtest: add qmp_eventwait Stefan Hajnoczi
2015-02-27 18:19 ` [Qemu-devel] [PULL 64/69] libqtest: add qmp_async Stefan Hajnoczi
2015-02-27 18:19 ` [Qemu-devel] [PULL 65/69] libqos: add blkdebug_prepare_script Stefan Hajnoczi
2015-02-27 18:19 ` [Qemu-devel] [PULL 66/69] qtest/ahci: add flush retry test Stefan Hajnoczi
2015-02-27 18:19 ` [Qemu-devel] [PULL 67/69] sheepdog: fix confused return values Stefan Hajnoczi
2015-02-27 18:19 ` [Qemu-devel] [PULL 68/69] libqos: Solve bug in interrupt checking when using MSIX in virtio-pci.c Stefan Hajnoczi
2015-02-27 18:19 ` [Qemu-devel] [PULL 69/69] tests: Check QVIRTIO_F_ANY_LAYOUT flag in virtio-blk test Stefan Hajnoczi
2015-02-27 18:57 ` [Qemu-devel] [PULL 00/69] Block patches Stefan Hajnoczi
2015-03-03 14:52   ` Peter Maydell
2015-03-03 17:29     ` Christian Borntraeger
2015-03-03 17:33       ` Max Reitz
2015-03-04  8:28         ` Christian Borntraeger
2015-03-04 12:03           ` Kevin Wolf
2015-03-04 16:32     ` Stefan Hajnoczi
2015-03-08  8:49 ` Peter Maydell

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1425061147-1411-22-git-send-email-stefanha@redhat.com \
    --to=stefanha@redhat.com \
    --cc=kwolf@redhat.com \
    --cc=mreitz@redhat.com \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).