📄 block-qcow2.c.svn-base
字号:
qemu_free(out_buf); return -1; } } qemu_free(out_buf); return 0;}static void qcow_flush(BlockDriverState *bs){ BDRVQcowState *s = bs->opaque; bdrv_flush(s->hd);}static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi){ BDRVQcowState *s = bs->opaque; bdi->cluster_size = s->cluster_size; bdi->vm_state_offset = (int64_t)s->l1_vm_state_index << (s->cluster_bits + s->l2_bits); return 0;}/*********************************************************//* snapshot support *//* update the refcounts of snapshots and the copied flag */static int update_snapshot_refcount(BlockDriverState *bs, int64_t l1_table_offset, int l1_size, int addend){ BDRVQcowState *s = bs->opaque; uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2, l1_allocated; int64_t old_offset, old_l2_offset; int l2_size, i, j, l1_modified, l2_modified, nb_csectors, refcount; l2_cache_reset(bs); l2_table = NULL; l1_table = NULL; l1_size2 = l1_size * sizeof(uint64_t); l1_allocated = 0; if (l1_table_offset != s->l1_table_offset) { l1_table = qemu_malloc(l1_size2); if (!l1_table) goto fail; l1_allocated = 1; if (bdrv_pread(s->hd, l1_table_offset, l1_table, l1_size2) != l1_size2) goto fail; for(i = 0;i < l1_size; i++) be64_to_cpus(&l1_table[i]); } else { assert(l1_size == s->l1_size); l1_table = s->l1_table; l1_allocated = 0; } l2_size = s->l2_size * sizeof(uint64_t); l2_table = qemu_malloc(l2_size); if (!l2_table) goto fail; l1_modified = 0; for(i = 0; i < l1_size; i++) { l2_offset = l1_table[i]; if (l2_offset) { old_l2_offset = l2_offset; l2_offset &= ~QCOW_OFLAG_COPIED; l2_modified = 0; if (bdrv_pread(s->hd, l2_offset, l2_table, l2_size) != l2_size) goto fail; for(j = 0; j < s->l2_size; j++) { offset = be64_to_cpu(l2_table[j]); if (offset != 0) { old_offset = offset; offset &= ~QCOW_OFLAG_COPIED; if (offset & QCOW_OFLAG_COMPRESSED) { nb_csectors = ((offset >> s->csize_shift) & s->csize_mask) + 1; if (addend != 0) update_refcount(bs, (offset & s->cluster_offset_mask) & ~511, nb_csectors * 512, addend); /* compressed clusters are never modified */ refcount = 2; } else { if (addend != 0) { refcount = update_cluster_refcount(bs, offset >> s->cluster_bits, addend); } else { refcount = get_refcount(bs, offset >> s->cluster_bits); } } if (refcount == 1) { offset |= QCOW_OFLAG_COPIED; } if (offset != old_offset) { l2_table[j] = cpu_to_be64(offset); l2_modified = 1; } } } if (l2_modified) { if (bdrv_pwrite(s->hd, l2_offset, l2_table, l2_size) != l2_size) goto fail; } if (addend != 0) { refcount = update_cluster_refcount(bs, l2_offset >> s->cluster_bits, addend); } else { refcount = get_refcount(bs, l2_offset >> s->cluster_bits); } if (refcount == 1) { l2_offset |= QCOW_OFLAG_COPIED; } if (l2_offset != old_l2_offset) { l1_table[i] = l2_offset; l1_modified = 1; } } } if (l1_modified) { for(i = 0; i < l1_size; i++) cpu_to_be64s(&l1_table[i]); if (bdrv_pwrite(s->hd, l1_table_offset, l1_table, l1_size2) != l1_size2) goto fail; for(i = 0; i < l1_size; i++) be64_to_cpus(&l1_table[i]); } if (l1_allocated) qemu_free(l1_table); qemu_free(l2_table); return 0; fail: if (l1_allocated) qemu_free(l1_table); qemu_free(l2_table); return -EIO;}static void qcow_free_snapshots(BlockDriverState *bs){ BDRVQcowState *s = bs->opaque; int i; for(i = 0; i < s->nb_snapshots; i++) { qemu_free(s->snapshots[i].name); qemu_free(s->snapshots[i].id_str); } qemu_free(s->snapshots); s->snapshots = NULL; s->nb_snapshots = 0;}static int qcow_read_snapshots(BlockDriverState *bs){ BDRVQcowState *s = bs->opaque; QCowSnapshotHeader h; QCowSnapshot *sn; int i, id_str_size, name_size; int64_t offset; uint32_t extra_data_size; offset = s->snapshots_offset; s->snapshots = qemu_mallocz(s->nb_snapshots * sizeof(QCowSnapshot)); if (!s->snapshots) goto fail; for(i = 0; i < s->nb_snapshots; i++) { offset = align_offset(offset, 8); if (bdrv_pread(s->hd, offset, &h, sizeof(h)) != sizeof(h)) goto fail; 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); offset += extra_data_size; sn->id_str = qemu_malloc(id_str_size + 1); if (!sn->id_str) goto fail; if (bdrv_pread(s->hd, offset, sn->id_str, id_str_size) != id_str_size) goto fail; offset += id_str_size; sn->id_str[id_str_size] = '\0'; sn->name = qemu_malloc(name_size + 1); if (!sn->name) goto fail; if (bdrv_pread(s->hd, offset, sn->name, name_size) != name_size) goto fail; offset += name_size; sn->name[name_size] = '\0'; } s->snapshots_size = offset - s->snapshots_offset; return 0; fail: qcow_free_snapshots(bs); return -1;}/* add at the end of the file a new list of snapshots */static int qcow_write_snapshots(BlockDriverState *bs){ BDRVQcowState *s = bs->opaque; QCowSnapshot *sn; QCowSnapshotHeader h; int i, name_size, id_str_size, snapshots_size; uint64_t data64; uint32_t data32; int64_t offset, snapshots_offset; /* 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); offset += strlen(sn->id_str); offset += strlen(sn->name); } snapshots_size = offset; snapshots_offset = alloc_clusters(bs, snapshots_size); offset = snapshots_offset; 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); h.vm_state_size = cpu_to_be32(sn->vm_state_size); 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); 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); if (bdrv_pwrite(s->hd, offset, &h, sizeof(h)) != sizeof(h)) goto fail; offset += sizeof(h); if (bdrv_pwrite(s->hd, offset, sn->id_str, id_str_size) != id_str_size) goto fail; offset += id_str_size; if (bdrv_pwrite(s->hd, offset, sn->name, name_size) != name_size) goto fail; offset += name_size; } /* update the various header fields */ data64 = cpu_to_be64(snapshots_offset); if (bdrv_pwrite(s->hd, offsetof(QCowHeader, snapshots_offset), &data64, sizeof(data64)) != sizeof(data64)) goto fail; data32 = cpu_to_be32(s->nb_snapshots); if (bdrv_pwrite(s->hd, offsetof(QCowHeader, nb_snapshots), &data32, sizeof(data32)) != sizeof(data32)) goto fail; /* free the old snapshot table */ free_clusters(bs, s->snapshots_offset, s->snapshots_size); s->snapshots_offset = snapshots_offset; s->snapshots_size = snapshots_size; return 0; fail: return -1;}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 */static int qcow_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info){ BDRVQcowState *s = bs->opaque; QCowSnapshot *snapshots1, sn1, *sn = &sn1; int i, ret; uint64_t *l1_table = NULL; memset(sn, 0, sizeof(*sn)); if (sn_info->id_str[0] == '\0') { /* compute a new id */ find_new_snapshot_id(bs, sn_info->id_str, sizeof(sn_info->id_str)); } /* check that the ID is unique */ if (find_snapshot_by_id(bs, sn_info->id_str) >= 0) return -ENOENT; sn->id_str = qemu_strdup(sn_info->id_str); if (!sn->id_str) goto fail; sn->name = qemu_strdup(sn_info->name); if (!sn->name) goto fail; 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; ret = update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 1); if (ret < 0) goto fail; /* create the L1 table of the snapshot */ sn->l1_table_offset = alloc_clusters(bs, s->l1_size * sizeof(uint64_t)); sn->l1_size = s->l1_size; l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t)); if (!l1_table) goto fail; for(i = 0; i < s->l1_size; i++) { l1_table[i] = cpu_to_be64(s->l1_table[i]); } if (bdrv_pwrite(s->hd, sn->l1_table_offset, l1_table, s->l1_size * sizeof(uint64_t)) != (s->l1_size * sizeof(uint64_t))) goto fail; qemu_free(l1_table); l1_table = NULL; snapshots1 = qemu_malloc((s->nb_snapshots + 1) * sizeof(QCowSnapshot)); if (!snapshots1) goto fail; memcpy(snapshots1, s->snapshots, s->nb_snapshots * sizeof(QCowSnapshot)); s->snapshots = snapshots1; s->snapshots[s->nb_snapshots++] = *sn; if (qcow_write_snapshots(bs) < 0) goto fail;#ifdef DEBUG_ALLOC check_refcounts(bs);#endif return 0; fail: qemu_free(sn->name); qemu_free(l1_table); return -1;}/* copy the snapshot 'snapshot_name' into the current disk image */static int qcow_snapshot_goto(BlockDriverState *bs, const char *snapshot_id){ BDRVQcowState *s = bs->opaque; QCowSnapshot *sn; int i, snapshot_index, l1_size2; snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id); if (snapshot_index < 0) return -ENOENT;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -