Statistics
| Branch: | Revision:

root / block / qcow2-snapshot.c @ 72893756

History | View | Annotate | Download (12.5 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 66f82cee Kevin Wolf
        if (bdrv_pread(bs->file, 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 66f82cee Kevin Wolf
        if (bdrv_pread(bs->file, 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 66f82cee Kevin Wolf
        if (bdrv_pread(bs->file, 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 29216ed1 Kevin Wolf
    bdrv_flush(bs->file);
142 c142442b Kevin Wolf
    offset = snapshots_offset;
143 5d757b56 Kevin Wolf
    if (offset < 0) {
144 5d757b56 Kevin Wolf
        return offset;
145 5d757b56 Kevin Wolf
    }
146 c142442b Kevin Wolf
147 c142442b Kevin Wolf
    for(i = 0; i < s->nb_snapshots; i++) {
148 c142442b Kevin Wolf
        sn = s->snapshots + i;
149 c142442b Kevin Wolf
        memset(&h, 0, sizeof(h));
150 c142442b Kevin Wolf
        h.l1_table_offset = cpu_to_be64(sn->l1_table_offset);
151 c142442b Kevin Wolf
        h.l1_size = cpu_to_be32(sn->l1_size);
152 c142442b Kevin Wolf
        h.vm_state_size = cpu_to_be32(sn->vm_state_size);
153 c142442b Kevin Wolf
        h.date_sec = cpu_to_be32(sn->date_sec);
154 c142442b Kevin Wolf
        h.date_nsec = cpu_to_be32(sn->date_nsec);
155 c142442b Kevin Wolf
        h.vm_clock_nsec = cpu_to_be64(sn->vm_clock_nsec);
156 c142442b Kevin Wolf
157 c142442b Kevin Wolf
        id_str_size = strlen(sn->id_str);
158 c142442b Kevin Wolf
        name_size = strlen(sn->name);
159 c142442b Kevin Wolf
        h.id_str_size = cpu_to_be16(id_str_size);
160 c142442b Kevin Wolf
        h.name_size = cpu_to_be16(name_size);
161 c142442b Kevin Wolf
        offset = align_offset(offset, 8);
162 8b3b7206 Kevin Wolf
        if (bdrv_pwrite_sync(bs->file, offset, &h, sizeof(h)) < 0)
163 c142442b Kevin Wolf
            goto fail;
164 c142442b Kevin Wolf
        offset += sizeof(h);
165 8b3b7206 Kevin Wolf
        if (bdrv_pwrite_sync(bs->file, offset, sn->id_str, id_str_size) < 0)
166 c142442b Kevin Wolf
            goto fail;
167 c142442b Kevin Wolf
        offset += id_str_size;
168 8b3b7206 Kevin Wolf
        if (bdrv_pwrite_sync(bs->file, offset, sn->name, name_size) < 0)
169 c142442b Kevin Wolf
            goto fail;
170 c142442b Kevin Wolf
        offset += name_size;
171 c142442b Kevin Wolf
    }
172 c142442b Kevin Wolf
173 c142442b Kevin Wolf
    /* update the various header fields */
174 c142442b Kevin Wolf
    data64 = cpu_to_be64(snapshots_offset);
175 8b3b7206 Kevin Wolf
    if (bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, snapshots_offset),
176 8b3b7206 Kevin Wolf
                    &data64, sizeof(data64)) < 0)
177 c142442b Kevin Wolf
        goto fail;
178 c142442b Kevin Wolf
    data32 = cpu_to_be32(s->nb_snapshots);
179 8b3b7206 Kevin Wolf
    if (bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, nb_snapshots),
180 8b3b7206 Kevin Wolf
                    &data32, sizeof(data32)) < 0)
181 c142442b Kevin Wolf
        goto fail;
182 c142442b Kevin Wolf
183 c142442b Kevin Wolf
    /* free the old snapshot table */
184 ed6ccf0f Kevin Wolf
    qcow2_free_clusters(bs, s->snapshots_offset, s->snapshots_size);
185 c142442b Kevin Wolf
    s->snapshots_offset = snapshots_offset;
186 c142442b Kevin Wolf
    s->snapshots_size = snapshots_size;
187 c142442b Kevin Wolf
    return 0;
188 c142442b Kevin Wolf
 fail:
189 c142442b Kevin Wolf
    return -1;
190 c142442b Kevin Wolf
}
191 c142442b Kevin Wolf
192 c142442b Kevin Wolf
static void find_new_snapshot_id(BlockDriverState *bs,
193 c142442b Kevin Wolf
                                 char *id_str, int id_str_size)
194 c142442b Kevin Wolf
{
195 c142442b Kevin Wolf
    BDRVQcowState *s = bs->opaque;
196 c142442b Kevin Wolf
    QCowSnapshot *sn;
197 c142442b Kevin Wolf
    int i, id, id_max = 0;
198 c142442b Kevin Wolf
199 c142442b Kevin Wolf
    for(i = 0; i < s->nb_snapshots; i++) {
200 c142442b Kevin Wolf
        sn = s->snapshots + i;
201 c142442b Kevin Wolf
        id = strtoul(sn->id_str, NULL, 10);
202 c142442b Kevin Wolf
        if (id > id_max)
203 c142442b Kevin Wolf
            id_max = id;
204 c142442b Kevin Wolf
    }
205 c142442b Kevin Wolf
    snprintf(id_str, id_str_size, "%d", id_max + 1);
206 c142442b Kevin Wolf
}
207 c142442b Kevin Wolf
208 c142442b Kevin Wolf
static int find_snapshot_by_id(BlockDriverState *bs, const char *id_str)
209 c142442b Kevin Wolf
{
210 c142442b Kevin Wolf
    BDRVQcowState *s = bs->opaque;
211 c142442b Kevin Wolf
    int i;
212 c142442b Kevin Wolf
213 c142442b Kevin Wolf
    for(i = 0; i < s->nb_snapshots; i++) {
214 c142442b Kevin Wolf
        if (!strcmp(s->snapshots[i].id_str, id_str))
215 c142442b Kevin Wolf
            return i;
216 c142442b Kevin Wolf
    }
217 c142442b Kevin Wolf
    return -1;
218 c142442b Kevin Wolf
}
219 c142442b Kevin Wolf
220 c142442b Kevin Wolf
static int find_snapshot_by_id_or_name(BlockDriverState *bs, const char *name)
221 c142442b Kevin Wolf
{
222 c142442b Kevin Wolf
    BDRVQcowState *s = bs->opaque;
223 c142442b Kevin Wolf
    int i, ret;
224 c142442b Kevin Wolf
225 c142442b Kevin Wolf
    ret = find_snapshot_by_id(bs, name);
226 c142442b Kevin Wolf
    if (ret >= 0)
227 c142442b Kevin Wolf
        return ret;
228 c142442b Kevin Wolf
    for(i = 0; i < s->nb_snapshots; i++) {
229 c142442b Kevin Wolf
        if (!strcmp(s->snapshots[i].name, name))
230 c142442b Kevin Wolf
            return i;
231 c142442b Kevin Wolf
    }
232 c142442b Kevin Wolf
    return -1;
233 c142442b Kevin Wolf
}
234 c142442b Kevin Wolf
235 c142442b Kevin Wolf
/* if no id is provided, a new one is constructed */
236 ed6ccf0f Kevin Wolf
int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
237 c142442b Kevin Wolf
{
238 c142442b Kevin Wolf
    BDRVQcowState *s = bs->opaque;
239 c142442b Kevin Wolf
    QCowSnapshot *snapshots1, sn1, *sn = &sn1;
240 c142442b Kevin Wolf
    int i, ret;
241 c142442b Kevin Wolf
    uint64_t *l1_table = NULL;
242 5d757b56 Kevin Wolf
    int64_t l1_table_offset;
243 c142442b Kevin Wolf
244 c142442b Kevin Wolf
    memset(sn, 0, sizeof(*sn));
245 c142442b Kevin Wolf
246 c142442b Kevin Wolf
    if (sn_info->id_str[0] == '\0') {
247 c142442b Kevin Wolf
        /* compute a new id */
248 c142442b Kevin Wolf
        find_new_snapshot_id(bs, sn_info->id_str, sizeof(sn_info->id_str));
249 c142442b Kevin Wolf
    }
250 c142442b Kevin Wolf
251 c142442b Kevin Wolf
    /* check that the ID is unique */
252 c142442b Kevin Wolf
    if (find_snapshot_by_id(bs, sn_info->id_str) >= 0)
253 c142442b Kevin Wolf
        return -ENOENT;
254 c142442b Kevin Wolf
255 c142442b Kevin Wolf
    sn->id_str = qemu_strdup(sn_info->id_str);
256 c142442b Kevin Wolf
    if (!sn->id_str)
257 c142442b Kevin Wolf
        goto fail;
258 c142442b Kevin Wolf
    sn->name = qemu_strdup(sn_info->name);
259 c142442b Kevin Wolf
    if (!sn->name)
260 c142442b Kevin Wolf
        goto fail;
261 c142442b Kevin Wolf
    sn->vm_state_size = sn_info->vm_state_size;
262 c142442b Kevin Wolf
    sn->date_sec = sn_info->date_sec;
263 c142442b Kevin Wolf
    sn->date_nsec = sn_info->date_nsec;
264 c142442b Kevin Wolf
    sn->vm_clock_nsec = sn_info->vm_clock_nsec;
265 c142442b Kevin Wolf
266 ed6ccf0f Kevin Wolf
    ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 1);
267 c142442b Kevin Wolf
    if (ret < 0)
268 c142442b Kevin Wolf
        goto fail;
269 c142442b Kevin Wolf
270 c142442b Kevin Wolf
    /* create the L1 table of the snapshot */
271 5d757b56 Kevin Wolf
    l1_table_offset = qcow2_alloc_clusters(bs, s->l1_size * sizeof(uint64_t));
272 5d757b56 Kevin Wolf
    if (l1_table_offset < 0) {
273 5d757b56 Kevin Wolf
        goto fail;
274 5d757b56 Kevin Wolf
    }
275 29216ed1 Kevin Wolf
    bdrv_flush(bs->file);
276 5d757b56 Kevin Wolf
277 5d757b56 Kevin Wolf
    sn->l1_table_offset = l1_table_offset;
278 c142442b Kevin Wolf
    sn->l1_size = s->l1_size;
279 c142442b Kevin Wolf
280 702ef63f Kevin Wolf
    if (s->l1_size != 0) {
281 702ef63f Kevin Wolf
        l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
282 702ef63f Kevin Wolf
    } else {
283 702ef63f Kevin Wolf
        l1_table = NULL;
284 702ef63f Kevin Wolf
    }
285 702ef63f Kevin Wolf
286 c142442b Kevin Wolf
    for(i = 0; i < s->l1_size; i++) {
287 c142442b Kevin Wolf
        l1_table[i] = cpu_to_be64(s->l1_table[i]);
288 c142442b Kevin Wolf
    }
289 8b3b7206 Kevin Wolf
    if (bdrv_pwrite_sync(bs->file, sn->l1_table_offset,
290 8b3b7206 Kevin Wolf
                    l1_table, s->l1_size * sizeof(uint64_t)) < 0)
291 c142442b Kevin Wolf
        goto fail;
292 c142442b Kevin Wolf
    qemu_free(l1_table);
293 c142442b Kevin Wolf
    l1_table = NULL;
294 c142442b Kevin Wolf
295 c142442b Kevin Wolf
    snapshots1 = qemu_malloc((s->nb_snapshots + 1) * sizeof(QCowSnapshot));
296 c142442b Kevin Wolf
    if (s->snapshots) {
297 c142442b Kevin Wolf
        memcpy(snapshots1, s->snapshots, s->nb_snapshots * sizeof(QCowSnapshot));
298 c142442b Kevin Wolf
        qemu_free(s->snapshots);
299 c142442b Kevin Wolf
    }
300 c142442b Kevin Wolf
    s->snapshots = snapshots1;
301 c142442b Kevin Wolf
    s->snapshots[s->nb_snapshots++] = *sn;
302 c142442b Kevin Wolf
303 c142442b Kevin Wolf
    if (qcow_write_snapshots(bs) < 0)
304 c142442b Kevin Wolf
        goto fail;
305 c142442b Kevin Wolf
#ifdef DEBUG_ALLOC
306 14899cdf Filip Navara
    qcow2_check_refcounts(bs);
307 c142442b Kevin Wolf
#endif
308 c142442b Kevin Wolf
    return 0;
309 c142442b Kevin Wolf
 fail:
310 c142442b Kevin Wolf
    qemu_free(sn->name);
311 c142442b Kevin Wolf
    qemu_free(l1_table);
312 c142442b Kevin Wolf
    return -1;
313 c142442b Kevin Wolf
}
314 c142442b Kevin Wolf
315 c142442b Kevin Wolf
/* copy the snapshot 'snapshot_name' into the current disk image */
316 ed6ccf0f Kevin Wolf
int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
317 c142442b Kevin Wolf
{
318 c142442b Kevin Wolf
    BDRVQcowState *s = bs->opaque;
319 c142442b Kevin Wolf
    QCowSnapshot *sn;
320 c142442b Kevin Wolf
    int i, snapshot_index, l1_size2;
321 c142442b Kevin Wolf
322 c142442b Kevin Wolf
    snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
323 c142442b Kevin Wolf
    if (snapshot_index < 0)
324 c142442b Kevin Wolf
        return -ENOENT;
325 c142442b Kevin Wolf
    sn = &s->snapshots[snapshot_index];
326 c142442b Kevin Wolf
327 ed6ccf0f Kevin Wolf
    if (qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, -1) < 0)
328 c142442b Kevin Wolf
        goto fail;
329 c142442b Kevin Wolf
330 72893756 Stefan Hajnoczi
    if (qcow2_grow_l1_table(bs, sn->l1_size, true) < 0)
331 c142442b Kevin Wolf
        goto fail;
332 c142442b Kevin Wolf
333 c142442b Kevin Wolf
    s->l1_size = sn->l1_size;
334 c142442b Kevin Wolf
    l1_size2 = s->l1_size * sizeof(uint64_t);
335 c142442b Kevin Wolf
    /* copy the snapshot l1 table to the current l1 table */
336 66f82cee Kevin Wolf
    if (bdrv_pread(bs->file, sn->l1_table_offset,
337 c142442b Kevin Wolf
                   s->l1_table, l1_size2) != l1_size2)
338 c142442b Kevin Wolf
        goto fail;
339 8b3b7206 Kevin Wolf
    if (bdrv_pwrite_sync(bs->file, s->l1_table_offset,
340 8b3b7206 Kevin Wolf
                    s->l1_table, l1_size2) < 0)
341 c142442b Kevin Wolf
        goto fail;
342 c142442b Kevin Wolf
    for(i = 0;i < s->l1_size; i++) {
343 c142442b Kevin Wolf
        be64_to_cpus(&s->l1_table[i]);
344 c142442b Kevin Wolf
    }
345 c142442b Kevin Wolf
346 ed6ccf0f Kevin Wolf
    if (qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 1) < 0)
