Statistics
| Branch: | Revision:

root / block / qcow2-snapshot.c @ 1e5b9d2f

History | View | Annotate | Download (12.2 kB)

1 c142442b Kevin Wolf
/*
2 c142442b Kevin Wolf
 * Block driver for the QCOW version 2 format
3 c142442b Kevin Wolf
 *
4 c142442b Kevin Wolf
 * Copyright (c) 2004-2006 Fabrice Bellard
5 c142442b Kevin Wolf
 *
6 c142442b Kevin Wolf
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 c142442b Kevin Wolf
 * of this software and associated documentation files (the "Software"), to deal
8 c142442b Kevin Wolf
 * in the Software without restriction, including without limitation the rights
9 c142442b Kevin Wolf
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 c142442b Kevin Wolf
 * copies of the Software, and to permit persons to whom the Software is
11 c142442b Kevin Wolf
 * furnished to do so, subject to the following conditions:
12 c142442b Kevin Wolf
 *
13 c142442b Kevin Wolf
 * The above copyright notice and this permission notice shall be included in
14 c142442b Kevin Wolf
 * all copies or substantial portions of the Software.
15 c142442b Kevin Wolf
 *
16 c142442b Kevin Wolf
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 c142442b Kevin Wolf
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 c142442b Kevin Wolf
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 c142442b Kevin Wolf
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 c142442b Kevin Wolf
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 c142442b Kevin Wolf
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 c142442b Kevin Wolf
 * THE SOFTWARE.
23 c142442b Kevin Wolf
 */
