static void test_sync_op_pwrite(BdrvChild *c) { uint8_t buf[512]; int ret; /* Success */ ret = bdrv_pwrite(c, 0, buf, sizeof(buf)); g_assert_cmpint(ret, ==, 512); /* Early error: Negative offset */ ret = bdrv_pwrite(c, -2, buf, sizeof(buf)); g_assert_cmpint(ret, ==, -EIO); }
static uint32_t nand_dev_erase_file(nand_dev *dev, uint64_t addr, uint32_t total_len) { uint32_t len = total_len; size_t write_len = dev->erase_size; int ret; #if !defined(ANDROID_QCOW) do_lseek(dev->fd, addr, SEEK_SET); #endif memset(dev->data, 0xff, dev->erase_size); while(len > 0) { if(len < write_len) write_len = len; #if defined(ANDROID_QCOW) ret = bdrv_pwrite(dev->bdrv, addr, dev->data, write_len); #else ret = do_write(dev->fd, dev->data, write_len); #endif if(ret < write_len) { XLOG( "nand_dev_write_file, write failed: %s\n", strerror(errno)); break; } len -= write_len; addr += write_len; } return total_len - len; }
static int do_pwrite(char *buf, int64_t offset, int count, int *total) { *total = bdrv_pwrite(bs, offset, (uint8_t *)buf, count); if (*total < 0) return *total; return 1; }
static uint32_t nand_dev_write_file(nand_dev *dev, uint32_t data, uint64_t addr, uint32_t total_len) { uint32_t len = total_len; size_t write_len = dev->erase_size; int ret; NAND_UPDATE_WRITE_THRESHOLD(total_len); #if !defined(ANDROID_QCOW) do_lseek(dev->fd, addr, SEEK_SET); #endif while(len > 0) { if(len < write_len) write_len = len; #ifdef TARGET_I386 if (kvm_enabled()) cpu_synchronize_state(cpu_single_env, 0); #endif cpu_memory_rw(cpu_single_env, data, dev->data, write_len, 0); #if defined(ANDROID_QCOW) ret = bdrv_pwrite(dev->bdrv,addr, dev->data, write_len); #else ret = do_write(dev->fd, dev->data, write_len); #endif if(ret < write_len) { XLOG("nand_dev_write_file, write failed: %s\n", strerror(errno)); break; } data += write_len; len -= write_len; addr += write_len; } return total_len - len; }
static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i) { BDRVQcowState *s = bs->opaque; int ret = 0; if (!c->entries[i].dirty || !c->entries[i].offset) { return 0; } trace_qcow2_cache_entry_flush(qemu_coroutine_self(), c == s->l2_table_cache, i); if (c->depends) { ret = qcow2_cache_flush_dependency(bs, c); } else if (c->depends_on_flush) { ret = bdrv_flush(bs->file); if (ret >= 0) { c->depends_on_flush = false; } } if (ret < 0) { return ret; } if (c == s->refcount_block_cache) { ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT & ~QCOW2_OL_REFCOUNT_BLOCK, c->entries[i].offset, s->cluster_size); } else if (c == s->l2_table_cache) { ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT & ~QCOW2_OL_ACTIVE_L2, c->entries[i].offset, s->cluster_size); } else { ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT, c->entries[i].offset, s->cluster_size); } if (ret < 0) { return ret; } if (c == s->refcount_block_cache) { BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_UPDATE_PART); } else if (c == s->l2_table_cache) { BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE); } ret = bdrv_pwrite(bs->file, c->entries[i].offset, c->entries[i].table, s->cluster_size); if (ret < 0) { return ret; } c->entries[i].dirty = false; return 0; }
int qed_write_header_sync(BDRVQEDState *s) { QEDHeader le; int ret; qed_header_cpu_to_le(&s->header, &le); ret = bdrv_pwrite(s->bs->file, 0, &le, sizeof(le)); if (ret != sizeof(le)) { return ret; } return 0; }
static int write_refcount_block(BlockDriverState *bs) { BDRVQcowState *s = bs->opaque; size_t size = s->cluster_size; if (s->refcount_block_cache_offset == 0) { return 0; } BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_UPDATE); if (bdrv_pwrite(bs->file, s->refcount_block_cache_offset, s->refcount_block_cache, size) != size) { return -EIO; } return 0; }
/* copy the snapshot 'snapshot_name' into the current disk image */ int qcow2_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; sn = &s->snapshots[snapshot_index]; if (!bs->read_only && qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, -1) < 0) goto fail; if (qcow2_grow_l1_table(bs, sn->l1_size) < 0) goto fail; s->l1_size = sn->l1_size; l1_size2 = s->l1_size * sizeof(uint64_t); /* copy the snapshot l1 table to the current l1 table */ if (bdrv_pread(s->hd, sn->l1_table_offset, s->l1_table, l1_size2) != l1_size2) goto fail; if (bs->read_only) s->l1_table_offset = sn->l1_table_offset; else if (bdrv_pwrite(s->hd, s->l1_table_offset, s->l1_table, l1_size2) != l1_size2) goto fail; for(i = 0;i < s->l1_size; i++) { be64_to_cpus(&s->l1_table[i]); } if (!bs->read_only && qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 1) < 0) goto fail; #ifdef DEBUG_ALLOC qcow2_check_refcounts(bs); #endif return 0; fail: return -EIO; }
static void rtas_nvram_store(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t token, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) { sPAPRNVRAM *nvram = spapr->nvram; hwaddr offset, buffer, len; int alen; void *membuf; if ((nargs != 3) || (nret != 2)) { rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); return; } if (!nvram) { rtas_st(rets, 0, RTAS_OUT_HW_ERROR); return; } offset = rtas_ld(args, 0); buffer = rtas_ld(args, 1); len = rtas_ld(args, 2); if (((offset + len) < offset) || ((offset + len) > nvram->size)) { rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); return; } membuf = cpu_physical_memory_map(buffer, &len, 0); if (nvram->drive) { alen = bdrv_pwrite(nvram->drive, offset, membuf, len); } else { assert(nvram->buf); memcpy(nvram->buf + offset, membuf, len); alen = len; } cpu_physical_memory_unmap(membuf, len, 0, len); rtas_st(rets, 0, (alen < len) ? RTAS_OUT_HW_ERROR : RTAS_OUT_SUCCESS); rtas_st(rets, 1, (alen < 0) ? 0 : alen); }
/* Writes num_sectors to the log (all log sectors are 4096 bytes), * from buffer 'buffer'. Upon return, *sectors_written will contain * the number of sectors successfully written. * * It is assumed that 'buffer' is at least 4096*num_sectors large. * * 0 is returned on success, -errno otherwise */ static int vhdx_log_write_sectors(BlockDriverState *bs, VHDXLogEntries *log, uint32_t *sectors_written, void *buffer, uint32_t num_sectors) { int ret = 0; uint64_t offset; uint32_t write; void *buffer_tmp; BDRVVHDXState *s = bs->opaque; ret = vhdx_user_visible_write(bs, s); if (ret < 0) { goto exit; } write = log->write; buffer_tmp = buffer; while (num_sectors) { offset = log->offset + write; write = vhdx_log_inc_idx(write, log->length); if (write == log->read) { /* full */ break; } ret = bdrv_pwrite(bs->file->bs, offset, buffer_tmp, VHDX_LOG_SECTOR_SIZE); if (ret < 0) { goto exit; } buffer_tmp += VHDX_LOG_SECTOR_SIZE; log->write = write; *sectors_written = *sectors_written + 1; num_sectors--; } exit: return ret; }
static int vpc_write(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors) { BDRVVPCState *s = bs->opaque; int64_t offset; int64_t sectors, sectors_per_block; int ret; VHDFooter *footer = (VHDFooter *) s->footer_buf; if (be32_to_cpu(footer->type) == VHD_FIXED) { return bdrv_write(bs->file->bs, sector_num, buf, nb_sectors); } while (nb_sectors > 0) { offset = get_sector_offset(bs, sector_num, 1); sectors_per_block = s->block_size >> BDRV_SECTOR_BITS; sectors = sectors_per_block - (sector_num % sectors_per_block); if (sectors > nb_sectors) { sectors = nb_sectors; } if (offset == -1) { offset = alloc_block(bs, sector_num); if (offset < 0) return -1; } ret = bdrv_pwrite(bs->file->bs, offset, buf, sectors * BDRV_SECTOR_SIZE); if (ret != sectors * BDRV_SECTOR_SIZE) { return -1; } nb_sectors -= sectors; sector_num += sectors; buf += sectors * BDRV_SECTOR_SIZE; } return 0; }
static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i) { BDRVQcowState *s = bs->opaque; int ret = 0; if (!c->entries[i].dirty || !c->entries[i].offset) { return 0; } if (c->depends) { ret = qcow2_cache_flush_dependency(bs, c); } else if (c->depends_on_flush) { ret = bdrv_flush(bs->file); if (ret >= 0) { c->depends_on_flush = false; } } if (ret < 0) { return ret; } if (c == s->refcount_block_cache) { BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_UPDATE_PART); } else if (c == s->l2_table_cache) { BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE); } ret = bdrv_pwrite(bs->file, c->entries[i].offset, c->entries[i].table, s->cluster_size); if (ret < 0) { return ret; } c->entries[i].dirty = false; return 0; }
/* if no id is provided, a new one is constructed */ int qcow2_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 = qcow2_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 = qcow2_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)); 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 (s->snapshots) { memcpy(snapshots1, s->snapshots, s->nb_snapshots * sizeof(QCowSnapshot)); qemu_free(s->snapshots); } s->snapshots = snapshots1; s->snapshots[s->nb_snapshots++] = *sn; if (qcow_write_snapshots(bs) < 0) goto fail; #ifdef DEBUG_ALLOC qcow2_check_refcounts(bs); #endif return 0; fail: qemu_free(sn->name); qemu_free(l1_table); 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 = qcow2_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 */ qcow2_free_clusters(bs, s->snapshots_offset, s->snapshots_size); s->snapshots_offset = snapshots_offset; s->snapshots_size = snapshots_size; return 0; fail: return -1; }
/* if no id is provided, a new one is constructed */ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) { BDRVQcow2State *s = bs->opaque; QCowSnapshot *new_snapshot_list = NULL; QCowSnapshot *old_snapshot_list = NULL; QCowSnapshot sn1, *sn = &sn1; int i, ret; uint64_t *l1_table = NULL; int64_t l1_table_offset; if (s->nb_snapshots >= QCOW_MAX_SNAPSHOTS) { return -EFBIG; } 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); sn->disk_size = bs->total_sectors * BDRV_SECTOR_SIZE; 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; /* Allocate the L1 table of the snapshot and copy the current one there. */ l1_table_offset = qcow2_alloc_clusters(bs, s->l1_size * sizeof(uint64_t)); if (l1_table_offset < 0) { ret = l1_table_offset; goto fail; } sn->l1_table_offset = l1_table_offset; sn->l1_size = s->l1_size; l1_table = g_try_new(uint64_t, s->l1_size); if (s->l1_size && l1_table == NULL) { ret = -ENOMEM; goto fail; } for(i = 0; i < s->l1_size; i++) { l1_table[i] = cpu_to_be64(s->l1_table[i]); } ret = qcow2_pre_write_overlap_check(bs, 0, sn->l1_table_offset, s->l1_size * sizeof(uint64_t)); if (ret < 0) { goto fail; } ret = bdrv_pwrite(bs->file->bs, sn->l1_table_offset, l1_table, s->l1_size * sizeof(uint64_t)); if (ret < 0) { goto fail; } g_free(l1_table); l1_table = NULL; /* * 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; } /* Append the new snapshot to the snapshot list */ new_snapshot_list = g_new(QCowSnapshot, s->nb_snapshots + 1); if (s->snapshots) { memcpy(new_snapshot_list, s->snapshots, s->nb_snapshots * sizeof(QCowSnapshot)); old_snapshot_list = s->snapshots; } s->snapshots = new_snapshot_list; s->snapshots[s->nb_snapshots++] = *sn; ret = qcow2_write_snapshots(bs); if (ret < 0) { g_free(s->snapshots); s->snapshots = old_snapshot_list; s->nb_snapshots--; goto fail; } g_free(old_snapshot_list); /* 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); #ifdef DEBUG_ALLOC { BdrvCheckResult result = {0}; qcow2_check_refcounts(bs, &result, 0); } #endif return 0; fail: g_free(sn->id_str); g_free(sn->name); g_free(l1_table); return ret; }
/* add at the end of the file a new list of snapshots */ static int qcow2_write_snapshots(BlockDriverState *bs) { BDRVQcowState *s = bs->opaque; QCowSnapshot *sn; QCowSnapshotHeader h; QCowSnapshotExtraData extra; int i, name_size, id_str_size, snapshots_size; struct { uint32_t nb_snapshots; uint64_t snapshots_offset; } QEMU_PACKED header_data; int64_t offset, snapshots_offset; int ret; /* 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 += sizeof(extra); offset += strlen(sn->id_str); offset += strlen(sn->name); } snapshots_size = offset; /* Allocate space for the new snapshot list */ snapshots_offset = qcow2_alloc_clusters(bs, snapshots_size); offset = snapshots_offset; if (offset < 0) { return offset; } ret = bdrv_flush(bs); if (ret < 0) { return ret; } /* The snapshot list position has not yet been updated, so these clusters * must indeed be completely free */ ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT, offset, s->snapshots_size); if (ret < 0) { return ret; } /* Write all snapshots to the new list */ 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); /* 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); } 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); 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); extra.disk_size = cpu_to_be64(sn->disk_size); 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); ret = bdrv_pwrite(bs->file, offset, &h, sizeof(h)); if (ret < 0) { goto fail; } offset += sizeof(h); ret = bdrv_pwrite(bs->file, offset, &extra, sizeof(extra)); if (ret < 0) { goto fail; } offset += sizeof(extra); 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, offset, sn->name, name_size); if (ret < 0) { goto fail; } offset += name_size; } /* * 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; } 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); ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, nb_snapshots), &header_data, sizeof(header_data)); if (ret < 0) { goto fail; } /* free the old snapshot table */ qcow2_free_clusters(bs, s->snapshots_offset, s->snapshots_size, QCOW2_DISCARD_SNAPSHOT); s->snapshots_offset = snapshots_offset; s->snapshots_size = snapshots_size; return 0; fail: return ret; }
/* if no id is provided, a new one is constructed */ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) { BDRVQcowState *s = bs->opaque; QCowSnapshot *new_snapshot_list = NULL; QCowSnapshot *old_snapshot_list = NULL; QCowSnapshot sn1, *sn = &sn1; int i, ret; uint64_t *l1_table = NULL; int64_t l1_table_offset; memset(sn, 0, sizeof(*sn)); /* Generate an ID if it wasn't passed */ if (sn_info->id_str[0] == '\0') { 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 -EEXIST; } /* Populate sn with passed data */ sn->id_str = g_strdup(sn_info->id_str); sn->name = g_strdup(sn_info->name); sn->disk_size = bs->total_sectors * BDRV_SECTOR_SIZE; 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; /* Allocate the L1 table of the snapshot and copy the current one there. */ l1_table_offset = qcow2_alloc_clusters(bs, s->l1_size * sizeof(uint64_t)); if (l1_table_offset < 0) { ret = l1_table_offset; goto fail; } sn->l1_table_offset = l1_table_offset; sn->l1_size = s->l1_size; l1_table = g_malloc(s->l1_size * sizeof(uint64_t)); for(i = 0; i < s->l1_size; i++) { l1_table[i] = cpu_to_be64(s->l1_table[i]); } ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT, sn->l1_table_offset, s->l1_size * sizeof(uint64_t)); if (ret < 0) { goto fail; } ret = bdrv_pwrite(bs->file, sn->l1_table_offset, l1_table, s->l1_size * sizeof(uint64_t)); if (ret < 0) { goto fail; } g_free(l1_table); l1_table = NULL; /* * 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; } /* Append the new snapshot to the snapshot list */ new_snapshot_list = g_malloc((s->nb_snapshots + 1) * sizeof(QCowSnapshot)); if (s->snapshots) { memcpy(new_snapshot_list, s->snapshots, s->nb_snapshots * sizeof(QCowSnapshot)); old_snapshot_list = s->snapshots; } s->snapshots = new_snapshot_list; s->snapshots[s->nb_snapshots++] = *sn; ret = qcow2_write_snapshots(bs); if (ret < 0) { g_free(s->snapshots); s->snapshots = old_snapshot_list; goto fail; } g_free(old_snapshot_list); #ifdef DEBUG_ALLOC { BdrvCheckResult result = {0}; qcow2_check_refcounts(bs, &result, 0); } #endif return 0; fail: g_free(sn->id_str); g_free(sn->name); g_free(l1_table); return ret; }