347 c142442b Kevin Wolf
        goto fail;
348 c142442b Kevin Wolf
349 c142442b Kevin Wolf
#ifdef DEBUG_ALLOC
350 14899cdf Filip Navara
    qcow2_check_refcounts(bs);
351 c142442b Kevin Wolf
#endif
352 c142442b Kevin Wolf
    return 0;
353 c142442b Kevin Wolf
 fail:
354 c142442b Kevin Wolf
    return -EIO;
355 c142442b Kevin Wolf
}
356 c142442b Kevin Wolf
357 ed6ccf0f Kevin Wolf
int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
358 c142442b Kevin Wolf
{
359 c142442b Kevin Wolf
    BDRVQcowState *s = bs->opaque;
360 c142442b Kevin Wolf
    QCowSnapshot *sn;
361 c142442b Kevin Wolf
    int snapshot_index, ret;
362 c142442b Kevin Wolf
363 c142442b Kevin Wolf
    snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
364 c142442b Kevin Wolf
    if (snapshot_index < 0)
365 c142442b Kevin Wolf
        return -ENOENT;
366 c142442b Kevin Wolf
    sn = &s->snapshots[snapshot_index];
367 c142442b Kevin Wolf
368 ed6ccf0f Kevin Wolf
    ret = qcow2_update_snapshot_refcount(bs, sn->l1_table_offset, sn->l1_size, -1);
369 c142442b Kevin Wolf
    if (ret < 0)
370 c142442b Kevin Wolf
        return ret;
371 c142442b Kevin Wolf
    /* must update the copied flag on the current cluster offsets */
372 ed6ccf0f Kevin Wolf
    ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 0);
