qcow2-snapshot.c 18.1 KB
Newer Older
K
Kevin Wolf 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
/*
 * Block driver for the QCOW version 2 format
 *
 * Copyright (c) 2004-2006 Fabrice Bellard
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "qemu-common.h"
#include "block_int.h"
#include "block/qcow2.h"

29
typedef struct QEMU_PACKED QCowSnapshotHeader {
K
Kevin Wolf 已提交
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
    /* header is 8 byte aligned */
    uint64_t l1_table_offset;

    uint32_t l1_size;
    uint16_t id_str_size;
    uint16_t name_size;

    uint32_t date_sec;
    uint32_t date_nsec;

    uint64_t vm_clock_nsec;

    uint32_t vm_state_size;
    uint32_t extra_data_size; /* for extension */
    /* extra data follows */
    /* id_str follows */
    /* name follows  */
} QCowSnapshotHeader;

K
Kevin Wolf 已提交
49 50 51 52
typedef struct QEMU_PACKED QCowSnapshotExtraData {
    uint64_t vm_state_size_large;
} QCowSnapshotExtraData;

K
Kevin Wolf 已提交
53
void qcow2_free_snapshots(BlockDriverState *bs)
K
Kevin Wolf 已提交
54 55 56 57 58
{
    BDRVQcowState *s = bs->opaque;
    int i;

    for(i = 0; i < s->nb_snapshots; i++) {
59 60
        g_free(s->snapshots[i].name);
        g_free(s->snapshots[i].id_str);
K
Kevin Wolf 已提交
61
    }
62
    g_free(s->snapshots);
K
Kevin Wolf 已提交
63 64 65 66
    s->snapshots = NULL;
    s->nb_snapshots = 0;
}

K
Kevin Wolf 已提交
67
int qcow2_read_snapshots(BlockDriverState *bs)
K
Kevin Wolf 已提交
68 69 70
{
    BDRVQcowState *s = bs->opaque;
    QCowSnapshotHeader h;
K
Kevin Wolf 已提交
71
    QCowSnapshotExtraData extra;
K
Kevin Wolf 已提交
72 73 74 75
    QCowSnapshot *sn;
    int i, id_str_size, name_size;
    int64_t offset;
    uint32_t extra_data_size;
76
    int ret;
K
Kevin Wolf 已提交
77 78 79 80 81 82 83 84

    if (!s->nb_snapshots) {
        s->snapshots = NULL;
        s->snapshots_size = 0;
        return 0;
    }

    offset = s->snapshots_offset;
85
    s->snapshots = g_malloc0(s->nb_snapshots * sizeof(QCowSnapshot));
86

K
Kevin Wolf 已提交
87
    for(i = 0; i < s->nb_snapshots; i++) {
88
        /* Read statically sized part of the snapshot header */
K
Kevin Wolf 已提交
89
        offset = align_offset(offset, 8);
90 91
        ret = bdrv_pread(bs->file, offset, &h, sizeof(h));
        if (ret < 0) {
K
Kevin Wolf 已提交
92
            goto fail;
93 94
        }

K
Kevin Wolf 已提交
95 96 97 98 99 100 101 102 103 104 105 106 107
        offset += sizeof(h);
        sn = s->snapshots + i;
        sn->l1_table_offset = be64_to_cpu(h.l1_table_offset);
        sn->l1_size = be32_to_cpu(h.l1_size);
        sn->vm_state_size = be32_to_cpu(h.vm_state_size);
        sn->date_sec = be32_to_cpu(h.date_sec);
        sn->date_nsec = be32_to_cpu(h.date_nsec);
        sn->vm_clock_nsec = be64_to_cpu(h.vm_clock_nsec);
        extra_data_size = be32_to_cpu(h.extra_data_size);

        id_str_size = be16_to_cpu(h.id_str_size);
        name_size = be16_to_cpu(h.name_size);

K
Kevin Wolf 已提交
108 109 110 111 112 113
        /* Read extra data */
        ret = bdrv_pread(bs->file, offset, &extra,
                         MIN(sizeof(extra), extra_data_size));
        if (ret < 0) {
            goto fail;
        }
K
Kevin Wolf 已提交
114 115
        offset += extra_data_size;

K
Kevin Wolf 已提交
116 117 118 119
        if (extra_data_size >= 8) {
            sn->vm_state_size = be64_to_cpu(extra.vm_state_size_large);
        }

120
        /* Read snapshot ID */
121
        sn->id_str = g_malloc(id_str_size + 1);
122 123
        ret = bdrv_pread(bs->file, offset, sn->id_str, id_str_size);
        if (ret < 0) {
K
Kevin Wolf 已提交
124
            goto fail;
125
        }
K
Kevin Wolf 已提交
126 127 128
        offset += id_str_size;
        sn->id_str[id_str_size] = '\0';

129
        /* Read snapshot name */
130
        sn->name = g_malloc(name_size + 1);
131 132
        ret = bdrv_pread(bs->file, offset, sn->name, name_size);
        if (ret < 0) {
K
Kevin Wolf 已提交
133
            goto fail;
134
        }
K
Kevin Wolf 已提交
135 136 137
        offset += name_size;
        sn->name[name_size] = '\0';
    }
138

K
Kevin Wolf 已提交
139 140
    s->snapshots_size = offset - s->snapshots_offset;
    return 0;
141 142

fail:
K
Kevin Wolf 已提交
143
    qcow2_free_snapshots(bs);
144
    return ret;
K
Kevin Wolf 已提交
145 146 147
}

