|
|
1.1 root 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:
1.1.1.8 root 29: typedef struct QEMU_PACKED QCowSnapshotHeader {
1.1 root 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:
1.1.1.9 ! root 49: typedef struct QEMU_PACKED QCowSnapshotExtraData {
! 50: uint64_t vm_state_size_large;
! 51: uint64_t disk_size;
! 52: } QCowSnapshotExtraData;
! 53:
1.1 root 54: void qcow2_free_snapshots(BlockDriverState *bs)
55: {
56: BDRVQcowState *s = bs->opaque;
57: int i;
58:
59: for(i = 0; i < s->nb_snapshots; i++) {
1.1.1.8 root 60: g_free(s->snapshots[i].name);
61: g_free(s->snapshots[i].id_str);
1.1 root 62: }
1.1.1.8 root 63: g_free(s->snapshots);
1.1 root 64: s->snapshots = NULL;
65: s->nb_snapshots = 0;
66: }
67:
68: int qcow2_read_snapshots(BlockDriverState *bs)
69: {
70: BDRVQcowState *s = bs->opaque;
71: QCowSnapshotHeader h;
1.1.1.9 ! root 72: QCowSnapshotExtraData extra;
1.1 root 73: QCowSnapshot *sn;
74: int i, id_str_size, name_size;
75: int64_t offset;
76: uint32_t extra_data_size;
1.1.1.9 ! root 77: int ret;
1.1 root 78:
79: if (!s->nb_snapshots) {
80: s->snapshots = NULL;
81: s->snapshots_size = 0;
82: return 0;
83: }
84:
85: offset = s->snapshots_offset;
1.1.1.8 root 86: s->snapshots = g_malloc0(s->nb_snapshots * sizeof(QCowSnapshot));
1.1.1.9 ! root 87:
1.1 root 88: for(i = 0; i < s->nb_snapshots; i++) {
1.1.1.9 ! root 89: /* Read statically sized part of the snapshot header */
1.1 root 90: offset = align_offset(offset, 8);
1.1.1.9 ! root 91: ret = bdrv_pread(bs->file, offset, &h, sizeof(h));
! 92: if (ret < 0) {
1.1 root 93: goto fail;
1.1.1.9 ! root 94: }
! 95:
1.1 root 96: offset += sizeof(h);
97: sn = s->snapshots + i;
98: sn->l1_table_offset = be64_to_cpu(h.l1_table_offset);
99: sn->l1_size = be32_to_cpu(h.l1_size);
100: sn->vm_state_size = be32_to_cpu(h.vm_state_size);
101: sn->date_sec = be32_to_cpu(h.date_sec);
102: sn->date_nsec = be32_to_cpu(h.date_nsec);
103: sn->vm_clock_nsec = be64_to_cpu(h.vm_clock_nsec);
104: extra_data_size = be32_to_cpu(h.extra_data_size);
105:
106: id_str_size = be16_to_cpu(h.id_str_size);
107: name_size = be16_to_cpu(h.name_size);
108:
1.1.1.9 ! root 109: /* Read extra data */
! 110: ret = bdrv_pread(bs->file, offset, &extra,
! 111: MIN(sizeof(extra), extra_data_size));
! 112: if (ret < 0) {
! 113: goto fail;
! 114: }
1.1 root 115: offset += extra_data_size;
116:
1.1.1.9 ! root 117: if (extra_data_size >= 8) {
! 118: sn->vm_state_size = be64_to_cpu(extra.vm_state_size_large);
! 119: }
! 120:
! 121: if (extra_data_size >= 16) {
! 122: sn->disk_size = be64_to_cpu(extra.disk_size);
! 123: } else {
! 124: sn->disk_size = bs->total_sectors * BDRV_SECTOR_SIZE;
! 125: }
! 126:
! 127: /* Read snapshot ID */
1.1.1.8 root 128: sn->id_str = g_malloc(id_str_size + 1);
1.1.1.9 ! root 129: ret = bdrv_pread(bs->file, offset, sn->id_str, id_str_size);
! 130: if (ret < 0) {
1.1 root 131: goto fail;
1.1.1.9 ! root 132: }
1.1 root 133: offset += id_str_size;
134: sn->id_str[id_str_size] = '\0';
135:
1.1.1.9 ! root 136: /* Read snapshot name */
1.1.1.8 root 137: sn->name = g_malloc(name_size + 1);
1.1.1.9 ! root 138: ret = bdrv_pread(bs->file, offset, sn->name, name_size);
! 139: if (ret < 0) {
1.1 root 140: goto fail;
1.1.1.9 ! root 141: }
1.1 root 142: offset += name_size;
143: sn->name[name_size] = '\0';
144: }
1.1.1.9 ! root 145:
1.1 root 146: s->snapshots_size = offset - s->snapshots_offset;
147: return 0;
1.1.1.9 ! root 148:
! 149: fail:
1.1 root 150: qcow2_free_snapshots(bs);
1.1.1.9 ! root 151: return ret;
1.1 root 152: }
153:
154: /* add at the end of the file a new list of snapshots */
1.1.1.6 root 155: static int qcow2_write_snapshots(BlockDriverState *bs)
1.1 root 156: {
157: BDRVQcowState *s = bs->opaque;
158: QCowSnapshot *sn;
159: QCowSnapshotHeader h;
1.1.1.9 ! root 160: QCowSnapshotExtraData extra;
1.1 root 161: int i, name_size, id_str_size, snapshots_size;
1.1.1.9 ! root 162: struct {
! 163: uint32_t nb_snapshots;
! 164: uint64_t snapshots_offset;
! 165: } QEMU_PACKED header_data;
1.1 root 166: int64_t offset, snapshots_offset;
1.1.1.9 ! root 167: int ret;
1.1 root 168:
169: /* compute the size of the snapshots */
170: offset = 0;
171: for(i = 0; i < s->nb_snapshots; i++) {
172: sn = s->snapshots + i;
173: offset = align_offset(offset, 8);
174: offset += sizeof(h);
1.1.1.9 ! root 175: offset += sizeof(extra);
1.1 root 176: offset += strlen(sn->id_str);
177: offset += strlen(sn->name);
178: }
179: snapshots_size = offset;
180:
1.1.1.9 ! root 181: /* Allocate space for the new snapshot list */
1.1 root 182: snapshots_offset = qcow2_alloc_clusters(bs, snapshots_size);
1.1.1.6 root 183: bdrv_flush(bs->file);
1.1 root 184: offset = snapshots_offset;
1.1.1.3 root 185: if (offset < 0) {
186: return offset;
187: }
1.1 root 188:
1.1.1.9 ! root 189: /* Write all snapshots to the new list */
1.1 root 190: for(i = 0; i < s->nb_snapshots; i++) {
191: sn = s->snapshots + i;
192: memset(&h, 0, sizeof(h));
193: h.l1_table_offset = cpu_to_be64(sn->l1_table_offset);
194: h.l1_size = cpu_to_be32(sn->l1_size);
1.1.1.9 ! root 195: /* If it doesn't fit in 32 bit, older implementations should treat it
! 196: * as a disk-only snapshot rather than truncate the VM state */
! 197: if (sn->vm_state_size <= 0xffffffff) {
! 198: h.vm_state_size = cpu_to_be32(sn->vm_state_size);
! 199: }
1.1 root 200: h.date_sec = cpu_to_be32(sn->date_sec);
201: h.date_nsec = cpu_to_be32(sn->date_nsec);
202: h.vm_clock_nsec = cpu_to_be64(sn->vm_clock_nsec);
1.1.1.9 ! root 203: h.extra_data_size = cpu_to_be32(sizeof(extra));
! 204:
! 205: memset(&extra, 0, sizeof(extra));
! 206: extra.vm_state_size_large = cpu_to_be64(sn->vm_state_size);
! 207: extra.disk_size = cpu_to_be64(sn->disk_size);
1.1 root 208:
209: id_str_size = strlen(sn->id_str);
210: name_size = strlen(sn->name);
211: h.id_str_size = cpu_to_be16(id_str_size);
212: h.name_size = cpu_to_be16(name_size);
213: offset = align_offset(offset, 8);
1.1.1.9 ! root 214:
! 215: ret = bdrv_pwrite(bs->file, offset, &h, sizeof(h));
! 216: if (ret < 0) {
1.1 root 217: goto fail;
1.1.1.9 ! root 218: }
1.1 root 219: offset += sizeof(h);
1.1.1.9 ! root 220:
! 221: ret = bdrv_pwrite(bs->file, offset, &extra, sizeof(extra));
! 222: if (ret < 0) {
1.1 root 223: goto fail;
1.1.1.9 ! root 224: }
! 225: offset += sizeof(extra);
! 226:
! 227: ret = bdrv_pwrite(bs->file, offset, sn->id_str, id_str_size);
! 228: if (ret < 0) {
! 229: goto fail;
! 230: }
1.1 root 231: offset += id_str_size;
1.1.1.9 ! root 232:
! 233: ret = bdrv_pwrite(bs->file, offset, sn->name, name_size);
! 234: if (ret < 0) {
1.1 root 235: goto fail;
1.1.1.9 ! root 236: }
1.1 root 237: offset += name_size;
238: }
239:
1.1.1.9 ! root 240: /*
! 241: * Update the header to point to the new snapshot table. This requires the
! 242: * new table and its refcounts to be stable on disk.
! 243: */
! 244: ret = bdrv_flush(bs);
! 245: if (ret < 0) {
1.1 root 246: goto fail;
1.1.1.9 ! root 247: }
! 248:
! 249: QEMU_BUILD_BUG_ON(offsetof(QCowHeader, snapshots_offset) !=
! 250: offsetof(QCowHeader, nb_snapshots) + sizeof(header_data.nb_snapshots));
! 251:
! 252: header_data.nb_snapshots = cpu_to_be32(s->nb_snapshots);
! 253: header_data.snapshots_offset = cpu_to_be64(snapshots_offset);
! 254:
! 255: ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, nb_snapshots),
! 256: &header_data, sizeof(header_data));
! 257: if (ret < 0) {
! 258: goto fail;
! 259: }
1.1 root 260:
261: /* free the old snapshot table */
262: qcow2_free_clusters(bs, s->snapshots_offset, s->snapshots_size);
263: s->snapshots_offset = snapshots_offset;
264: s->snapshots_size = snapshots_size;
265: return 0;
1.1.1.9 ! root 266:
! 267: fail:
! 268: return ret;
1.1 root 269: }
270:
271: static void find_new_snapshot_id(BlockDriverState *bs,
272: char *id_str, int id_str_size)
273: {
274: BDRVQcowState *s = bs->opaque;
275: QCowSnapshot *sn;
276: int i, id, id_max = 0;
277:
278: for(i = 0; i < s->nb_snapshots; i++) {
279: sn = s->snapshots + i;
280: id = strtoul(sn->id_str, NULL, 10);
281: if (id > id_max)
282: id_max = id;
283: }
284: snprintf(id_str, id_str_size, "%d", id_max + 1);
285: }
286:
287: static int find_snapshot_by_id(BlockDriverState *bs, const char *id_str)
288: {
289: BDRVQcowState *s = bs->opaque;
290: int i;
291:
292: for(i = 0; i < s->nb_snapshots; i++) {
293: if (!strcmp(s->snapshots[i].id_str, id_str))
294: return i;
295: }
296: return -1;
297: }
298:
299: static int find_snapshot_by_id_or_name(BlockDriverState *bs, const char *name)
300: {
301: BDRVQcowState *s = bs->opaque;
302: int i, ret;
303:
304: ret = find_snapshot_by_id(bs, name);
305: if (ret >= 0)
306: return ret;
307: for(i = 0; i < s->nb_snapshots; i++) {
308: if (!strcmp(s->snapshots[i].name, name))
309: return i;
310: }
311: return -1;
312: }
313:
314: /* if no id is provided, a new one is constructed */
315: int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
316: {
317: BDRVQcowState *s = bs->opaque;
1.1.1.9 ! root 318: QCowSnapshot *new_snapshot_list = NULL;
! 319: QCowSnapshot *old_snapshot_list = NULL;
! 320: QCowSnapshot sn1, *sn = &sn1;
1.1 root 321: int i, ret;
322: uint64_t *l1_table = NULL;
1.1.1.3 root 323: int64_t l1_table_offset;
1.1 root 324:
325: memset(sn, 0, sizeof(*sn));
326:
1.1.1.9 ! root 327: /* Generate an ID if it wasn't passed */
1.1 root 328: if (sn_info->id_str[0] == '\0') {
329: find_new_snapshot_id(bs, sn_info->id_str, sizeof(sn_info->id_str));
330: }
331:
1.1.1.9 ! root 332: /* Check that the ID is unique */
! 333: if (find_snapshot_by_id(bs, sn_info->id_str) >= 0) {
! 334: return -EEXIST;
! 335: }
1.1 root 336:
1.1.1.9 ! root 337: /* Populate sn with passed data */
1.1.1.8 root 338: sn->id_str = g_strdup(sn_info->id_str);
339: sn->name = g_strdup(sn_info->name);
1.1.1.9 ! root 340:
! 341: sn->disk_size = bs->total_sectors * BDRV_SECTOR_SIZE;
1.1 root 342: sn->vm_state_size = sn_info->vm_state_size;
343: sn->date_sec = sn_info->date_sec;
344: sn->date_nsec = sn_info->date_nsec;
345: sn->vm_clock_nsec = sn_info->vm_clock_nsec;
346:
1.1.1.9 ! root 347: /* Allocate the L1 table of the snapshot and copy the current one there. */
1.1.1.3 root 348: l1_table_offset = qcow2_alloc_clusters(bs, s->l1_size * sizeof(uint64_t));
349: if (l1_table_offset < 0) {
1.1.1.9 ! root 350: ret = l1_table_offset;
1.1.1.3 root 351: goto fail;
352: }
353:
354: sn->l1_table_offset = l1_table_offset;
1.1 root 355: sn->l1_size = s->l1_size;
356:
1.1.1.9 ! root 357: l1_table = g_malloc(s->l1_size * sizeof(uint64_t));
1.1 root 358: for(i = 0; i < s->l1_size; i++) {
359: l1_table[i] = cpu_to_be64(s->l1_table[i]);
360: }
1.1.1.9 ! root 361:
! 362: ret = bdrv_pwrite(bs->file, sn->l1_table_offset, l1_table,
! 363: s->l1_size * sizeof(uint64_t));
! 364: if (ret < 0) {
1.1 root 365: goto fail;
1.1.1.9 ! root 366: }
! 367:
1.1.1.8 root 368: g_free(l1_table);
1.1 root 369: l1_table = NULL;
370:
1.1.1.9 ! root 371: /*
! 372: * Increase the refcounts of all clusters and make sure everything is
! 373: * stable on disk before updating the snapshot table to contain a pointer
! 374: * to the new L1 table.
! 375: */
! 376: ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 1);
! 377: if (ret < 0) {
! 378: goto fail;
! 379: }
! 380:
! 381: ret = bdrv_flush(bs);
! 382: if (ret < 0) {
! 383: goto fail;
! 384: }
! 385:
! 386: /* Append the new snapshot to the snapshot list */
! 387: new_snapshot_list = g_malloc((s->nb_snapshots + 1) * sizeof(QCowSnapshot));
1.1 root 388: if (s->snapshots) {
1.1.1.9 ! root 389: memcpy(new_snapshot_list, s->snapshots,
! 390: s->nb_snapshots * sizeof(QCowSnapshot));
! 391: old_snapshot_list = s->snapshots;
1.1 root 392: }
1.1.1.9 ! root 393: s->snapshots = new_snapshot_list;
1.1 root 394: s->snapshots[s->nb_snapshots++] = *sn;
395:
1.1.1.9 ! root 396: ret = qcow2_write_snapshots(bs);
! 397: if (ret < 0) {
! 398: g_free(s->snapshots);
! 399: s->snapshots = old_snapshot_list;
1.1 root 400: goto fail;
1.1.1.9 ! root 401: }
! 402:
! 403: g_free(old_snapshot_list);
! 404:
1.1 root 405: #ifdef DEBUG_ALLOC
1.1.1.8 root 406: {
407: BdrvCheckResult result = {0};
408: qcow2_check_refcounts(bs, &result);
409: }
1.1 root 410: #endif
411: return 0;
1.1.1.9 ! root 412:
! 413: fail:
! 414: g_free(sn->id_str);
1.1.1.8 root 415: g_free(sn->name);
416: g_free(l1_table);
1.1.1.9 ! root 417:
! 418: return ret;
1.1 root 419: }
420:
421: /* copy the snapshot 'snapshot_name' into the current disk image */
422: int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
423: {
424: BDRVQcowState *s = bs->opaque;
425: QCowSnapshot *sn;
1.1.1.7 root 426: int i, snapshot_index;
427: int cur_l1_bytes, sn_l1_bytes;
1.1.1.9 ! root 428: int ret;
! 429: uint64_t *sn_l1_table = NULL;
1.1 root 430:
1.1.1.9 ! root 431: /* Search the snapshot */
1.1 root 432: snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
1.1.1.9 ! root 433: if (snapshot_index < 0) {
1.1 root 434: return -ENOENT;
1.1.1.9 ! root 435: }
1.1 root 436: sn = &s->snapshots[snapshot_index];
437:
1.1.1.9 ! root 438: if (sn->disk_size != bs->total_sectors * BDRV_SECTOR_SIZE) {
! 439: error_report("qcow2: Loading snapshots with different disk "
! 440: "size is not implemented");
! 441: ret = -ENOTSUP;
1.1 root 442: goto fail;
1.1.1.9 ! root 443: }
1.1 root 444:
1.1.1.9 ! root 445: /*
! 446: * Make sure that the current L1 table is big enough to contain the whole
! 447: * L1 table of the snapshot. If the snapshot L1 table is smaller, the
! 448: * current one must be padded with zeros.
! 449: */
! 450: ret = qcow2_grow_l1_table(bs, sn->l1_size, true);
! 451: if (ret < 0) {
1.1 root 452: goto fail;
1.1.1.9 ! root 453: }
1.1 root 454:
1.1.1.7 root 455: cur_l1_bytes = s->l1_size * sizeof(uint64_t);
456: sn_l1_bytes = sn->l1_size * sizeof(uint64_t);
457:
1.1.1.9 ! root 458: /*
! 459: * Copy the snapshot L1 table to the current L1 table.
! 460: *
! 461: * Before overwriting the old current L1 table on disk, make sure to
! 462: * increase all refcounts for the clusters referenced by the new one.
! 463: * Decrease the refcount referenced by the old one only when the L1
! 464: * table is overwritten.
! 465: */
! 466: sn_l1_table = g_malloc0(cur_l1_bytes);
! 467:
! 468: ret = bdrv_pread(bs->file, sn->l1_table_offset, sn_l1_table, sn_l1_bytes);
! 469: if (ret < 0) {
! 470: goto fail;
1.1.1.7 root 471: }
472:
1.1.1.9 ! root 473: ret = qcow2_update_snapshot_refcount(bs, sn->l1_table_offset,
! 474: sn->l1_size, 1);
! 475: if (ret < 0) {
1.1 root 476: goto fail;
1.1.1.9 ! root 477: }
! 478:
! 479: ret = bdrv_pwrite_sync(bs->file, s->l1_table_offset, sn_l1_table,
! 480: cur_l1_bytes);
! 481: if (ret < 0) {
1.1 root 482: goto fail;
1.1.1.9 ! root 483: }
! 484:
! 485: /*
! 486: * Decrease refcount of clusters of current L1 table.
! 487: *
! 488: * At this point, the in-memory s->l1_table points to the old L1 table,
! 489: * whereas on disk we already have the new one.
! 490: *
! 491: * qcow2_update_snapshot_refcount special cases the current L1 table to use
! 492: * the in-memory data instead of really using the offset to load a new one,
! 493: * which is why this works.
! 494: */
! 495: ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset,
! 496: s->l1_size, -1);
! 497:
! 498: /*
! 499: * Now update the in-memory L1 table to be in sync with the on-disk one. We
! 500: * need to do this even if updating refcounts failed.
! 501: */
1.1 root 502: for(i = 0;i < s->l1_size; i++) {
1.1.1.9 ! root 503: s->l1_table[i] = be64_to_cpu(sn_l1_table[i]);
1.1 root 504: }
505:
1.1.1.9 ! root 506: if (ret < 0) {
! 507: goto fail;
! 508: }
! 509:
! 510: g_free(sn_l1_table);
! 511: sn_l1_table = NULL;
! 512:
! 513: /*
! 514: * Update QCOW_OFLAG_COPIED in the active L1 table (it may have changed
! 515: * when we decreased the refcount of the old snapshot.
! 516: */
! 517: ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 0);
! 518: if (ret < 0) {
1.1 root 519: goto fail;
1.1.1.9 ! root 520: }
1.1 root 521:
522: #ifdef DEBUG_ALLOC
1.1.1.8 root 523: {
524: BdrvCheckResult result = {0};
525: qcow2_check_refcounts(bs, &result);
526: }
1.1 root 527: #endif
528: return 0;
1.1.1.9 ! root 529:
! 530: fail:
! 531: g_free(sn_l1_table);
! 532: return ret;
1.1 root 533: }
534:
535: int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
536: {
537: BDRVQcowState *s = bs->opaque;
1.1.1.9 ! root 538: QCowSnapshot sn;
1.1 root 539: int snapshot_index, ret;
540:
1.1.1.9 ! root 541: /* Search the snapshot */
1.1 root 542: snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
1.1.1.9 ! root 543: if (snapshot_index < 0) {
1.1 root 544: return -ENOENT;
1.1.1.9 ! root 545: }
! 546: sn = s->snapshots[snapshot_index];
1.1 root 547:
1.1.1.9 ! root 548: /* Remove it from the snapshot list */
! 549: memmove(s->snapshots + snapshot_index,
! 550: s->snapshots + snapshot_index + 1,
! 551: (s->nb_snapshots - snapshot_index - 1) * sizeof(sn));
! 552: s->nb_snapshots--;
! 553: ret = qcow2_write_snapshots(bs);
! 554: if (ret < 0) {
1.1 root 555: return ret;
1.1.1.9 ! root 556: }
! 557:
! 558: /*
! 559: * The snapshot is now unused, clean up. If we fail after this point, we
! 560: * won't recover but just leak clusters.
! 561: */
! 562: g_free(sn.id_str);
! 563: g_free(sn.name);
! 564:
! 565: /*
! 566: * Now decrease the refcounts of clusters referenced by the snapshot and
! 567: * free the L1 table.
! 568: */
! 569: ret = qcow2_update_snapshot_refcount(bs, sn.l1_table_offset,
! 570: sn.l1_size, -1);
! 571: if (ret < 0) {
1.1 root 572: return ret;
1.1.1.9 ! root 573: }
! 574: qcow2_free_clusters(bs, sn.l1_table_offset, sn.l1_size * sizeof(uint64_t));
1.1 root 575:
1.1.1.9 ! root 576: /* must update the copied flag on the current cluster offsets */
! 577: ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 0);
1.1 root 578: if (ret < 0) {
579: return ret;
580: }
1.1.1.9 ! root 581:
1.1 root 582: #ifdef DEBUG_ALLOC
1.1.1.8 root 583: {
584: BdrvCheckResult result = {0};
585: qcow2_check_refcounts(bs, &result);
586: }
1.1 root 587: #endif
588: return 0;
589: }
590:
591: int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
592: {
593: BDRVQcowState *s = bs->opaque;
594: QEMUSnapshotInfo *sn_tab, *sn_info;
595: QCowSnapshot *sn;
596: int i;
597:
598: if (!s->nb_snapshots) {
599: *psn_tab = NULL;
600: return s->nb_snapshots;
601: }
602:
1.1.1.8 root 603: sn_tab = g_malloc0(s->nb_snapshots * sizeof(QEMUSnapshotInfo));
1.1 root 604: for(i = 0; i < s->nb_snapshots; i++) {
605: sn_info = sn_tab + i;
606: sn = s->snapshots + i;
607: pstrcpy(sn_info->id_str, sizeof(sn_info->id_str),
608: sn->id_str);
609: pstrcpy(sn_info->name, sizeof(sn_info->name),
610: sn->name);
611: sn_info->vm_state_size = sn->vm_state_size;
612: sn_info->date_sec = sn->date_sec;
613: sn_info->date_nsec = sn->date_nsec;
614: sn_info->vm_clock_nsec = sn->vm_clock_nsec;
615: }
616: *psn_tab = sn_tab;
617: return s->nb_snapshots;
618: }
619:
1.1.1.6 root 620: int qcow2_snapshot_load_tmp(BlockDriverState *bs, const char *snapshot_name)
621: {
1.1.1.9 ! root 622: int i, snapshot_index;
1.1.1.6 root 623: BDRVQcowState *s = bs->opaque;
624: QCowSnapshot *sn;
1.1.1.9 ! root 625: uint64_t *new_l1_table;
! 626: int new_l1_bytes;
! 627: int ret;
1.1.1.6 root 628:
1.1.1.9 ! root 629: assert(bs->read_only);
! 630:
! 631: /* Search the snapshot */
1.1.1.6 root 632: snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_name);
633: if (snapshot_index < 0) {
634: return -ENOENT;
635: }
636: sn = &s->snapshots[snapshot_index];
637:
1.1.1.9 ! root 638: /* Allocate and read in the snapshot's L1 table */
! 639: new_l1_bytes = s->l1_size * sizeof(uint64_t);
! 640: new_l1_table = g_malloc0(align_offset(new_l1_bytes, 512));
1.1.1.6 root 641:
1.1.1.9 ! root 642: ret = bdrv_pread(bs->file, sn->l1_table_offset, new_l1_table, new_l1_bytes);
! 643: if (ret < 0) {
! 644: g_free(new_l1_table);
! 645: return ret;
1.1.1.6 root 646: }
647:
1.1.1.9 ! root 648: /* Switch the L1 table */
! 649: g_free(s->l1_table);
! 650:
! 651: s->l1_size = sn->l1_size;
! 652: s->l1_table_offset = sn->l1_table_offset;
! 653: s->l1_table = new_l1_table;
! 654:
1.1.1.6 root 655: for(i = 0;i < s->l1_size; i++) {
656: be64_to_cpus(&s->l1_table[i]);
657: }
1.1.1.9 ! root 658:
1.1.1.6 root 659: return 0;
660: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.