#include "qemu/osdep.h"
#include "qapi/error.h"
#include "block/block_int.h"
-#include "block/qcow2.h"
+#include "qcow2.h"
#include "qemu/bswap.h"
#include "qemu/error-report.h"
#include "qemu/cutils.h"
for(i = 0; i < s->nb_snapshots; i++) {
/* Read statically sized part of the snapshot header */
- offset = align_offset(offset, 8);
+ offset = ROUND_UP(offset, 8);
ret = bdrv_pread(bs->file, offset, &h, sizeof(h));
if (ret < 0) {
goto fail;
offset = 0;
for(i = 0; i < s->nb_snapshots; i++) {
sn = s->snapshots + i;
- offset = align_offset(offset, 8);
+ offset = ROUND_UP(offset, 8);
offset += sizeof(h);
offset += sizeof(extra);
offset += strlen(sn->id_str);
/* The snapshot list position has not yet been updated, so these clusters
* must indeed be completely free */
- ret = qcow2_pre_write_overlap_check(bs, 0, offset, snapshots_size);
+ ret = qcow2_pre_write_overlap_check(bs, 0, offset, snapshots_size, false);
if (ret < 0) {
goto fail;
}
assert(id_str_size <= UINT16_MAX && name_size <= UINT16_MAX);
h.id_str_size = cpu_to_be16(id_str_size);
h.name_size = cpu_to_be16(name_size);
- offset = align_offset(offset, 8);
+ offset = ROUND_UP(offset, 8);
- ret = bdrv_pwrite(bs->file->bs, offset, &h, sizeof(h));
+ ret = bdrv_pwrite(bs->file, offset, &h, sizeof(h));
if (ret < 0) {
goto fail;
}
offset += sizeof(h);
- ret = bdrv_pwrite(bs->file->bs, offset, &extra, sizeof(extra));
+ ret = bdrv_pwrite(bs->file, offset, &extra, sizeof(extra));
if (ret < 0) {
goto fail;
}
offset += sizeof(extra);
- ret = bdrv_pwrite(bs->file->bs, offset, sn->id_str, id_str_size);
+ ret = bdrv_pwrite(bs->file, offset, sn->id_str, id_str_size);
if (ret < 0) {
goto fail;
}
offset += id_str_size;
- ret = bdrv_pwrite(bs->file->bs, offset, sn->name, name_size);
+ ret = bdrv_pwrite(bs->file, offset, sn->name, name_size);
if (ret < 0) {
goto fail;
}
header_data.nb_snapshots = cpu_to_be32(s->nb_snapshots);
header_data.snapshots_offset = cpu_to_be64(snapshots_offset);
- ret = bdrv_pwrite_sync(bs->file->bs, offsetof(QCowHeader, nb_snapshots),
+ ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, nb_snapshots),
&header_data, sizeof(header_data));
if (ret < 0) {
goto fail;
return -EFBIG;
}
+ if (has_data_file(bs)) {
+ return -ENOTSUP;
+ }
+
memset(sn, 0, sizeof(*sn));
/* Generate an 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_and_name(bs, sn_info->id_str, NULL) >= 0) {
- return -EEXIST;
- }
-
/* Populate sn with passed data */
sn->id_str = g_strdup(sn_info->id_str);
sn->name = g_strdup(sn_info->name);
}
ret = qcow2_pre_write_overlap_check(bs, 0, sn->l1_table_offset,
- s->l1_size * sizeof(uint64_t));
+ s->l1_size * sizeof(uint64_t), false);
if (ret < 0) {
goto fail;
}
- ret = bdrv_pwrite(bs->file->bs, sn->l1_table_offset, l1_table,
+ ret = bdrv_pwrite(bs->file, sn->l1_table_offset, l1_table,
s->l1_size * sizeof(uint64_t));
if (ret < 0) {
goto fail;
/* The VM state isn't needed any more in the active L1 table; in fact, it
* hurts by causing expensive COW for the next snapshot. */
- qcow2_discard_clusters(bs, qcow2_vm_state_offset(s),
- align_offset(sn->vm_state_size, s->cluster_size)
- >> BDRV_SECTOR_BITS,
- QCOW2_DISCARD_NEVER, false);
+ qcow2_cluster_discard(bs, qcow2_vm_state_offset(s),
+ ROUND_UP(sn->vm_state_size, s->cluster_size),
+ QCOW2_DISCARD_NEVER, false);
#ifdef DEBUG_ALLOC
{
{
BDRVQcow2State *s = bs->opaque;
QCowSnapshot *sn;
+ Error *local_err = NULL;
int i, snapshot_index;
int cur_l1_bytes, sn_l1_bytes;
int ret;
uint64_t *sn_l1_table = NULL;
+ if (has_data_file(bs)) {
+ return -ENOTSUP;
+ }
+
/* Search the snapshot */
snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
if (snapshot_index < 0) {
}
sn = &s->snapshots[snapshot_index];
+ ret = qcow2_validate_table(bs, sn->l1_table_offset, sn->l1_size,
+ sizeof(uint64_t), QCOW_MAX_L1_SIZE,
+ "Snapshot L1 table", &local_err);
+ if (ret < 0) {
+ error_report_err(local_err);
+ goto fail;
+ }
+
if (sn->disk_size != bs->total_sectors * BDRV_SECTOR_SIZE) {
error_report("qcow2: Loading snapshots with different disk "
"size is not implemented");
}
ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L1,
- s->l1_table_offset, cur_l1_bytes);
+ s->l1_table_offset, cur_l1_bytes,
+ false);
if (ret < 0) {
goto fail;
}
- ret = bdrv_pwrite_sync(bs->file->bs, s->l1_table_offset, sn_l1_table,
+ ret = bdrv_pwrite_sync(bs->file, s->l1_table_offset, sn_l1_table,
cur_l1_bytes);
if (ret < 0) {
goto fail;
QCowSnapshot sn;
int snapshot_index, ret;
+ if (has_data_file(bs)) {
+ return -ENOTSUP;
+ }
+
/* Search the snapshot */
snapshot_index = find_snapshot_by_id_and_name(bs, snapshot_id, name);
if (snapshot_index < 0) {
}
sn = s->snapshots[snapshot_index];
+ ret = qcow2_validate_table(bs, sn.l1_table_offset, sn.l1_size,
+ sizeof(uint64_t), QCOW_MAX_L1_SIZE,
+ "Snapshot L1 table", errp);
+ if (ret < 0) {
+ return ret;
+ }
+
/* Remove it from the snapshot list */
memmove(s->snapshots + snapshot_index,
s->snapshots + snapshot_index + 1,
QCowSnapshot *sn;
int i;
+ if (has_data_file(bs)) {
+ return -ENOTSUP;
+ }
if (!s->nb_snapshots) {
*psn_tab = NULL;
return s->nb_snapshots;
sn = &s->snapshots[snapshot_index];
/* Allocate and read in the snapshot's L1 table */
- if (sn->l1_size > QCOW_MAX_L1_SIZE / sizeof(uint64_t)) {
- error_setg(errp, "Snapshot L1 table too large");
- return -EFBIG;
+ ret = qcow2_validate_table(bs, sn->l1_table_offset, sn->l1_size,
+ sizeof(uint64_t), QCOW_MAX_L1_SIZE,
+ "Snapshot L1 table", errp);
+ if (ret < 0) {
+ return ret;
}
new_l1_bytes = sn->l1_size * sizeof(uint64_t);
new_l1_table = qemu_try_blockalign(bs->file->bs,
- align_offset(new_l1_bytes, 512));
+ ROUND_UP(new_l1_bytes, 512));
if (new_l1_table == NULL) {
return -ENOMEM;
}