/* add at the end of the file a new list of snapshots */
148
static int qcow2_write_snapshots(BlockDriverState *bs)
K
Kevin Wolf 已提交
149 150 151 152
{
    BDRVQcowState *s = bs->opaque;
    QCowSnapshot *sn;
    QCowSnapshotHeader h;
K
Kevin Wolf 已提交
153
    QCowSnapshotExtraData extra;
K
Kevin Wolf 已提交
154
    int i, name_size, id_str_size, snapshots_size;
155 156 157 158
    struct {
        uint32_t nb_snapshots;
        uint64_t snapshots_offset;
    } QEMU_PACKED header_data;
K
Kevin Wolf 已提交
159
    int64_t offset, snapshots_offset;
160
    int ret;
K
Kevin Wolf 已提交
161 162 163 164 165 166 167

    /* compute the size of the snapshots */
    offset = 0;
    for(i = 0; i < s->nb_snapshots; i++) {
        sn = s->snapshots + i;
        offset = align_offset(offset, 8);
        offset += sizeof(h);
K
Kevin Wolf 已提交
168
        offset += sizeof(extra);
K
Kevin Wolf 已提交
169 170 171 172 173
        offset += strlen(sn->id_str);
        offset += strlen(sn->name);
    }
    snapshots_size = offset;

174
    /* Allocate space for the new snapshot list */
K
Kevin Wolf 已提交
175
    snapshots_offset = qcow2_alloc_clusters(bs, snapshots_size);
176
    bdrv_flush(bs->file);
K
Kevin Wolf 已提交
177
    offset = snapshots_offset;
178 179 180
    if (offset < 0) {
        return offset;
    }
K
Kevin Wolf 已提交
181

182
    /* Write all snapshots to the new list */
K
Kevin Wolf 已提交
183 184 185 186 187
    for(i = 0; i < s->nb_snapshots; i++) {
        sn = s->snapshots + i;
        memset(&h, 0, sizeof(h));
        h.l1_table_offset = cpu_to_be64(sn->l1_table_offset);
        h.l1_size = cpu_to_be32(sn->l1_size);
K
Kevin Wolf 已提交
188 189 190 191 192
        /* If it doesn't fit in 32 bit, older implementations should treat it
         * as a disk-only snapshot rather than truncate the VM state */
        if (sn->vm_state_size <= 0xffffffff) {
            h.vm_state_size = cpu_to_be32(sn->vm_state_size);
        }
K
Kevin Wolf 已提交
193 194 195
        h.date_sec = cpu_to_be32(sn->date_sec);
        h.date_nsec = cpu_to_be32(sn->date_nsec);
        h.vm_clock_nsec = cpu_to_be64(sn->vm_clock_nsec);
K
Kevin Wolf 已提交
196 197 198 199
        h.extra_data_size = cpu_to_be32(sizeof(extra));

        memset(&extra, 0, sizeof(extra));
        extra.vm_state_size_large = cpu_to_be64(sn->vm_state_size);
K
Kevin Wolf 已提交
200 201 202 203 204 205

        id_str_size = strlen(sn->id_str);
        name_size = strlen(sn->name);
        h.id_str_size = cpu_to_be16(id_str_size);
        h.name_size = cpu_to_be16(name_size);
        offset = align_offset(offset, 8);
206 207 208

        ret = bdrv_pwrite(bs->file, offset, &h, sizeof(h));
        if (ret < 0) {
K
Kevin Wolf 已提交
209
            goto fail;
210
        }
K
Kevin Wolf 已提交
211
        offset += sizeof(h);
212

K
Kevin Wolf 已提交
213 214 215 216 217 218
        ret = bdrv_pwrite(bs->file, offset, &extra, sizeof(extra));
        if (ret < 0) {
            goto fail;
        }
        offset += sizeof(extra);

219 220
        ret = bdrv_pwrite(bs->file, offset, sn->id_str, id_str_size);
        if (ret < 0) {
K
Kevin Wolf 已提交
221
            goto fail;
222
        }
K
Kevin Wolf 已提交
223
        offset += id_str_size;
224 225 226

        ret = bdrv_pwrite(bs->file, offset, sn->name, name_size);
        if (ret < 0) {
K
Kevin Wolf 已提交
227
            goto fail;
228
        }
K
Kevin Wolf 已提交
229 230 231
        offset += name_size;
    }

232 233 234 235 236 237 238 239 240
    /*
     * Update the header to point to the new snapshot table. This requires the
     * new table and its refcounts to be stable on disk.
     */
    ret = bdrv_flush(bs);
    if (ret < 0) {
        goto fail;
    }

241 242 243 244 245
    QEMU_BUILD_BUG_ON(offsetof(QCowHeader, snapshots_offset) !=
        offsetof(QCowHeader, nb_snapshots) + sizeof(header_data.nb_snapshots));

    header_data.nb_snapshots        = cpu_to_be32(s->nb_snapshots);
    header_data.snapshots_offset    = cpu_to_be64(snapshots_offset);
246 247

    ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, nb_snapshots),