24 c142442b Kevin Wolf
25 c142442b Kevin Wolf
#include "qemu-common.h"
26 c142442b Kevin Wolf
#include "block_int.h"
27 c142442b Kevin Wolf
#include "block/qcow2.h"
28 c142442b Kevin Wolf
29 c142442b Kevin Wolf
typedef struct __attribute__((packed)) QCowSnapshotHeader {
30 c142442b Kevin Wolf
    /* header is 8 byte aligned */
31 c142442b Kevin Wolf
    uint64_t l1_table_offset;
32 c142442b Kevin Wolf
33 c142442b Kevin Wolf
    uint32_t l1_size;
34 c142442b Kevin Wolf
    uint16_t id_str_size;
35 c142442b Kevin Wolf
    uint16_t name_size;
36 c142442b Kevin Wolf
37 c142442b Kevin Wolf
    uint32_t date_sec;
38 c142442b Kevin Wolf
    uint32_t date_nsec;
39 c142442b Kevin Wolf
40 c142442b Kevin Wolf
    uint64_t vm_clock_nsec;
41 c142442b Kevin Wolf
42 c142442b Kevin Wolf
    uint32_t vm_state_size;
43 c142442b Kevin Wolf
    uint32_t extra_data_size; /* for extension */
44 c142442b Kevin Wolf
    /* extra data follows */
45 c142442b Kevin Wolf
    /* id_str follows */
46 c142442b Kevin Wolf
    /* name follows  */
47 c142442b Kevin Wolf
} QCowSnapshotHeader;
48 c142442b Kevin Wolf
49 ed6ccf0f Kevin Wolf
void qcow2_free_snapshots(BlockDriverState *bs)
50 c142442b Kevin Wolf
{
51 c142442b Kevin Wolf
    BDRVQcowState *s = bs->opaque;
52 c142442b Kevin Wolf
    int i;
53 c142442b Kevin Wolf
54 c142442b Kevin Wolf
    for(i = 0; i < s->nb_snapshots; i++) {
55 c142442b Kevin Wolf
        qemu_free(s->snapshots[i].name);
56 c142442b Kevin Wolf
        qemu_free(s->snapshots[i].id_str);
57 c142442b Kevin Wolf
    }
58 c142442b Kevin Wolf
    qemu_free(s->snapshots);
59 c142442b Kevin Wolf
    s->snapshots = NULL;
60 c142442b Kevin Wolf
    s->nb_snapshots = 0;
61 c142442b Kevin Wolf
}
62 c142442b Kevin Wolf
63 ed6ccf0f Kevin Wolf
int qcow2_read_snapshots(BlockDriverState *bs)
64 c142442b Kevin Wolf
{
65 c142442b Kevin Wolf
    BDRVQcowState *s = bs->opaque;
66 c142442b Kevin Wolf
    QCowSnapshotHeader h;
67 c142442b Kevin Wolf
    QCowSnapshot *sn;
68 c142442b Kevin Wolf
    int i, id_str_size, name_size;
69 c142442b Kevin Wolf
    int64_t offset;
70 c142442b Kevin Wolf
    uint32_t extra_data_size;
71 c142442b Kevin Wolf
72 c142442b Kevin Wolf
    if (!s->nb_snapshots) {
73 c142442b Kevin Wolf
        s->snapshots = NULL;
74 c142442b Kevin Wolf
        s->snapshots_size = 0;
75 c142442b Kevin Wolf
        return 0;
76 c142442b Kevin Wolf
    }
77 c142442b Kevin Wolf
78 c142442b Kevin Wolf
    offset = s->snapshots_offset;
79 c142442b Kevin Wolf
    s->snapshots = qemu_mallocz(s->nb_snapshots * sizeof(QCowSnapshot));
80 c142442b Kevin Wolf
    for(i = 0; i < s->nb_snapshots; i++) {
81 c142442b Kevin Wolf
        offset = align_offset(offset, 8);
82 c142442b Kevin Wolf
        if (bdrv_pread(s->hd, offset, &h, sizeof(h)) != sizeof(h))
83 c142442b Kevin Wolf
            goto fail;
84 c142442b Kevin Wolf
        offset += sizeof(h);
85 c142442b Kevin Wolf
        sn = s->snapshots + i;
86 c142442b Kevin Wolf
        sn->l1_table_offset = be64_to_cpu(h.l1_table_offset);
87 c142442b Kevin Wolf
        sn->l1_size = be32_to_cpu(h.l1_size);
88 c142442b Kevin Wolf
        sn->vm_state_size = be32_to_cpu(h.vm_state_size);
89 c142442b Kevin Wolf
        sn->date_sec = be32_to_cpu(h.date_sec);
90 c142442b Kevin Wolf
        sn->date_nsec = be32_to_cpu(h.date_nsec);
91 c142442b Kevin Wolf
        sn->vm_clock_nsec = be64_to_cpu(h.vm_clock_nsec);
92 c142442b Kevin Wolf
        extra_data_size = be32_to_cpu(h.extra_data_size);
93 c142442b Kevin Wolf
94 c142442b Kevin Wolf
        id_str_size = be16_to_cpu(h.id_str_size);
95 c142442b Kevin Wolf
        name_size = be16_to_cpu(h.name_size);
96 c142442b Kevin Wolf
97 c142442b Kevin Wolf
        offset += extra_data_size;
98 c142442b Kevin Wolf
99 c142442b Kevin Wolf
        sn->id_str = qemu_malloc(id_str_size + 1);
100 c142442b Kevin Wolf
        if (bdrv_pread(s->hd, offset, sn->id_str, id_str_size) != id_str_size)
101 c142442b Kevin Wolf
            goto fail;
102 c142442b Kevin Wolf
        offset += id_str_size;
103 c142442b Kevin Wolf
        sn->id_str[id_str_size] = '\0';
104 c142442b Kevin Wolf
105 c142442b Kevin Wolf
        sn->name = qemu_malloc(name_size + 1);
106 c142442b Kevin Wolf
        if (bdrv_pread(s->hd, offset, sn->name, name_size) != name_size)
107 c142442b Kevin Wolf
            goto fail;
108 c142442b Kevin Wolf
        offset += name_size;
109 c142442b Kevin Wolf
        sn->name[name_size] = '\0';
110 c142442b Kevin Wolf
    }
111 c142442b Kevin Wolf
    s->snapshots_size = offset - s->snapshots_offset;
112 c142442b Kevin Wolf
    return 0;
113 c142442b Kevin Wolf
 fail:
114 ed6ccf0f Kevin Wolf
    qcow2_free_snapshots(bs);
115 c142442b Kevin Wolf
    return -1;
116 c142442b Kevin Wolf
}
117 c142442b Kevin Wolf
118 c142442b Kevin Wolf
/* add at the end of the file a new list of snapshots */
119 c142442b Kevin Wolf
static int qcow_write_snapshots(BlockDriverState *bs)
120 c142442b Kevin Wolf
{
121 c142442b Kevin Wolf
    BDRVQcowState *s = bs->opaque;
122 c142442b Kevin Wolf
    QCowSnapshot *sn;
123 c142442b Kevin Wolf
    QCowSnapshotHeader h;
124 c142442b Kevin Wolf
    int i, name_size, id_str_size, snapshots_size;
125 c142442b Kevin Wolf
    uint64_t data64;
126 c142442b Kevin Wolf
    uint32_t data32;
127 c142442b Kevin Wolf
    int64_t offset, snapshots_offset;
128 c142442b Kevin Wolf
129 c142442b Kevin Wolf
    /* compute the size of the snapshots */
130 c142442b Kevin Wolf
    offset = 0;
131 c142442b Kevin Wolf
    for(i = 0; i < s->nb_snapshots; i++) {
132 c142442b Kevin Wolf
        sn = s->snapshots + i;
133 c142442b Kevin Wolf
        offset = align_offset(offset, 8);
134 c142442b Kevin Wolf
        offset += sizeof(h);
135 c142442b Kevin Wolf
        offset += strlen(sn->id_str);
136 c142442b Kevin Wolf
        offset += strlen(sn->name);
137 c142442b Kevin Wolf
    }
138 c142442b Kevin Wolf
    snapshots_size = offset;
139 c142442b Kevin Wolf
140 ed6ccf0f Kevin Wolf
    snapshots_offset = qcow2_alloc_clusters(bs, snapshots_size);
141 c142442b Kevin Wolf
    offset = snapshots_offset;
142 c142442b Kevin Wolf
143 c142442b Kevin Wolf
    for(i = 0; i < s->nb_snapshots; i++) {
144 c142442b Kevin Wolf
        sn = s->snapshots + i;
145 c142442b Kevin Wolf
        memset(&h, 0, sizeof(h));
146 c142442b Kevin Wolf
        h.l1_table_offset = cpu_to_be64(sn->l1_table_offset);
147 c142442b Kevin Wolf
        h.l1_size = cpu_to_be32(sn->l1_size);
148 c142442b Kevin Wolf
        h.vm_state_size = cpu_to_be32(sn->vm_state_size);
149 c142442b Kevin Wolf
        h.date_sec = cpu_to_be32(sn->date_sec);
150 c142442b Kevin Wolf
        h.date_nsec = cpu_to_be32(sn->date_nsec);
151 c142442b Kevin Wolf
        h.vm_clock_nsec = cpu_to_be64(sn->vm_clock_nsec);
152 c142442b Kevin Wolf
153 c142442b Kevin Wolf
        id_str_size = strlen(sn->id_str);
154 c142442b Kevin Wolf
        name_size = strlen(sn->name);
155 c142442b Kevin Wolf
        h.id_str_size = cpu_to_be16(id_str_size);
156 c142442b Kevin Wolf
        h.name_size = cpu_to_be16(name_size);
157 c142442b Kevin Wolf
        offset = align_offset(offset, 8);
158 c142442b Kevin Wolf
        if (bdrv_pwrite(s->hd, offset, &h, sizeof(h)) != sizeof(h))
159 c142442b Kevin Wolf
            goto fail;
160 c142442b Kevin Wolf
        offset += sizeof(h);
161 c142442b Kevin Wolf
        if (bdrv_pwrite(s->hd, offset, sn->id_str, id_str_size) != id_str_size)
162 c142442b Kevin Wolf
            goto fail;
163 c142442b Kevin Wolf
        offset += id_str_size;
164 c142442b Kevin Wolf
        if (bdrv_pwrite(s->hd, offset, sn->name, name_size) != name_size)
165 c142442b Kevin Wolf
            goto fail;
166 c142442b Kevin Wolf
        offset += name_size;
167 c142442b Kevin Wolf
    }
168 c142442b Kevin Wolf
169 c142442b Kevin Wolf
    /* update the various header fields */
170 c142442b Kevin Wolf
    data64 = cpu_to_be64(snapshots_offset);
171 c142442b Kevin Wolf
    if (bdrv_pwrite(s->hd, offsetof(QCowHeader, snapshots_offset),
172 c142442b Kevin Wolf
                    &data64, sizeof(data64)) != sizeof(data64))
173 c142442b Kevin Wolf
        goto fail;
174 c142442b Kevin Wolf
    data32 = cpu_to_be32(s->nb_snapshots);
175 c142442b Kevin Wolf
    if (bdrv_pwrite(s->hd, offsetof(QCowHeader, nb_snapshots),
176 c142442b Kevin Wolf
                    &data32, sizeof(data32)) != sizeof(data32))
177 c142442b Kevin Wolf
        goto fail;
178 c142442b Kevin Wolf
179 c142442b Kevin Wolf
    /* free the old snapshot table */
180 ed6ccf0f Kevin Wolf
    qcow2_free_clusters(bs, s->snapshots_offset, s->snapshots_size);
181 c142442b Kevin Wolf
    s->snapshots_offset = snapshots_offset;
182 c142442b Kevin Wolf
    s->snapshots_size = snapshots_size;
183 c142442b Kevin Wolf
    return 0;
184 c142442b Kevin Wolf
 fail:
185 c142442b Kevin Wolf
    return -1;
186 c142442b Kevin Wolf
}
187 c142442b Kevin Wolf
188 c142442b Kevin Wolf
static void find_new_snapshot_id(BlockDriverState *bs,
189 c142442b Kevin Wolf
                                 char *id_str, int id_str_size)