373 c142442b Kevin Wolf
    if (ret < 0)
374 c142442b Kevin Wolf
        return ret;
375 ed6ccf0f Kevin Wolf
    qcow2_free_clusters(bs, sn->l1_table_offset, sn->l1_size * sizeof(uint64_t));
376 c142442b Kevin Wolf
377 c142442b Kevin Wolf
    qemu_free(sn->id_str);
378 c142442b Kevin Wolf
    qemu_free(sn->name);
379 c142442b Kevin Wolf
    memmove(sn, sn + 1, (s->nb_snapshots - snapshot_index - 1) * sizeof(*sn));
380 c142442b Kevin Wolf
    s->nb_snapshots--;
381 c142442b Kevin Wolf
    ret = qcow_write_snapshots(bs);
382 c142442b Kevin Wolf
    if (ret < 0) {
383 c142442b Kevin Wolf
        /* XXX: restore snapshot if error ? */
384 c142442b Kevin Wolf
        return ret;
385 c142442b Kevin Wolf
    }
386 c142442b Kevin Wolf
#ifdef DEBUG_ALLOC
387 14899cdf Filip Navara
    qcow2_check_refcounts(bs);
388 c142442b Kevin Wolf
#endif
389 c142442b Kevin Wolf
    return 0;
390 c142442b Kevin Wolf
}
391 c142442b Kevin Wolf
392 ed6ccf0f Kevin Wolf
int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
393 c142442b Kevin Wolf
{
394 c142442b Kevin Wolf
    BDRVQcowState *s = bs->opaque;
395 c142442b Kevin Wolf
    QEMUSnapshotInfo *sn_tab, *sn_info;
396 c142442b Kevin Wolf
    QCowSnapshot *sn;
397 c142442b Kevin Wolf
    int i;
398 c142442b Kevin Wolf
399 c142442b Kevin Wolf
    if (!s->nb_snapshots) {
400 c142442b Kevin Wolf
        *psn_tab = NULL;
401 c142442b Kevin Wolf
        return s->nb_snapshots;
402 c142442b Kevin Wolf
    }
403 c142442b Kevin Wolf
404 c142442b Kevin Wolf
    sn_tab = qemu_mallocz(s->nb_snapshots * sizeof(QEMUSnapshotInfo));
405 c142442b Kevin Wolf
    for(i = 0; i < s->nb_snapshots; i++) {
406 c142442b Kevin Wolf
        sn_info = sn_tab + i;
407 c142442b Kevin Wolf
        sn = s->snapshots + i;
408 c142442b Kevin Wolf
        pstrcpy(sn_info->id_str, sizeof(sn_info->id_str),
409 c142442b Kevin Wolf
                sn->id_str);
410 c142442b Kevin Wolf
        pstrcpy(sn_info->name, sizeof(sn_info->name),
411 c142442b Kevin Wolf
                sn->name);
412 c142442b Kevin Wolf
        sn_info->vm_state_size = sn->vm_state_size;
413 c142442b Kevin Wolf
        sn_info->date_sec = sn->date_sec;
414 c142442b Kevin Wolf
        sn_info->date_nsec = sn->date_nsec;
415 c142442b Kevin Wolf
        sn_info->vm_clock_nsec = sn->vm_clock_nsec;
416 c142442b Kevin Wolf
    }
417 c142442b Kevin Wolf
    *psn_tab = sn_tab;
418 c142442b Kevin Wolf
    return s->nb_snapshots;
419 c142442b Kevin Wolf
}