248
                           &header_data, sizeof(header_data));
249
    if (ret < 0) {
K
Kevin Wolf 已提交
250
        goto fail;
251
    }
K
Kevin Wolf 已提交
252 253

    /* free the old snapshot table */
K
Kevin Wolf 已提交
254
    qcow2_free_clusters(bs, s->snapshots_offset, s->snapshots_size);
K
Kevin Wolf 已提交
255 256 257
    s->snapshots_offset = snapshots_offset;
    s->snapshots_size = snapshots_size;
    return 0;
258 259 260

fail:
    return ret;
K
Kevin Wolf 已提交
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
}

static void find_new_snapshot_id(BlockDriverState *bs,
                                 char *id_str, int id_str_size)
{
    BDRVQcowState *s = bs->opaque;
    QCowSnapshot *sn;
    int i, id, id_max = 0;

    for(i = 0; i < s->nb_snapshots; i++) {
        sn = s->snapshots + i;
        id = strtoul(sn->id_str, NULL, 10);
        if (id > id_max)
            id_max = id;
    }
    snprintf(id_str, id_str_size, "%d", id_max + 1);
}

static int find_snapshot_by_id(BlockDriverState *bs, const char *id_str)
{
    BDRVQcowState *s = bs->opaque;
    int i;

    for(i = 0; i < s->nb_snapshots; i++) {
        if (!strcmp(s->snapshots[i].id_str, id_str))
            return i;
    }
    return -1;
}

static int find_snapshot_by_id_or_name(BlockDriverState *bs, const char *name)
{
    BDRVQcowState *s = bs->opaque;
    int i, ret;

    ret = find_snapshot_by_id(bs, name);
    if (ret >= 0)
        return ret;
    for(i = 0; i < s->nb_snapshots; i++) {
        if (!strcmp(s->snapshots[i].name, name))
            return i;
    }
    return -1;
}