190 c142442b Kevin Wolf
{
191 c142442b Kevin Wolf
    BDRVQcowState *s = bs->opaque;
192 c142442b Kevin Wolf
    QCowSnapshot *sn;
193 c142442b Kevin Wolf
    int i, id, id_max = 0;
194 c142442b Kevin Wolf
195 c142442b Kevin Wolf
    for(i = 0; i < s->nb_snapshots; i++) {
196 c142442b Kevin Wolf
        sn = s->snapshots + i;
197 c142442b Kevin Wolf
        id = strtoul(sn->id_str, NULL, 10);
198 c142442b Kevin Wolf
        if (id > id_max)
199 c142442b Kevin Wolf
            id_max = id;
200 c142442b Kevin Wolf
    }
201 c142442b Kevin Wolf
    snprintf(id_str, id_str_size, "%d", id_max + 1);
202 c142442b Kevin Wolf
}
203 c142442b Kevin Wolf
204 c142442b Kevin Wolf
static int find_snapshot_by_id(BlockDriverState *bs, const char *id_str)
205 c142442b Kevin Wolf
{
206 c142442b Kevin Wolf
    BDRVQcowState *s = bs->opaque;
207 c142442b Kevin Wolf
    int i;
208 c142442b Kevin Wolf
209 c142442b Kevin Wolf
    for(i = 0; i < s->nb_snapshots; i++) {
210 c142442b Kevin Wolf
        if (!strcmp(s->snapshots[i].id_str, id_str))
211 c142442b Kevin Wolf
            return i;
212 c142442b Kevin Wolf
    }
213 c142442b Kevin Wolf
    return -1;
214 c142442b Kevin Wolf
}
215 c142442b Kevin Wolf
216 c142442b Kevin Wolf
static int find_snapshot_by_id_or_name(BlockDriverState *bs, const char *name)
217 c142442b Kevin Wolf
{
218 c142442b Kevin Wolf
    BDRVQcowState *s = bs->opaque;
219 c142442b Kevin Wolf
    int i, ret;
220 c142442b Kevin Wolf
221 c142442b Kevin Wolf
    ret = find_snapshot_by_id(bs, name);
222 c142442b Kevin Wolf
    if (ret >= 0)
223 c142442b Kevin Wolf
        return ret;
224 c142442b Kevin Wolf
    for(i = 0; i < s->nb_snapshots; i++) {
225 c142442b Kevin Wolf
        if (!strcmp(s->snapshots[i].name, name))
226 c142442b Kevin Wolf
            return i;
227 c142442b Kevin Wolf
    }
228 c142442b Kevin Wolf
    return -1;
229 c142442b Kevin Wolf
}
230 c142442b Kevin Wolf
231 c142442b Kevin Wolf
/* if no id is provided, a new one is constructed */
232 ed6ccf0f Kevin Wolf
int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
233 c142442b Kevin Wolf
{
234 c142442b Kevin Wolf
    BDRVQcowState *s = bs->opaque;
235 c142442b Kevin Wolf
    QCowSnapshot *snapshots1, sn1, *sn = &sn1;
236 c142442b Kevin Wolf
    int i, ret;
237 c142442b Kevin Wolf
    uint64_t *l1_table = NULL;
238 c142442b Kevin Wolf
239 c142442b Kevin Wolf
    memset(sn, 0, sizeof(*sn));
240 c142442b Kevin Wolf
241 c142442b Kevin Wolf
    if (sn_info->id_str[0] == '\0') {
242 c142442b Kevin Wolf
        /* compute a new id */
243 c142442b Kevin Wolf
        find_new_snapshot_id(bs, sn_info->id_str, sizeof(sn_info->id_str));
244 c142442b Kevin Wolf
    }
245 c142442b Kevin Wolf
246 c142442b Kevin Wolf
    /* check that the ID is unique */
247 c142442b Kevin Wolf
    if (find_snapshot_by_id(bs, sn_info->id_str) >= 0)
248 c142442b Kevin Wolf
        return -ENOENT;
249 c142442b Kevin Wolf
250 c142442b Kevin Wolf
    sn->id_str = qemu_strdup(sn_info->id_str);
251 c142442b Kevin Wolf
    if (!sn->id_str)
252 c142442b Kevin Wolf
        goto fail;
253 c142442b Kevin Wolf
    sn->name = qemu_strdup(sn_info->name);
254 c142442b Kevin Wolf
    if (!sn->name)
255 c142442b Kevin Wolf
        goto fail;
256 c142442b Kevin Wolf
    sn->vm_state_size = sn_info->vm_state_size;
257 c142442b Kevin Wolf
    sn->date_sec = sn_info->date_sec;
258 c142442b Kevin Wolf
    sn->date_nsec = sn_info->date_nsec;
259 c142442b Kevin Wolf
    sn->vm_clock_nsec = sn_info->vm_clock_nsec;
260 c142442b Kevin Wolf
261 ed6ccf0f Kevin Wolf
    ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 1);
