qcow2: Implement .bdrv_co_pwritev()
This changes qcow2 to implement the byte-based .bdrv_co_pwritev interface rather than the sector-based old one. As preallocation uses the same allocation function as normal writes, and the interface of that function needs to be changed, it is converted in the same patch. Signed-off-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com>
This commit is contained in:
parent
8556739355
commit
d46a0bb24d
@ -1265,7 +1265,8 @@ fail:
|
||||
* Return 0 on success and -errno in error cases
|
||||
*/
|
||||
int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||
int *num, uint64_t *host_offset, QCowL2Meta **m)
|
||||
unsigned int *bytes, uint64_t *host_offset,
|
||||
QCowL2Meta **m)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
uint64_t start, remaining;
|
||||
@ -1273,13 +1274,11 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t cur_bytes;
|
||||
int ret;
|
||||
|
||||
trace_qcow2_alloc_clusters_offset(qemu_coroutine_self(), offset, *num);
|
||||
|
||||
assert((offset & ~BDRV_SECTOR_MASK) == 0);
|
||||
trace_qcow2_alloc_clusters_offset(qemu_coroutine_self(), offset, *bytes);
|
||||
|
||||
again:
|
||||
start = offset;
|
||||
remaining = (uint64_t)*num << BDRV_SECTOR_BITS;
|
||||
remaining = *bytes;
|
||||
cluster_offset = 0;
|
||||
*host_offset = 0;
|
||||
cur_bytes = 0;
|
||||
@ -1365,8 +1364,8 @@ again:
|
||||
}
|
||||
}
|
||||
|
||||
*num -= remaining >> BDRV_SECTOR_BITS;
|
||||
assert(*num > 0);
|
||||
*bytes -= remaining;
|
||||
assert(*bytes > 0);
|
||||
assert(*host_offset != 0);
|
||||
|
||||
return 0;
|
||||
|
@ -1544,23 +1544,21 @@ fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
int remaining_sectors,
|
||||
QEMUIOVector *qiov)
|
||||
static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t bytes, QEMUIOVector *qiov,
|
||||
int flags)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
int index_in_cluster;
|
||||
int offset_in_cluster;
|
||||
int ret;
|
||||
int cur_nr_sectors; /* number of sectors in current iteration */
|
||||
unsigned int cur_bytes; /* number of sectors in current iteration */
|
||||
uint64_t cluster_offset;
|
||||
QEMUIOVector hd_qiov;
|
||||
uint64_t bytes_done = 0;
|
||||
uint8_t *cluster_data = NULL;
|
||||
QCowL2Meta *l2meta = NULL;
|
||||
|
||||
trace_qcow2_writev_start_req(qemu_coroutine_self(), sector_num,
|
||||
remaining_sectors);
|
||||
trace_qcow2_writev_start_req(qemu_coroutine_self(), offset, bytes);
|
||||
|
||||
qemu_iovec_init(&hd_qiov, qiov->niov);
|
||||
|
||||
@ -1568,22 +1566,21 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
|
||||
|
||||
qemu_co_mutex_lock(&s->lock);
|
||||
|
||||
while (remaining_sectors != 0) {
|
||||
while (bytes != 0) {
|
||||
|
||||
l2meta = NULL;
|
||||
|
||||
trace_qcow2_writev_start_part(qemu_coroutine_self());
|
||||
index_in_cluster = sector_num & (s->cluster_sectors - 1);
|
||||
cur_nr_sectors = remaining_sectors;
|
||||
if (bs->encrypted &&
|
||||
cur_nr_sectors >
|
||||
QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors - index_in_cluster) {
|
||||
cur_nr_sectors =
|
||||
QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors - index_in_cluster;
|
||||
offset_in_cluster = offset_into_cluster(s, offset);
|
||||
cur_bytes = MIN(bytes, INT_MAX);
|
||||
if (bs->encrypted) {
|
||||
cur_bytes = MIN(cur_bytes,
|
||||
QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size
|
||||
- offset_in_cluster);
|
||||
}
|
||||
|
||||
ret = qcow2_alloc_cluster_offset(bs, sector_num << 9,
|
||||
&cur_nr_sectors, &cluster_offset, &l2meta);
|
||||
ret = qcow2_alloc_cluster_offset(bs, offset, &cur_bytes,
|
||||
&cluster_offset, &l2meta);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
@ -1591,8 +1588,7 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
|
||||
assert((cluster_offset & 511) == 0);
|
||||
|
||||
qemu_iovec_reset(&hd_qiov);
|
||||
qemu_iovec_concat(&hd_qiov, qiov, bytes_done,
|
||||
cur_nr_sectors * 512);
|
||||
qemu_iovec_concat(&hd_qiov, qiov, bytes_done, cur_bytes);
|
||||
|
||||
if (bs->encrypted) {
|
||||
Error *err = NULL;
|
||||
@ -1611,8 +1607,9 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
|
||||
QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size);
|
||||
qemu_iovec_to_buf(&hd_qiov, 0, cluster_data, hd_qiov.size);
|
||||
|
||||
if (qcow2_encrypt_sectors(s, sector_num, cluster_data,
|
||||
cluster_data, cur_nr_sectors,
|
||||
if (qcow2_encrypt_sectors(s, offset >> BDRV_SECTOR_BITS,
|
||||
cluster_data, cluster_data,
|
||||
cur_bytes >>BDRV_SECTOR_BITS,
|
||||
true, &err) < 0) {
|
||||
error_free(err);
|
||||
ret = -EIO;
|
||||
@ -1620,13 +1617,11 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
qemu_iovec_reset(&hd_qiov);
|
||||
qemu_iovec_add(&hd_qiov, cluster_data,
|
||||
cur_nr_sectors * 512);
|
||||
qemu_iovec_add(&hd_qiov, cluster_data, cur_bytes);
|
||||
}
|
||||
|
||||
ret = qcow2_pre_write_overlap_check(bs, 0,
|
||||
cluster_offset + index_in_cluster * BDRV_SECTOR_SIZE,
|
||||
cur_nr_sectors * BDRV_SECTOR_SIZE);
|
||||
cluster_offset + offset_in_cluster, cur_bytes);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
@ -1634,10 +1629,10 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
|
||||
qemu_co_mutex_unlock(&s->lock);
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
|
||||
trace_qcow2_writev_data(qemu_coroutine_self(),
|
||||
(cluster_offset >> 9) + index_in_cluster);
|
||||
ret = bdrv_co_writev(bs->file->bs,
|
||||
(cluster_offset >> 9) + index_in_cluster,
|
||||
cur_nr_sectors, &hd_qiov);
|
||||
cluster_offset + offset_in_cluster);
|
||||
ret = bdrv_co_pwritev(bs->file->bs,
|
||||
cluster_offset + offset_in_cluster,
|
||||
cur_bytes, &hd_qiov, 0);
|
||||
qemu_co_mutex_lock(&s->lock);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
@ -1663,10 +1658,10 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
|
||||
l2meta = next;
|
||||
}
|
||||
|
||||
remaining_sectors -= cur_nr_sectors;
|
||||
sector_num += cur_nr_sectors;
|
||||
bytes_done += cur_nr_sectors * 512;
|
||||
trace_qcow2_writev_done_part(qemu_coroutine_self(), cur_nr_sectors);
|
||||
bytes -= cur_bytes;
|
||||
offset += cur_bytes;
|
||||
bytes_done += cur_bytes;
|
||||
trace_qcow2_writev_done_part(qemu_coroutine_self(), cur_bytes);
|
||||
}
|
||||
ret = 0;
|
||||
|
||||
@ -2008,19 +2003,19 @@ static int qcow2_change_backing_file(BlockDriverState *bs,
|
||||
|
||||
static int preallocate(BlockDriverState *bs)
|
||||
{
|
||||
uint64_t nb_sectors;
|
||||
uint64_t bytes;
|
||||
uint64_t offset;
|
||||
uint64_t host_offset = 0;
|
||||
int num;
|
||||
unsigned int cur_bytes;
|
||||
int ret;
|
||||
QCowL2Meta *meta;
|
||||
|
||||
nb_sectors = bdrv_nb_sectors(bs);
|
||||
bytes = bdrv_getlength(bs);
|
||||
offset = 0;
|
||||
|
||||
while (nb_sectors) {
|
||||
num = MIN(nb_sectors, INT_MAX >> BDRV_SECTOR_BITS);
|
||||
ret = qcow2_alloc_cluster_offset(bs, offset, &num,
|
||||
while (bytes) {
|
||||
cur_bytes = MIN(bytes, INT_MAX);
|
||||
ret = qcow2_alloc_cluster_offset(bs, offset, &cur_bytes,
|
||||
&host_offset, &meta);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
@ -2046,8 +2041,8 @@ static int preallocate(BlockDriverState *bs)
|
||||
|
||||
/* TODO Preallocate data if requested */
|
||||
|
||||
nb_sectors -= num;
|
||||
offset += num << BDRV_SECTOR_BITS;
|
||||
bytes -= cur_bytes;
|
||||
offset += cur_bytes;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2056,11 +2051,9 @@ static int preallocate(BlockDriverState *bs)
|
||||
* EOF). Extend the image to the last allocated sector.
|
||||
*/
|
||||
if (host_offset != 0) {
|
||||
uint8_t buf[BDRV_SECTOR_SIZE];
|
||||
memset(buf, 0, BDRV_SECTOR_SIZE);
|
||||
ret = bdrv_write(bs->file->bs,
|
||||
(host_offset >> BDRV_SECTOR_BITS) + num - 1,
|
||||
buf, 1);
|
||||
uint8_t data = 0;
|
||||
ret = bdrv_pwrite(bs->file->bs, (host_offset + cur_bytes) - 1,
|
||||
&data, 1);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
@ -3379,7 +3372,7 @@ BlockDriver bdrv_qcow2 = {
|
||||
.bdrv_set_key = qcow2_set_key,
|
||||
|
||||
.bdrv_co_preadv = qcow2_co_preadv,
|
||||
.bdrv_co_writev = qcow2_co_writev,
|
||||
.bdrv_co_pwritev = qcow2_co_pwritev,
|
||||
.bdrv_co_flush_to_os = qcow2_co_flush_to_os,
|
||||
|
||||
.bdrv_co_pwrite_zeroes = qcow2_co_pwrite_zeroes,
|
||||
|
@ -539,7 +539,8 @@ int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num,
|
||||
int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||
unsigned int *bytes, uint64_t *cluster_offset);
|
||||
int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||
int *num, uint64_t *host_offset, QCowL2Meta **m);
|
||||
unsigned int *bytes, uint64_t *host_offset,
|
||||
QCowL2Meta **m);
|
||||
uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
|
||||
uint64_t offset,
|
||||
int compressed_size);
|
||||
|
@ -606,16 +606,16 @@ qemu_system_shutdown_request(void) ""
|
||||
qemu_system_powerdown_request(void) ""
|
||||
|
||||
# block/qcow2.c
|
||||
qcow2_writev_start_req(void *co, int64_t sector, int nb_sectors) "co %p sector %" PRIx64 " nb_sectors %d"
|
||||
qcow2_writev_start_req(void *co, int64_t offset, int bytes) "co %p offset %" PRIx64 " bytes %d"
|
||||
qcow2_writev_done_req(void *co, int ret) "co %p ret %d"
|
||||
qcow2_writev_start_part(void *co) "co %p"
|
||||
qcow2_writev_done_part(void *co, int cur_nr_sectors) "co %p cur_nr_sectors %d"
|
||||
qcow2_writev_done_part(void *co, int cur_bytes) "co %p cur_bytes %d"
|
||||
qcow2_writev_data(void *co, uint64_t offset) "co %p offset %" PRIx64
|
||||
qcow2_pwrite_zeroes_start_req(void *co, int64_t offset, int count) "co %p offset %" PRIx64 " count %d"
|
||||
qcow2_pwrite_zeroes(void *co, int64_t offset, int count) "co %p offset %" PRIx64 " count %d"
|
||||
|
||||
# block/qcow2-cluster.c
|
||||
qcow2_alloc_clusters_offset(void *co, uint64_t offset, int num) "co %p offset %" PRIx64 " num %d"
|
||||
qcow2_alloc_clusters_offset(void *co, uint64_t offset, int bytes) "co %p offset %" PRIx64 " bytes %d"
|
||||
qcow2_handle_copied(void *co, uint64_t guest_offset, uint64_t host_offset, uint64_t bytes) "co %p guest_offset %" PRIx64 " host_offset %" PRIx64 " bytes %" PRIx64
|
||||
qcow2_handle_alloc(void *co, uint64_t guest_offset, uint64_t host_offset, uint64_t bytes) "co %p guest_offset %" PRIx64 " host_offset %" PRIx64 " bytes %" PRIx64
|
||||
qcow2_do_alloc_clusters_offset(void *co, uint64_t guest_offset, uint64_t host_offset, int nb_clusters) "co %p guest_offset %" PRIx64 " host_offset %" PRIx64 " nb_clusters %d"
|
||||
|
Loading…
Reference in New Issue
Block a user