/* if no id is provided, a new one is constructed */
K
Kevin Wolf 已提交
307
int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
K
Kevin Wolf 已提交
308 309
{
    BDRVQcowState *s = bs->opaque;
310 311 312
    QCowSnapshot *new_snapshot_list = NULL;
    QCowSnapshot *old_snapshot_list = NULL;
    QCowSnapshot sn1, *sn = &sn1;
K
Kevin Wolf 已提交
313 314
    int i, ret;
    uint64_t *l1_table = NULL;
315
    int64_t l1_table_offset;
K
Kevin Wolf 已提交
316 317 318

    memset(sn, 0, sizeof(*sn));

319
    /* Generate an ID if it wasn't passed */
K
Kevin Wolf 已提交
320 321 322 323
    if (sn_info->id_str[0] == '\0') {
        find_new_snapshot_id(bs, sn_info->id_str, sizeof(sn_info->id_str));
    }

324 325
    /* Check that the ID is unique */
    if (find_snapshot_by_id(bs, sn_info->id_str) >= 0) {
K
Kevin Wolf 已提交
326
        return -ENOENT;
327
    }
K
Kevin Wolf 已提交
328

329
    /* Populate sn with passed data */
330 331
    sn->id_str = g_strdup(sn_info->id_str);
    sn->name = g_strdup(sn_info->name);
332

K
Kevin Wolf 已提交
333 334 335 336 337
    sn->vm_state_size = sn_info->vm_state_size;
    sn->date_sec = sn_info->date_sec;
    sn->date_nsec = sn_info->date_nsec;
    sn->vm_clock_nsec = sn_info->vm_clock_nsec;

338
    /* Allocate the L1 table of the snapshot and copy the current one there. */
339 340
    l1_table_offset = qcow2_alloc_clusters(bs, s->l1_size * sizeof(uint64_t));
    if (l1_table_offset < 0) {
341
        ret = l1_table_offset;
342 343 344 345
        goto fail;
    }

    sn->l1_table_offset = l1_table_offset;
K
Kevin Wolf 已提交
346 347
    sn->l1_size = s->l1_size;

348
    l1_table = g_malloc(s->l1_size * sizeof(uint64_t));
K
Kevin Wolf 已提交
349 350 351
    for(i = 0; i < s->l1_size; i++) {
        l1_table[i] = cpu_to_be64(s->l1_table[i]);
    }
352 353 354 355

    ret = bdrv_pwrite(bs->file, sn->l1_table_offset, l1_table,
                      s->l1_size * sizeof(uint64_t));
    if (ret < 0) {
K
Kevin Wolf 已提交
356
        goto fail;
357 358
    }

359
    g_free(l1_table);
K
Kevin Wolf 已提交
360 361
    l1_table = NULL;

362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
    /*
     * Increase the refcounts of all clusters and make sure everything is
     * stable on disk before updating the snapshot table to contain a pointer
     * to the new L1 table.
     */
    ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 1);
    if (ret < 0) {
        goto fail;
    }

    ret = bdrv_flush(bs);
    if (ret < 0) {
        goto fail;
    }

    /* Append the new snapshot to the snapshot list */
    new_snapshot_list = g_malloc((s->nb_snapshots + 1) * sizeof(QCowSnapshot));
K
Kevin Wolf 已提交
379
    if (s->snapshots) {
380 381 382
        memcpy(new_snapshot_list, s->snapshots,
               s->nb_snapshots * sizeof(QCowSnapshot));
        old_snapshot_list = s->snapshots;
K
Kevin Wolf 已提交
383
    }
384
    s->snapshots = new_snapshot_list;
K
Kevin Wolf 已提交
385 386
    s->snapshots[s->nb_snapshots++] = *sn;

387 388 389 390
    ret = qcow2_write_snapshots(bs);
    if (ret < 0) {
        g_free(s->snapshots);
        s->snapshots = old_snapshot_list;
K
Kevin Wolf 已提交
391
        goto fail;
392 393 394 395
    }

    g_free(old_snapshot_list);

K
Kevin Wolf 已提交
396
#ifdef DEBUG_ALLOC
P
Philipp Hahn 已提交
397 398 399 400
    {
      BdrvCheckResult result = {0};
      qcow2_check_refcounts(bs, &result);
    }
K
Kevin Wolf 已提交
401 402
#endif
    return 0;
403 404 405

fail:
    g_free(sn->id_str);
406 407
    g_free(sn->name);
    g_free(l1_table);
408 409

    return ret;
K
Kevin Wolf 已提交
410 411 412
}