262 c142442b Kevin Wolf
    if (ret < 0)
263 c142442b Kevin Wolf
        goto fail;
264 c142442b Kevin Wolf
265 c142442b Kevin Wolf
    /* create the L1 table of the snapshot */
266 ed6ccf0f Kevin Wolf
    sn->l1_table_offset = qcow2_alloc_clusters(bs, s->l1_size * sizeof(uint64_t));
267 c142442b Kevin Wolf
    sn->l1_size = s->l1_size;
268 c142442b Kevin Wolf
269 c142442b Kevin Wolf
    l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
270 c142442b Kevin Wolf
    for(i = 0; i < s->l1_size; i++) {
271 c142442b Kevin Wolf
        l1_table[i] = cpu_to_be64(s->l1_table[i]);
272 c142442b Kevin Wolf
    }
273 c142442b Kevin Wolf
    if (bdrv_pwrite(s->hd, sn->l1_table_offset,
274 c142442b Kevin Wolf
                    l1_table, s->l1_size * sizeof(uint64_t)) !=
275 c142442b Kevin Wolf
        (s->l1_size * sizeof(uint64_t)))
276 c142442b Kevin Wolf
        goto fail;
277 c142442b Kevin Wolf
    qemu_free(l1_table);
278 c142442b Kevin Wolf
    l1_table = NULL;
