Commit c142442b06c51df60d000145d18af60ae5f0ac1c

Authored by Kevin Wolf
Committed by Anthony Liguori
1 parent 45aba42f

qcow2: Split out snapshot functions

qcow2-snapshot.c contains the code related to snapshotting.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Makefile
... ... @@ -69,6 +69,7 @@ BLOCK_OBJS=cutils.o cache-utils.o qemu-malloc.o qemu-option.o module.o
69 69 BLOCK_OBJS+=block/cow.o block/qcow.o aes.o block/vmdk.o block/cloop.o
70 70 BLOCK_OBJS+=block/dmg.o block/bochs.o block/vpc.o block/vvfat.o
71 71 BLOCK_OBJS+=block/qcow2.o block/qcow2-refcount.o block/qcow2-cluster.o
  72 +BLOCK_OBJS+=block/qcow2-snapshot.o
72 73 BLOCK_OBJS+=block/parallels.o block/nbd.o
73 74 BLOCK_OBJS+=nbd.o block.o aio.o
74 75  
... ...
block/qcow2-snapshot.c 0 → 100644
  1 +/*
  2 + * Block driver for the QCOW version 2 format
  3 + *
  4 + * Copyright (c) 2004-2006 Fabrice Bellard
  5 + *
  6 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  7 + * of this software and associated documentation files (the "Software"), to deal
  8 + * in the Software without restriction, including without limitation the rights
  9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 + * copies of the Software, and to permit persons to whom the Software is
  11 + * furnished to do so, subject to the following conditions:
  12 + *
  13 + * The above copyright notice and this permission notice shall be included in
  14 + * all copies or substantial portions of the Software.
  15 + *
  16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 + * THE SOFTWARE.
  23 + */
  24 +
  25 +#include "qemu-common.h"
  26 +#include "block_int.h"
  27 +#include "block/qcow2.h"
  28 +
  29 +typedef struct __attribute__((packed)) QCowSnapshotHeader {
  30 + /* header is 8 byte aligned */
  31 + uint64_t l1_table_offset;
  32 +
  33 + uint32_t l1_size;
  34 + uint16_t id_str_size;
  35 + uint16_t name_size;
  36 +
  37 + uint32_t date_sec;
  38 + uint32_t date_nsec;
  39 +
  40 + uint64_t vm_clock_nsec;
  41 +
  42 + uint32_t vm_state_size;
  43 + uint32_t extra_data_size; /* for extension */
  44 + /* extra data follows */
  45 + /* id_str follows */
  46 + /* name follows */
  47 +} QCowSnapshotHeader;
  48 +
  49 +void qcow_free_snapshots(BlockDriverState *bs)
  50 +{
  51 + BDRVQcowState *s = bs->opaque;
  52 + int i;
  53 +
  54 + for(i = 0; i < s->nb_snapshots; i++) {
  55 + qemu_free(s->snapshots[i].name);
  56 + qemu_free(s->snapshots[i].id_str);
  57 + }
  58 + qemu_free(s->snapshots);
  59 + s->snapshots = NULL;
  60 + s->nb_snapshots = 0;
  61 +}
  62 +
  63 +int qcow_read_snapshots(BlockDriverState *bs)
  64 +{
  65 + BDRVQcowState *s = bs->opaque;
  66 + QCowSnapshotHeader h;
  67 + QCowSnapshot *sn;
  68 + int i, id_str_size, name_size;
  69 + int64_t offset;
  70 + uint32_t extra_data_size;
  71 +
  72 + if (!s->nb_snapshots) {
  73 + s->snapshots = NULL;
  74 + s->snapshots_size = 0;
  75 + return 0;
  76 + }
  77 +
  78 + offset = s->snapshots_offset;
  79 + s->snapshots = qemu_mallocz(s->nb_snapshots * sizeof(QCowSnapshot));
  80 + for(i = 0; i < s->nb_snapshots; i++) {
  81 + offset = align_offset(offset, 8);
  82 + if (bdrv_pread(s->hd, offset, &h, sizeof(h)) != sizeof(h))
  83 + goto fail;
  84 + offset += sizeof(h);
  85 + sn = s->snapshots + i;
  86 + sn->l1_table_offset = be64_to_cpu(h.l1_table_offset);
  87 + sn->l1_size = be32_to_cpu(h.l1_size);
  88 + sn->vm_state_size = be32_to_cpu(h.vm_state_size);
  89 + sn->date_sec = be32_to_cpu(h.date_sec);
  90 + sn->date_nsec = be32_to_cpu(h.date_nsec);
  91 + sn->vm_clock_nsec = be64_to_cpu(h.vm_clock_nsec);
  92 + extra_data_size = be32_to_cpu(h.extra_data_size);
  93 +
  94 + id_str_size = be16_to_cpu(h.id_str_size);
  95 + name_size = be16_to_cpu(h.name_size);
  96 +
  97 + offset += extra_data_size;
  98 +
  99 + sn->id_str = qemu_malloc(id_str_size + 1);
  100 + if (bdrv_pread(s->hd, offset, sn->id_str, id_str_size) != id_str_size)
  101 + goto fail;
  102 + offset += id_str_size;
  103 + sn->id_str[id_str_size] = '\0';
  104 +
  105 + sn->name = qemu_malloc(name_size + 1);
  106 + if (bdrv_pread(s->hd, offset, sn->name, name_size) != name_size)
  107 + goto fail;
  108 + offset += name_size;
  109 + sn->name[name_size] = '\0';
  110 + }
  111 + s->snapshots_size = offset - s->snapshots_offset;
  112 + return 0;
  113 + fail:
  114 + qcow_free_snapshots(bs);
  115 + return -1;
  116 +}
  117 +
  118 +/* add at the end of the file a new list of snapshots */
  119 +static int qcow_write_snapshots(BlockDriverState *bs)
  120 +{
  121 + BDRVQcowState *s = bs->opaque;
  122 + QCowSnapshot *sn;
  123 + QCowSnapshotHeader h;
  124 + int i, name_size, id_str_size, snapshots_size;
  125 + uint64_t data64;
  126 + uint32_t data32;
  127 + int64_t offset, snapshots_offset;
  128 +
  129 + /* compute the size of the snapshots */
  130 + offset = 0;
  131 + for(i = 0; i < s->nb_snapshots; i++) {
  132 + sn = s->snapshots + i;
  133 + offset = align_offset(offset, 8);
  134 + offset += sizeof(h);
  135 + offset += strlen(sn->id_str);
  136 + offset += strlen(sn->name);
  137 + }
  138 + snapshots_size = offset;
  139 +
  140 + snapshots_offset = alloc_clusters(bs, snapshots_size);
  141 + offset = snapshots_offset;
  142 +
  143 + for(i = 0; i < s->nb_snapshots; i++) {
  144 + sn = s->snapshots + i;
  145 + memset(&h, 0, sizeof(h));
  146 + h.l1_table_offset = cpu_to_be64(sn->l1_table_offset);
  147 + h.l1_size = cpu_to_be32(sn->l1_size);
  148 + h.vm_state_size = cpu_to_be32(sn->vm_state_size);
  149 + h.date_sec = cpu_to_be32(sn->date_sec);
  150 + h.date_nsec = cpu_to_be32(sn->date_nsec);
  151 + h.vm_clock_nsec = cpu_to_be64(sn->vm_clock_nsec);
  152 +
  153 + id_str_size = strlen(sn->id_str);
  154 + name_size = strlen(sn->name);
  155 + h.id_str_size = cpu_to_be16(id_str_size);
  156 + h.name_size = cpu_to_be16(name_size);
  157 + offset = align_offset(offset, 8);
  158 + if (bdrv_pwrite(s->hd, offset, &h, sizeof(h)) != sizeof(h))
  159 + goto fail;
  160 + offset += sizeof(h);
  161 + if (bdrv_pwrite(s->hd, offset, sn->id_str, id_str_size) != id_str_size)
  162 + goto fail;
  163 + offset += id_str_size;
  164 + if (bdrv_pwrite(s->hd, offset, sn->name, name_size) != name_size)
  165 + goto fail;
  166 + offset += name_size;
  167 + }
  168 +
  169 + /* update the various header fields */
  170 + data64 = cpu_to_be64(snapshots_offset);
  171 + if (bdrv_pwrite(s->hd, offsetof(QCowHeader, snapshots_offset),
  172 + &data64, sizeof(data64)) != sizeof(data64))
  173 + goto fail;
  174 + data32 = cpu_to_be32(s->nb_snapshots);
  175 + if (bdrv_pwrite(s->hd, offsetof(QCowHeader, nb_snapshots),
  176 + &data32, sizeof(data32)) != sizeof(data32))
  177 + goto fail;
  178 +
  179 + /* free the old snapshot table */
  180 + free_clusters(bs, s->snapshots_offset, s->snapshots_size);
  181 + s->snapshots_offset = snapshots_offset;
  182 + s->snapshots_size = snapshots_size;
  183 + return 0;
  184 + fail:
  185 + return -1;
  186 +}
  187 +
  188 +static void find_new_snapshot_id(BlockDriverState *bs,
  189 + char *id_str, int id_str_size)
  190 +{
  191 + BDRVQcowState *s = bs->opaque;
  192 + QCowSnapshot *sn;
  193 + int i, id, id_max = 0;
  194 +
  195 + for(i = 0; i < s->nb_snapshots; i++) {
  196 + sn = s->snapshots + i;
  197 + id = strtoul(sn->id_str, NULL, 10);
  198 + if (id > id_max)
  199 + id_max = id;
  200 + }
  201 + snprintf(id_str, id_str_size, "%d", id_max + 1);
  202 +}
  203 +
  204 +static int find_snapshot_by_id(BlockDriverState *bs, const char *id_str)
  205 +{
  206 + BDRVQcowState *s = bs->opaque;
  207 + int i;
  208 +
  209 + for(i = 0; i < s->nb_snapshots; i++) {
  210 + if (!strcmp(s->snapshots[i].id_str, id_str))
  211 + return i;
  212 + }
  213 + return -1;
  214 +}
  215 +
  216 +static int find_snapshot_by_id_or_name(BlockDriverState *bs, const char *name)
  217 +{
  218 + BDRVQcowState *s = bs->opaque;
  219 + int i, ret;
  220 +
  221 + ret = find_snapshot_by_id(bs, name);
  222 + if (ret >= 0)
  223 + return ret;
  224 + for(i = 0; i < s->nb_snapshots; i++) {
  225 + if (!strcmp(s->snapshots[i].name, name))
  226 + return i;
  227 + }
  228 + return -1;
  229 +}
  230 +
  231 +/* if no id is provided, a new one is constructed */
  232 +int qcow_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
  233 +{
  234 + BDRVQcowState *s = bs->opaque;
  235 + QCowSnapshot *snapshots1, sn1, *sn = &sn1;
  236 + int i, ret;
  237 + uint64_t *l1_table = NULL;
  238 +
  239 + memset(sn, 0, sizeof(*sn));
  240 +
  241 + if (sn_info->id_str[0] == '\0') {
  242 + /* compute a new id */
  243 + find_new_snapshot_id(bs, sn_info->id_str, sizeof(sn_info->id_str));
  244 + }
  245 +
  246 + /* check that the ID is unique */
  247 + if (find_snapshot_by_id(bs, sn_info->id_str) >= 0)
  248 + return -ENOENT;
  249 +
  250 + sn->id_str = qemu_strdup(sn_info->id_str);
  251 + if (!sn->id_str)
  252 + goto fail;
  253 + sn->name = qemu_strdup(sn_info->name);
  254 + if (!sn->name)
  255 + goto fail;
  256 + sn->vm_state_size = sn_info->vm_state_size;
  257 + sn->date_sec = sn_info->date_sec;
  258 + sn->date_nsec = sn_info->date_nsec;
  259 + sn->vm_clock_nsec = sn_info->vm_clock_nsec;
  260 +
  261 + ret = update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 1);
  262 + if (ret < 0)
  263 + goto fail;
  264 +
  265 + /* create the L1 table of the snapshot */
  266 + sn->l1_table_offset = alloc_clusters(bs, s->l1_size * sizeof(uint64_t));
  267 + sn->l1_size = s->l1_size;
  268 +
  269 + l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
  270 + for(i = 0; i < s->l1_size; i++) {
  271 + l1_table[i] = cpu_to_be64(s->l1_table[i]);
  272 + }
  273 + if (bdrv_pwrite(s->hd, sn->l1_table_offset,
  274 + l1_table, s->l1_size * sizeof(uint64_t)) !=
  275 + (s->l1_size * sizeof(uint64_t)))
  276 + goto fail;
  277 + qemu_free(l1_table);
  278 + l1_table = NULL;
  279 +
  280 + snapshots1 = qemu_malloc((s->nb_snapshots + 1) * sizeof(QCowSnapshot));
  281 + if (s->snapshots) {
  282 + memcpy(snapshots1, s->snapshots, s->nb_snapshots * sizeof(QCowSnapshot));
  283 + qemu_free(s->snapshots);
  284 + }
  285 + s->snapshots = snapshots1;
  286 + s->snapshots[s->nb_snapshots++] = *sn;
  287 +
  288 + if (qcow_write_snapshots(bs) < 0)
  289 + goto fail;
  290 +#ifdef DEBUG_ALLOC
  291 + check_refcounts(bs);
  292 +#endif
  293 + return 0;
  294 + fail:
  295 + qemu_free(sn->name);
  296 + qemu_free(l1_table);
  297 + return -1;
  298 +}
  299 +
  300 +/* copy the snapshot 'snapshot_name' into the current disk image */
  301 +int qcow_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
  302 +{
  303 + BDRVQcowState *s = bs->opaque;
  304 + QCowSnapshot *sn;
  305 + int i, snapshot_index, l1_size2;
  306 +
  307 + snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
  308 + if (snapshot_index < 0)
  309 + return -ENOENT;
  310 + sn = &s->snapshots[snapshot_index];
  311 +
  312 + if (update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, -1) < 0)
  313 + goto fail;
  314 +
  315 + if (grow_l1_table(bs, sn->l1_size) < 0)
  316 + goto fail;
  317 +
  318 + s->l1_size = sn->l1_size;
  319 + l1_size2 = s->l1_size * sizeof(uint64_t);
  320 + /* copy the snapshot l1 table to the current l1 table */
  321 + if (bdrv_pread(s->hd, sn->l1_table_offset,
  322 + s->l1_table, l1_size2) != l1_size2)
  323 + goto fail;
  324 + if (bdrv_pwrite(s->hd, s->l1_table_offset,
  325 + s->l1_table, l1_size2) != l1_size2)
  326 + goto fail;
  327 + for(i = 0;i < s->l1_size; i++) {
  328 + be64_to_cpus(&s->l1_table[i]);
  329 + }
  330 +
  331 + if (update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 1) < 0)
  332 + goto fail;
  333 +
  334 +#ifdef DEBUG_ALLOC
  335 + check_refcounts(bs);
  336 +#endif
  337 + return 0;
  338 + fail:
  339 + return -EIO;
  340 +}
  341 +
  342 +int qcow_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
  343 +{
  344 + BDRVQcowState *s = bs->opaque;
  345 + QCowSnapshot *sn;
  346 + int snapshot_index, ret;
  347 +
  348 + snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
  349 + if (snapshot_index < 0)
  350 + return -ENOENT;
  351 + sn = &s->snapshots[snapshot_index];
  352 +
  353 + ret = update_snapshot_refcount(bs, sn->l1_table_offset, sn->l1_size, -1);
  354 + if (ret < 0)
  355 + return ret;
  356 + /* must update the copied flag on the current cluster offsets */
  357 + ret = update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 0);
  358 + if (ret < 0)
  359 + return ret;
  360 + free_clusters(bs, sn->l1_table_offset, sn->l1_size * sizeof(uint64_t));
  361 +
  362 + qemu_free(sn->id_str);
  363 + qemu_free(sn->name);
  364 + memmove(sn, sn + 1, (s->nb_snapshots - snapshot_index - 1) * sizeof(*sn));
  365 + s->nb_snapshots--;
  366 + ret = qcow_write_snapshots(bs);
  367 + if (ret < 0) {
  368 + /* XXX: restore snapshot if error ? */
  369 + return ret;
  370 + }
  371 +#ifdef DEBUG_ALLOC
  372 + check_refcounts(bs);
  373 +#endif
  374 + return 0;
  375 +}
  376 +
  377 +int qcow_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
  378 +{
  379 + BDRVQcowState *s = bs->opaque;
  380 + QEMUSnapshotInfo *sn_tab, *sn_info;
  381 + QCowSnapshot *sn;
  382 + int i;
  383 +
  384 + if (!s->nb_snapshots) {
  385 + *psn_tab = NULL;
  386 + return s->nb_snapshots;
  387 + }
  388 +
  389 + sn_tab = qemu_mallocz(s->nb_snapshots * sizeof(QEMUSnapshotInfo));
  390 + for(i = 0; i < s->nb_snapshots; i++) {
  391 + sn_info = sn_tab + i;
  392 + sn = s->snapshots + i;
  393 + pstrcpy(sn_info->id_str, sizeof(sn_info->id_str),
  394 + sn->id_str);
  395 + pstrcpy(sn_info->name, sizeof(sn_info->name),
  396 + sn->name);
  397 + sn_info->vm_state_size = sn->vm_state_size;
  398 + sn_info->date_sec = sn->date_sec;
  399 + sn_info->date_nsec = sn->date_nsec;
  400 + sn_info->vm_clock_nsec = sn->vm_clock_nsec;
  401 + }
  402 + *psn_tab = sn_tab;
  403 + return s->nb_snapshots;
  404 +}
  405 +