/* copy the snapshot 'snapshot_name' into the current disk image */
K
Kevin Wolf 已提交
413
int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
K
Kevin Wolf 已提交
414 415 416
{
    BDRVQcowState *s = bs->opaque;
    QCowSnapshot *sn;
417 418
    int i, snapshot_index;
    int cur_l1_bytes, sn_l1_bytes;
419
    int ret;
420
    uint64_t *sn_l1_table = NULL;
K
Kevin Wolf 已提交
421

422
    /* Search the snapshot */
K
Kevin Wolf 已提交
423
    snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
424
    if (snapshot_index < 0) {
K
Kevin Wolf 已提交
425
        return -ENOENT;
426
    }
K
Kevin Wolf 已提交
427 428
    sn = &s->snapshots[snapshot_index];

429 430 431 432 433 434 435
    /*
     * Make sure that the current L1 table is big enough to contain the whole
     * L1 table of the snapshot. If the snapshot L1 table is smaller, the
     * current one must be padded with zeros.
     */
    ret = qcow2_grow_l1_table(bs, sn->l1_size, true);
    if (ret < 0) {
K
Kevin Wolf 已提交
436
        goto fail;
437
    }
K
Kevin Wolf 已提交
438

439 440 441
    cur_l1_bytes = s->l1_size * sizeof(uint64_t);
    sn_l1_bytes = sn->l1_size * sizeof(uint64_t);

442 443 444 445 446
    /*
     * Copy the snapshot L1 table to the current L1 table.
     *
     * Before overwriting the old current L1 table on disk, make sure to
     * increase all refcounts for the clusters referenced by the new one.
447 448
     * Decrease the refcount referenced by the old one only when the L1
     * table is overwritten.
449
     */
450 451 452 453 454 455 456 457 458
    sn_l1_table = g_malloc0(cur_l1_bytes);

    ret = bdrv_pread(bs->file, sn->l1_table_offset, sn_l1_table, sn_l1_bytes);
    if (ret < 0) {
        goto fail;
    }

    ret = qcow2_update_snapshot_refcount(bs, sn->l1_table_offset,
                                         sn->l1_size, 1);
459
    if (ret < 0) {
K
Kevin Wolf 已提交
460
        goto fail;
461 462
    }

463
    ret = bdrv_pwrite_sync(bs->file, s->l1_table_offset, sn_l1_table,
464 465
                           cur_l1_bytes);
    if (ret < 0) {
K
Kevin Wolf 已提交
466
        goto fail;
467 468
    }

469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485
    /*
     * Decrease refcount of clusters of current L1 table.
     *
     * At this point, the in-memory s->l1_table points to the old L1 table,
     * whereas on disk we already have the new one.
     *
     * qcow2_update_snapshot_refcount special cases the current L1 table to use
     * the in-memory data instead of really using the offset to load a new one,
     * which is why this works.
     */
    ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset,
                                         s->l1_size, -1);

    /*
     * Now update the in-memory L1 table to be in sync with the on-disk one. We
     * need to do this even if updating refcounts failed.
     */
K
Kevin Wolf 已提交
486
    for(i = 0;i < s->l1_size; i++) {
487
        s->l1_table[i] = be64_to_cpu(sn_l1_table[i]);
K
Kevin Wolf 已提交
488 489
    }

490 491 492 493 494 495 496 497 498 499 500 501
    if (ret < 0) {
        goto fail;
    }

    g_free(sn_l1_table);
    sn_l1_table = NULL;

    /*
     * Update QCOW_OFLAG_COPIED in the active L1 table (it may have changed
     * when we decreased the refcount of the old snapshot.
     */
    ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 0);
502
    if (ret < 0) {
K
Kevin Wolf 已提交
503
        goto fail;
504
    }
K
Kevin Wolf 已提交
505 506

#ifdef DEBUG_ALLOC
P
Philipp Hahn 已提交
507 508 509 510
    {
        BdrvCheckResult result = {0};
        qcow2_check_refcounts(bs, &result);
    }
K
Kevin Wolf 已提交
511 512
#endif
    return 0;
513 514

fail:
515
    g_free(sn_l1_table);
516
    return ret;
K
Kevin Wolf 已提交
517 518
}