279 c142442b Kevin Wolf
280 c142442b Kevin Wolf
    snapshots1 = qemu_malloc((s->nb_snapshots + 1) * sizeof(QCowSnapshot));
281 c142442b Kevin Wolf
    if (s->snapshots) {
282 c142442b Kevin Wolf
        memcpy(snapshots1, s->snapshots, s->nb_snapshots * sizeof(QCowSnapshot));
283 c142442b Kevin Wolf
        qemu_free(s->snapshots);
284 c142442b Kevin Wolf
    }
285 c142442b Kevin Wolf
    s->snapshots = snapshots1;
286 c142442b Kevin Wolf
    s->snapshots[s->nb_snapshots++] = *sn;
287 c142442b Kevin Wolf
288 c142442b Kevin Wolf
    if (qcow_write_snapshots(bs) < 0)
289 c142442b Kevin Wolf
        goto fail;
290 c142442b Kevin Wolf
#ifdef DEBUG_ALLOC
291 14899cdf Filip Navara
    qcow2_check_refcounts(bs);
292 c142442b Kevin Wolf
#endif
293 c142442b Kevin Wolf
    return 0;
294 c142442b Kevin Wolf
 fail:
295 c142442b Kevin Wolf
    qemu_free(sn->name);
296 c142442b Kevin Wolf
    qemu_free(l1_table);