... ...
block/qcow2.c
... ... @@ -57,29 +57,6 @@ typedef struct {
57 57 #define QCOW_EXT_MAGIC_BACKING_FORMAT 0xE2792ACA
58 58  
59 59  
60   -typedef struct __attribute__((packed)) QCowSnapshotHeader {
61   - /* header is 8 byte aligned */
62   - uint64_t l1_table_offset;
63   -
64   - uint32_t l1_size;
65   - uint16_t id_str_size;
66   - uint16_t name_size;
67   -
68   - uint32_t date_sec;
69   - uint32_t date_nsec;
70   -
71   - uint64_t vm_clock_nsec;
72   -
73   - uint32_t vm_state_size;
74   - uint32_t extra_data_size; /* for extension */
75   - /* extra data follows */
76   - /* id_str follows */
77   - /* name follows */
78   -} QCowSnapshotHeader;
79   -
80   -
81   -static int qcow_read_snapshots(BlockDriverState *bs);
82   -static void qcow_free_snapshots(BlockDriverState *bs);
83 60  
84 61 static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
85 62 {
... ... @@ -331,12 +308,6 @@ static int qcow_set_key(BlockDriverState *bs, const char *key)
331 308 return 0;
332 309 }
333 310  
334   -static int64_t align_offset(int64_t offset, int n)
335   -{
336   - offset = (offset + n - 1) & ~(n - 1);
337   - return offset;
338   -}
339   -
340 311 static int qcow_is_allocated(BlockDriverState *bs, int64_t sector_num,
341 312 int nb_sectors, int *pnum)
342 313 {
... ... @@ -936,369 +907,6 @@ static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
936 907 return 0;
937 908 }
938 909  
939   -/*********************************************************/
940   -/* snapshot support */
941   -
942   -
943   -static void qcow_free_snapshots(BlockDriverState *bs)
944   -{
945   - BDRVQcowState *s = bs->opaque;
946   - int i;
947   -
948   - for(i = 0; i < s->nb_snapshots; i++) {
949   - qemu_free(s->snapshots[i].name);
950   - qemu_free(s->snapshots[i].id_str);
951   - }
952   - qemu_free(s->snapshots);
953   - s->snapshots = NULL;
954   - s->nb_snapshots = 0;
955   -}
956   -
957   -static int qcow_read_snapshots(BlockDriverState *bs)
958   -{
959   - BDRVQcowState *s = bs->opaque;
960   - QCowSnapshotHeader h;
961   - QCowSnapshot *sn;
962   - int i, id_str_size, name_size;
963   - int64_t offset;
964   - uint32_t extra_data_size;
965   -
966   - if (!s->nb_snapshots) {
967   - s->snapshots = NULL;
968   - s->snapshots_size = 0;
969   - return 0;
970   - }
971   -
972   - offset = s->snapshots_offset;
973   - s->snapshots = qemu_mallocz(s->nb_snapshots * sizeof(QCowSnapshot));
974   - for(i = 0; i < s->nb_snapshots; i++) {
975   - offset = align_offset(offset, 8);
976   - if (bdrv_pread(s->hd, offset, &h, sizeof(h)) != sizeof(h))
977   - goto fail;
978   - offset += sizeof(h);
979   - sn = s->snapshots + i;
980   - sn->l1_table_offset = be64_to_cpu(h.l1_table_offset);
981   - sn->l1_size = be32_to_cpu(h.l1_size);
982   - sn->vm_state_size = be32_to_cpu(h.vm_state_size);
983   - sn->date_sec = be32_to_cpu(h.date_sec);
984   - sn->date_nsec = be32_to_cpu(h.date_nsec);
985   - sn->vm_clock_nsec = be64_to_cpu(h.vm_clock_nsec);
986   - extra_data_size = be32_to_cpu(h.extra_data_size);
987   -
988   - id_str_size = be16_to_cpu(h.id_str_size);
989   - name_size = be16_to_cpu(h.name_size);
990   -
991   - offset += extra_data_size;
992   -
993   - sn->id_str = qemu_malloc(id_str_size + 1);
994   - if (bdrv_pread(s->hd, offset, sn->id_str, id_str_size) != id_str_size)
995   - goto fail;
996   - offset += id_str_size;
997   - sn->id_str[id_str_size] = '\0';
998   -
999   - sn->name = qemu_malloc(name_size + 1);
1000   - if (bdrv_pread(s->hd, offset, sn->name, name_size) != name_size)
1001   - goto fail;
1002   - offset += name_size;
1003   - sn->name[name_size] = '\0';
1004   - }
1005   - s->snapshots_size = offset - s->snapshots_offset;
1006   - return 0;
1007   - fail:
1008   - qcow_free_snapshots(bs);
1009   - return -1;
1010   -}
1011   -
1012   -/* add at the end of the file a new list of snapshots */
1013   -static int qcow_write_snapshots(BlockDriverState *bs)
1014   -{
1015   - BDRVQcowState *s = bs->opaque;
1016   - QCowSnapshot *sn;
1017   - QCowSnapshotHeader h;
1018   - int i, name_size, id_str_size, snapshots_size;
1019   - uint64_t data64;
1020   - uint32_t data32;
1021   - int64_t offset, snapshots_offset;
1022   -
1023   - /* compute the size of the snapshots */
1024   - offset = 0;
1025   - for(i = 0; i < s->nb_snapshots; i++) {
1026   - sn = s->snapshots + i;
1027   - offset = align_offset(offset, 8);
1028   - offset += sizeof(h);
1029   - offset += strlen(sn->id_str);
1030   - offset += strlen(sn->name);
1031   - }
1032   - snapshots_size = offset;
1033   -
1034   - snapshots_offset = alloc_clusters(bs, snapshots_size);
1035   - offset = snapshots_offset;
1036   -
1037   - for(i = 0; i < s->nb_snapshots; i++) {
1038   - sn = s->snapshots + i;
1039   - memset(&h, 0, sizeof(h));
1040   - h.l1_table_offset = cpu_to_be64(sn->l1_table_offset);
1041   - h.l1_size = cpu_to_be32(sn->l1_size);
1042   - h.vm_state_size = cpu_to_be32(sn->vm_state_size);
1043   - h.date_sec = cpu_to_be32(sn->date_sec);
1044   - h.date_nsec = cpu_to_be32(sn->date_nsec);
1045   - h.vm_clock_nsec = cpu_to_be64(sn->vm_clock_nsec);
1046   -
1047   - id_str_size = strlen(sn->id_str);
1048   - name_size = strlen(sn->name);
1049   - h.id_str_size = cpu_to_be16(id_str_size);
1050   - h.name_size = cpu_to_be16(name_size);
1051   - offset = align_offset(offset, 8);
1052   - if (bdrv_pwrite(s->hd, offset, &h, sizeof(h)) != sizeof(h))
1053   - goto fail;
1054   - offset += sizeof(h);
1055   - if (bdrv_pwrite(s->hd, offset, sn->id_str, id_str_size) != id_str_size)
1056   - goto fail;
1057   - offset += id_str_size;
1058   - if (bdrv_pwrite(s->hd, offset, sn->name, name_size) != name_size)
1059   - goto fail;
1060   - offset += name_size;
1061   - }
1062   -
1063   - /* update the various header fields */
1064   - data64 = cpu_to_be64(snapshots_offset);
1065   - if (bdrv_pwrite(s->hd, offsetof(QCowHeader, snapshots_offset),
1066   - &data64, sizeof(data64)) != sizeof(data64))
1067   - goto fail;
1068   - data32 = cpu_to_be32(s->nb_snapshots);
1069   - if (bdrv_pwrite(s->hd, offsetof(QCowHeader, nb_snapshots),
1070   - &data32, sizeof(data32)) != sizeof(data32))
1071   - goto fail;
1072   -
1073   - /* free the old snapshot table */
1074   - free_clusters(bs, s->snapshots_offset, s->snapshots_size);
1075   - s->snapshots_offset = snapshots_offset;
1076   - s->snapshots_size = snapshots_size;
1077   - return 0;
1078   - fail:
1079   - return -1;
1080   -}
1081   -
1082   -static void find_new_snapshot_id(BlockDriverState *bs,
1083   - char *id_str, int id_str_size)
1084   -{
1085   - BDRVQcowState *s = bs->opaque;
1086   - QCowSnapshot *sn;
1087   - int i, id, id_max = 0;
1088   -
1089   - for(i = 0; i < s->nb_snapshots; i++) {
1090   - sn = s->snapshots + i;
1091   - id = strtoul(sn->id_str, NULL, 10);
1092   - if (id > id_max)
1093   - id_max = id;
1094   - }
1095   - snprintf(id_str, id_str_size, "%d", id_max + 1);
1096   -}
1097   -
1098   -static int find_snapshot_by_id(BlockDriverState *bs, const char *id_str)
1099   -{
1100   - BDRVQcowState *s = bs->opaque;
1101   - int i;
1102   -
1103   - for(i = 0; i < s->nb_snapshots; i++) {
1104   - if (!strcmp(s->snapshots[i].id_str, id_str))
1105   - return i;
1106   - }
1107   - return -1;
1108   -}
1109   -
1110   -static int find_snapshot_by_id_or_name(BlockDriverState *bs, const char *name)
1111   -{
1112   - BDRVQcowState *s = bs->opaque;
1113   - int i, ret;
1114   -
1115   - ret = find_snapshot_by_id(bs, name);
1116   - if (ret >= 0)
1117   - return ret;
1118   - for(i = 0; i < s->nb_snapshots; i++) {
1119   - if (!strcmp(s->snapshots[i].name, name))
1120   - return i;
1121   - }
1122   - return -1;
1123   -}
1124   -
1125   -/* if no id is provided, a new one is constructed */
1126   -static int qcow_snapshot_create(BlockDriverState *bs,
1127   - QEMUSnapshotInfo *sn_info)
1128   -{
1129   - BDRVQcowState *s = bs->opaque;
1130   - QCowSnapshot *snapshots1, sn1, *sn = &sn1;
1131   - int i, ret;
1132   - uint64_t *l1_table = NULL;
1133   -
1134   - memset(sn, 0, sizeof(*sn));
1135   -
1136   - if (sn_info->id_str[0] == '\0') {
1137   - /* compute a new id */
1138   - find_new_snapshot_id(bs, sn_info->id_str, sizeof(sn_info->id_str));
1139   - }
1140   -
1141   - /* check that the ID is unique */
1142   - if (find_snapshot_by_id(bs, sn_info->id_str) >= 0)
1143   - return -ENOENT;
1144   -
1145   - sn->id_str = qemu_strdup(sn_info->id_str);
1146   - if (!sn->id_str)
1147   - goto fail;
1148   - sn->name = qemu_strdup(sn_info->name);
1149   - if (!sn->name)
1150   - goto fail;
1151   - sn->vm_state_size = sn_info->vm_state_size;
1152   - sn->date_sec = sn_info->date_sec;
1153   - sn->date_nsec = sn_info->date_nsec;
1154   - sn->vm_clock_nsec = sn_info->vm_clock_nsec;
1155   -
1156   - ret = update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 1);
1157   - if (ret < 0)
1158   - goto fail;
1159   -
1160   - /* create the L1 table of the snapshot */
1161   - sn->l1_table_offset = alloc_clusters(bs, s->l1_size * sizeof(uint64_t));
1162   - sn->l1_size = s->l1_size;
1163   -
1164   - l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
1165   - for(i = 0; i < s->l1_size; i++) {
1166   - l1_table[i] = cpu_to_be64(s->l1_table[i]);
1167   - }
1168   - if (bdrv_pwrite(s->hd, sn->l1_table_offset,
1169   - l1_table, s->l1_size * sizeof(uint64_t)) !=
1170   - (s->l1_size * sizeof(uint64_t)))
1171   - goto fail;
1172   - qemu_free(l1_table);
1173   - l1_table = NULL;
1174   -
1175   - snapshots1 = qemu_malloc((s->nb_snapshots + 1) * sizeof(QCowSnapshot));
1176   - if (s->snapshots) {
1177   - memcpy(snapshots1, s->snapshots, s->nb_snapshots * sizeof(QCowSnapshot));
1178   - qemu_free(s->snapshots);
1179   - }
1180   - s->snapshots = snapshots1;
1181   - s->snapshots[s->nb_snapshots++] = *sn;
1182   -
1183   - if (qcow_write_snapshots(bs) < 0)
1184   - goto fail;
1185   -#ifdef DEBUG_ALLOC
1186   - check_refcounts(bs);
1187   -#endif
1188   - return 0;
1189   - fail:
1190   - qemu_free(sn->name);
1191   - qemu_free(l1_table);
1192   - return -1;
1193   -}
1194   -
1195   -/* copy the snapshot 'snapshot_name' into the current disk image */
1196   -static int qcow_snapshot_goto(BlockDriverState *bs,
1197   - const char *snapshot_id)
1198   -{
1199   - BDRVQcowState *s = bs->opaque;
1200   - QCowSnapshot *sn;
1201   - int i, snapshot_index, l1_size2;
1202   -
1203   - snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
1204   - if (snapshot_index < 0)
1205   - return -ENOENT;
1206   - sn = &s->snapshots[snapshot_index];
1207   -
1208   - if (update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, -1) < 0)
1209   - goto fail;
1210   -
1211   - if (grow_l1_table(bs, sn->l1_size) < 0)
1212   - goto fail;
1213   -
1214   - s->l1_size = sn->l1_size;
1215   - l1_size2 = s->l1_size * sizeof(uint64_t);
1216   - /* copy the snapshot l1 table to the current l1 table */
1217   - if (bdrv_pread(s->hd, sn->l1_table_offset,
1218   - s->l1_table, l1_size2) != l1_size2)
1219   - goto fail;
1220   - if (bdrv_pwrite(s->hd, s->l1_table_offset,
1221   - s->l1_table, l1_size2) != l1_size2)
1222   - goto fail;
1223   - for(i = 0;i < s->l1_size; i++) {
1224   - be64_to_cpus(&s->l1_table[i]);
1225   - }
1226   -
1227   - if (update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 1) < 0)
1228   - goto fail;
1229   -
1230   -#ifdef DEBUG_ALLOC
1231   - check_refcounts(bs);
1232   -#endif
1233   - return 0;
1234   - fail:
1235   - return -EIO;
1236   -}
1237   -
1238   -static int qcow_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
1239   -{
1240   - BDRVQcowState *s = bs->opaque;
1241   - QCowSnapshot *sn;
1242   - int snapshot_index, ret;
1243   -
1244   - snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
1245   - if (snapshot_index < 0)
1246   - return -ENOENT;
1247   - sn = &s->snapshots[snapshot_index];
1248   -
1249   - ret = update_snapshot_refcount(bs, sn->l1_table_offset, sn->l1_size, -1);
1250   - if (ret < 0)
1251   - return ret;
1252   - /* must update the copied flag on the current cluster offsets */
1253   - ret = update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 0);
1254   - if (ret < 0)
1255   - return ret;
1256   - free_clusters(bs, sn->l1_table_offset, sn->l1_size * sizeof(uint64_t));
1257   -
1258   - qemu_free(sn->id_str);
1259   - qemu_free(sn->name);
1260   - memmove(sn, sn + 1, (s->nb_snapshots - snapshot_index - 1) * sizeof(*sn));
1261   - s->nb_snapshots--;
1262   - ret = qcow_write_snapshots(bs);
1263   - if (ret < 0) {
1264   - /* XXX: restore snapshot if error ? */
1265   - return ret;
1266   - }
1267   -#ifdef DEBUG_ALLOC
1268   - check_refcounts(bs);
1269   -#endif
1270   - return 0;
1271   -}
1272   -
1273   -static int qcow_snapshot_list(BlockDriverState *bs,
1274   - QEMUSnapshotInfo **psn_tab)
1275   -{
1276   - BDRVQcowState *s = bs->opaque;
1277   - QEMUSnapshotInfo *sn_tab, *sn_info;
1278   - QCowSnapshot *sn;
1279   - int i;
1280   -
1281   - if (!s->nb_snapshots) {
1282   - *psn_tab = NULL;
1283   - return s->nb_snapshots;
1284   - }
1285   -
1286   - sn_tab = qemu_mallocz(s->nb_snapshots * sizeof(QEMUSnapshotInfo));
1287   - for(i = 0; i < s->nb_snapshots; i++) {
1288   - sn_info = sn_tab + i;
1289   - sn = s->snapshots + i;
1290   - pstrcpy(sn_info->id_str, sizeof(sn_info->id_str),
1291   - sn->id_str);
1292   - pstrcpy(sn_info->name, sizeof(sn_info->name),
1293   - sn->name);
1294   - sn_info->vm_state_size = sn->vm_state_size;
1295   - sn_info->date_sec = sn->date_sec;
1296   - sn_info->date_nsec = sn->date_nsec;
1297   - sn_info->vm_clock_nsec = sn->vm_clock_nsec;
1298   - }
1299   - *psn_tab = sn_tab;
1300   - return s->nb_snapshots;
1301   -}
1302 910  
1303 911 static int qcow_check(BlockDriverState *bs)
1304 912 {
... ...
block/qcow2.h
... ... @@ -138,6 +138,13 @@ static inline int size_to_clusters(BDRVQcowState *s, int64_t size)
138 138 return (size + (s->cluster_size - 1)) >> s->cluster_bits;
139 139 }
140 140  
  141 +static inline int64_t align_offset(int64_t offset, int n)
  142 +{
  143 + offset = (offset + n - 1) & ~(n - 1);
  144 + return offset;
  145 +}
  146 +
  147 +
141 148 // FIXME Need qcow2_ prefix to global functions
142 149  
143 150 /* qcow2.c functions */
... ... @@ -184,4 +191,13 @@ uint64_t alloc_compressed_cluster_offset(BlockDriverState *bs,
184 191 int alloc_cluster_link_l2(BlockDriverState *bs, uint64_t cluster_offset,
185 192 QCowL2Meta *m);
186 193  
  194 +/* qcow2-snapshot.c functions */
  195 +int qcow_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info);
  196 +int qcow_snapshot_goto(BlockDriverState *bs, const char *snapshot_id);
  197 +int qcow_snapshot_delete(BlockDriverState *bs, const char *snapshot_id);
  198 +int qcow_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab);
  199 +
  200 +void qcow_free_snapshots(BlockDriverState *bs);
  201 +int qcow_read_snapshots(BlockDriverState *bs);
  202 +
187 203 #endif
... ...