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,6 +69,7 @@ BLOCK_OBJS=cutils.o cache-utils.o qemu-malloc.o qemu-option.o module.o
69 BLOCK_OBJS+=block/cow.o block/qcow.o aes.o block/vmdk.o block/cloop.o 69 BLOCK_OBJS+=block/cow.o block/qcow.o aes.o block/vmdk.o block/cloop.o
70 BLOCK_OBJS+=block/dmg.o block/bochs.o block/vpc.o block/vvfat.o 70 BLOCK_OBJS+=block/dmg.o block/bochs.o block/vpc.o block/vvfat.o
71 BLOCK_OBJS+=block/qcow2.o block/qcow2-refcount.o block/qcow2-cluster.o 71 BLOCK_OBJS+=block/qcow2.o block/qcow2-refcount.o block/qcow2-cluster.o
  72 +BLOCK_OBJS+=block/qcow2-snapshot.o
72 BLOCK_OBJS+=block/parallels.o block/nbd.o 73 BLOCK_OBJS+=block/parallels.o block/nbd.o
73 BLOCK_OBJS+=nbd.o block.o aio.o 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,29 +57,6 @@ typedef struct {
57 #define QCOW_EXT_MAGIC_BACKING_FORMAT 0xE2792ACA 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 static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename) 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,12 +308,6 @@ static int qcow_set_key(BlockDriverState *bs, const char *key)
331 return 0; 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 static int qcow_is_allocated(BlockDriverState *bs, int64_t sector_num, 311 static int qcow_is_allocated(BlockDriverState *bs, int64_t sector_num,
341 int nb_sectors, int *pnum) 312 int nb_sectors, int *pnum)
342 { 313 {
@@ -936,369 +907,6 @@ static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) @@ -936,369 +907,6 @@ static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
936 return 0; 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 static int qcow_check(BlockDriverState *bs) 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,6 +138,13 @@ static inline int size_to_clusters(BDRVQcowState *s, int64_t size)
138 return (size + (s->cluster_size - 1)) >> s->cluster_bits; 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 // FIXME Need qcow2_ prefix to global functions 148 // FIXME Need qcow2_ prefix to global functions
142 149
143 /* qcow2.c functions */ 150 /* qcow2.c functions */
@@ -184,4 +191,13 @@ uint64_t alloc_compressed_cluster_offset(BlockDriverState *bs, @@ -184,4 +191,13 @@ uint64_t alloc_compressed_cluster_offset(BlockDriverState *bs,
184 int alloc_cluster_link_l2(BlockDriverState *bs, uint64_t cluster_offset, 191 int alloc_cluster_link_l2(BlockDriverState *bs, uint64_t cluster_offset,
185 QCowL2Meta *m); 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 #endif 203 #endif