297 c142442b Kevin Wolf
    return -1;
298 c142442b Kevin Wolf
}
299 c142442b Kevin Wolf
300 c142442b Kevin Wolf
/* copy the snapshot 'snapshot_name' into the current disk image */
301 ed6ccf0f Kevin Wolf
int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
302 c142442b Kevin Wolf
{
303 c142442b Kevin Wolf
    BDRVQcowState *s = bs->opaque;
304 c142442b Kevin Wolf
    QCowSnapshot *sn;
305 c142442b Kevin Wolf
    int i, snapshot_index, l1_size2;
306 c142442b Kevin Wolf
307 c142442b Kevin Wolf
    snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
308 c142442b Kevin Wolf
    if (snapshot_index < 0)
309 c142442b Kevin Wolf
        return -ENOENT;
310 c142442b Kevin Wolf
    sn = &s->snapshots[snapshot_index];
311 c142442b Kevin Wolf
312 ed6ccf0f Kevin Wolf
    if (qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, -1) < 0)
313 c142442b Kevin Wolf
        goto fail;
314 c142442b Kevin Wolf
315 ed6ccf0f Kevin Wolf
    if (qcow2_grow_l1_table(bs, sn->l1_size) < 0)
316 c142442b Kevin Wolf
        goto fail;
317 c142442b Kevin Wolf
318 c142442b Kevin Wolf
    s->l1_size = sn->l1_size;
319 c142442b Kevin Wolf
    l1_size2 = s->l1_size * sizeof(uint64_t);
320 c142442b Kevin Wolf
    /* copy the snapshot l1 table to the current l1 table */
321 c142442b Kevin Wolf
    if (bdrv_pread(s->hd, sn->l1_table_offset,
322 c142442b Kevin Wolf
                   s->l1_table, l1_size2) != l1_size2)
323 c142442b Kevin Wolf
        goto fail;
324 c142442b Kevin Wolf
    if (bdrv_pwrite(s->hd, s->l1_table_offset,
325 c142442b Kevin Wolf
                    s->l1_table, l1_size2) != l1_size2)
326 c142442b Kevin Wolf
        goto fail;
327 c142442b Kevin Wolf
    for(i = 0;i < s->l1_size; i++) {
328 c142442b Kevin Wolf
        be64_to_cpus(&s->l1_table[i]);
329 c142442b Kevin Wolf
    }
330 c142442b Kevin Wolf
331 ed6ccf0f Kevin Wolf
    if (qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 1) < 0)
332 c142442b Kevin Wolf
        goto fail;
333 c142442b Kevin Wolf
334 c142442b Kevin Wolf
#ifdef DEBUG_ALLOC
335 14899cdf Filip Navara
    qcow2_check_refcounts(bs);
336 c142442b Kevin Wolf
#endif
337 c142442b Kevin Wolf
    return 0;
338 c142442b Kevin Wolf
 fail:
339 c142442b Kevin Wolf
    return -EIO;