K
Kevin Wolf 已提交
519
int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
K
Kevin Wolf 已提交
520 521
{
    BDRVQcowState *s = bs->opaque;
522
    QCowSnapshot sn;
K
Kevin Wolf 已提交
523 524
    int snapshot_index, ret;

525
    /* Search the snapshot */
K
Kevin Wolf 已提交
526
    snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
527
    if (snapshot_index < 0) {
K
Kevin Wolf 已提交
528
        return -ENOENT;
529 530
    }
    sn = s->snapshots[snapshot_index];
K
Kevin Wolf 已提交
531

532 533 534 535 536 537 538
    /* Remove it from the snapshot list */
    memmove(s->snapshots + snapshot_index,
            s->snapshots + snapshot_index + 1,
            (s->nb_snapshots - snapshot_index - 1) * sizeof(sn));
    s->nb_snapshots--;
    ret = qcow2_write_snapshots(bs);
    if (ret < 0) {
K
Kevin Wolf 已提交
539
        return ret;
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555
    }

    /*
     * The snapshot is now unused, clean up. If we fail after this point, we
     * won't recover but just leak clusters.
     */
    g_free(sn.id_str);
    g_free(sn.name);

    /*
     * Now decrease the refcounts of clusters referenced by the snapshot and
     * free the L1 table.
     */
    ret = qcow2_update_snapshot_refcount(bs, sn.l1_table_offset,
                                         sn.l1_size, -1);
    if (ret < 0) {
K
Kevin Wolf 已提交
556
        return ret;
557 558
    }
    qcow2_free_clusters(bs, sn.l1_table_offset, sn.l1_size * sizeof(uint64_t));
K
Kevin Wolf 已提交
559

560 561
    /* must update the copied flag on the current cluster offsets */
    ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 0);
K
Kevin Wolf 已提交
562 563 564
    if (ret < 0) {
        return ret;
    }
565

K
Kevin Wolf 已提交
566
#ifdef DEBUG_ALLOC
P
Philipp Hahn 已提交
567 568 569 570
    {
        BdrvCheckResult result = {0};
        qcow2_check_refcounts(bs, &result);
    }
K
Kevin Wolf 已提交
571 572 573 574
#endif
    return 0;
}

K
Kevin Wolf 已提交
575
int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
K
Kevin Wolf 已提交
576 577 578 579 580 581 582 583 584 585 586
{
    BDRVQcowState *s = bs->opaque;
    QEMUSnapshotInfo *sn_tab, *sn_info;
    QCowSnapshot *sn;
    int i;

    if (!s->nb_snapshots) {
        *psn_tab = NULL;
        return s->nb_snapshots;
    }

587
    sn_tab = g_malloc0(s->nb_snapshots * sizeof(QEMUSnapshotInfo));
K
Kevin Wolf 已提交
588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603
    for(i = 0; i < s->nb_snapshots; i++) {
        sn_info = sn_tab + i;
        sn = s->snapshots + i;
        pstrcpy(sn_info->id_str, sizeof(sn_info->id_str),
                sn->id_str);
        pstrcpy(sn_info->name, sizeof(sn_info->name),
                sn->name);
        sn_info->vm_state_size = sn->vm_state_size;
        sn_info->date_sec = sn->date_sec;
        sn_info->date_nsec = sn->date_nsec;
        sn_info->vm_clock_nsec = sn->vm_clock_nsec;
    }
    *psn_tab = sn_tab;
    return s->nb_snapshots;
}

E
edison 已提交
604 605
int qcow2_snapshot_load_tmp(BlockDriverState *bs, const char *snapshot_name)
{
606
    int i, snapshot_index;
E
edison 已提交
607 608
    BDRVQcowState *s = bs->opaque;
    QCowSnapshot *sn;
609 610 611
    uint64_t *new_l1_table;
    int new_l1_bytes;
    int ret;
E
edison 已提交
612

613 614 615
    assert(bs->read_only);

    /* Search the snapshot */
E
edison 已提交
616 617 618 619 620 621
    snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_name);
    if (snapshot_index < 0) {
        return -ENOENT;
    }
    sn = &s->snapshots[snapshot_index];

622 623 624
    /* Allocate and read in the snapshot's L1 table */
    new_l1_bytes = s->l1_size * sizeof(uint64_t);
    new_l1_table = g_malloc0(align_offset(new_l1_bytes, 512));
E
edison 已提交
625

626 627 628 629
    ret = bdrv_pread(bs->file, sn->l1_table_offset, new_l1_table, new_l1_bytes);
    if (ret < 0) {
        g_free(new_l1_table);
        return ret;
E
edison 已提交
630 631
    }

632 633 634 635 636 637 638
    /* Switch the L1 table */
    g_free(s->l1_table);

    s->l1_size = sn->l1_size;
    s->l1_table_offset = sn->l1_table_offset;
    s->l1_table = new_l1_table;

E
edison 已提交
639 640 641
    for(i = 0;i < s->l1_size; i++) {
        be64_to_cpus(&s->l1_table[i]);
    }
642

E
edison 已提交
643 644
    return 0;
}