340 c142442b Kevin Wolf
}
341 c142442b Kevin Wolf
342 ed6ccf0f Kevin Wolf
int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
343 c142442b Kevin Wolf
{
344 c142442b Kevin Wolf
    BDRVQcowState *s = bs->opaque;
345 c142442b Kevin Wolf
    QCowSnapshot *sn;
346 c142442b Kevin Wolf
    int snapshot_index, ret;
347 c142442b Kevin Wolf
348 c142442b Kevin Wolf
    snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
349 c142442b Kevin Wolf
    if (snapshot_index < 0)
350 c142442b Kevin Wolf
        return -ENOENT;
351 c142442b Kevin Wolf
    sn = &s->snapshots[snapshot_index];
352 c142442b Kevin Wolf
353 ed6ccf0f Kevin Wolf
    ret = qcow2_update_snapshot_refcount(bs, sn->l1_table_offset, sn->l1_size, -1);
354 c142442b Kevin Wolf
    if (ret < 0)
355 c142442b Kevin Wolf
        return ret;
356 c142442b Kevin Wolf
    /* must update the copied flag on the current cluster offsets */
357 ed6ccf0f Kevin Wolf
    ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 0);
358 c142442b Kevin Wolf
    if (ret < 0)
359 c142442b Kevin Wolf
        return ret;
360 ed6ccf0f Kevin Wolf
    qcow2_free_clusters(bs, sn->l1_table_offset, sn->l1_size * sizeof(uint64_t));
361 c142442b Kevin Wolf
362 c142442b Kevin Wolf
    qemu_free(sn->id_str);
363 c142442b Kevin Wolf
    qemu_free(sn->name);
364 c142442b Kevin Wolf
    memmove(sn, sn + 1, (s->nb_snapshots - snapshot_index - 1) * sizeof(*sn));
365 c142442b Kevin Wolf
    s->nb_snapshots--;
366 c142442b Kevin Wolf
    ret = qcow_write_snapshots(bs);
367 c142442b Kevin Wolf
    if (ret < 0) {
368 c142442b Kevin Wolf
        /* XXX: restore snapshot if error ? */
369 c142442b Kevin Wolf
        return ret;
370 c142442b Kevin Wolf
    }
371 c142442b Kevin Wolf
#ifdef DEBUG_ALLOC
372 14899cdf Filip Navara
    qcow2_check_refcounts(bs);
373 c142442b Kevin Wolf
#endif
374 c142442b Kevin Wolf
    return 0;
375 c142442b Kevin Wolf
}
376 c142442b Kevin Wolf
377 ed6ccf0f Kevin Wolf
int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
378 c142442b Kevin Wolf
{
379 c142442b Kevin Wolf
    BDRVQcowState *s = bs->opaque;
380 c142442b Kevin Wolf
    QEMUSnapshotInfo *sn_tab, *sn_info;
381 c142442b Kevin Wolf
    QCowSnapshot *sn;
382 c142442b Kevin Wolf
    int i;
383 c142442b Kevin Wolf
384 c142442b Kevin Wolf
    if (!s->nb_snapshots) {
385 c142442b Kevin Wolf
        *psn_tab = NULL;
386 c142442b Kevin Wolf
        return s->nb_snapshots;
387 c142442b Kevin Wolf
    }
388 c142442b Kevin Wolf
389 c142442b Kevin Wolf
    sn_tab = qemu_mallocz(s->nb_snapshots * sizeof(QEMUSnapshotInfo));
390 c142442b Kevin Wolf
    for(i = 0; i < s->nb_snapshots; i++) {
391 c142442b Kevin Wolf
        sn_info = sn_tab + i;
392 c142442b Kevin Wolf
        sn = s->snapshots + i;
393 c142442b Kevin Wolf
        pstrcpy(sn_info->id_str, sizeof(sn_info->id_str),
394 c142442b Kevin Wolf
                sn->id_str);
395 c142442b Kevin Wolf
        pstrcpy(sn_info->name, sizeof(sn_info->name),
396 c142442b Kevin Wolf
                sn->name);
397 c142442b Kevin Wolf
        sn_info->vm_state_size = sn->vm_state_size;
398 c142442b Kevin Wolf
        sn_info->date_sec = sn->date_sec;
399 c142442b Kevin Wolf
        sn_info->date_nsec = sn->date_nsec;
400 c142442b Kevin Wolf
        sn_info->vm_clock_nsec = sn->vm_clock_nsec;
401 c142442b Kevin Wolf
    }
402 c142442b Kevin Wolf
    *psn_tab = sn_tab;
403 c142442b Kevin Wolf
    return s->nb_snapshots;
404 c142442b Kevin Wolf
}