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:
Kevin Wolf 2016-06-01 16:55:05 +02:00
parent 8556739355
commit d46a0bb24d
4 changed files with 52 additions and 59 deletions

View file

@ -1265,7 +1265,8 @@ fail:
* Return 0 on success and -errno in error cases * Return 0 on success and -errno in error cases
*/ */
int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t 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)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
uint64_t start, remaining; uint64_t start, remaining;
@ -1273,13 +1274,11 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
uint64_t cur_bytes; uint64_t cur_bytes;
int ret; int ret;
trace_qcow2_alloc_clusters_offset(qemu_coroutine_self(), offset, *num); trace_qcow2_alloc_clusters_offset(qemu_coroutine_self(), offset, *bytes);
assert((offset & ~BDRV_SECTOR_MASK) == 0);
again: again:
start = offset; start = offset;
remaining = (uint64_t)*num << BDRV_SECTOR_BITS; remaining = *bytes;
cluster_offset = 0; cluster_offset = 0;
*host_offset = 0; *host_offset = 0;
cur_bytes = 0; cur_bytes = 0;
@ -1365,8 +1364,8 @@ again:
} }
} }
*num -= remaining >> BDRV_SECTOR_BITS; *bytes -= remaining;
assert(*num > 0); assert(*bytes > 0);
assert(*host_offset != 0); assert(*host_offset != 0);
return 0; return 0;

View file

@ -1544,23 +1544,21 @@ fail:
return ret; return ret;
} }
static coroutine_fn int qcow2_co_writev(BlockDriverState *bs, static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset,
int64_t sector_num, uint64_t bytes, QEMUIOVector *qiov,
int remaining_sectors, int flags)
QEMUIOVector *qiov)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int index_in_cluster; int offset_in_cluster;
int ret; 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; uint64_t cluster_offset;
QEMUIOVector hd_qiov; QEMUIOVector hd_qiov;
uint64_t bytes_done = 0; uint64_t bytes_done = 0;
uint8_t *cluster_data = NULL; uint8_t *cluster_data = NULL;
QCowL2Meta *l2meta = NULL; QCowL2Meta *l2meta = NULL;
trace_qcow2_writev_start_req(qemu_coroutine_self(), sector_num, trace_qcow2_writev_start_req(qemu_coroutine_self(), offset, bytes);
remaining_sectors);
qemu_iovec_init(&hd_qiov, qiov->niov); 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); qemu_co_mutex_lock(&s->lock);
while (remaining_sectors != 0) { while (bytes != 0) {
l2meta = NULL; l2meta = NULL;
trace_qcow2_writev_start_part(qemu_coroutine_self()); trace_qcow2_writev_start_part(qemu_coroutine_self());
index_in_cluster = sector_num & (s->cluster_sectors - 1); offset_in_cluster = offset_into_cluster(s, offset);
cur_nr_sectors = remaining_sectors; cur_bytes = MIN(bytes, INT_MAX);
if (bs->encrypted && if (bs->encrypted) {
cur_nr_sectors > cur_bytes = MIN(cur_bytes,
QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors - index_in_cluster) { QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size
cur_nr_sectors = - offset_in_cluster);
QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors - index_in_cluster;
} }
ret = qcow2_alloc_cluster_offset(bs, sector_num << 9, ret = qcow2_alloc_cluster_offset(bs, offset, &cur_bytes,
&cur_nr_sectors, &cluster_offset, &l2meta); &cluster_offset, &l2meta);
if (ret < 0) { if (ret < 0) {
goto fail; goto fail;
} }
@ -1591,8 +1588,7 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
assert((cluster_offset & 511) == 0); assert((cluster_offset & 511) == 0);
qemu_iovec_reset(&hd_qiov); qemu_iovec_reset(&hd_qiov);
qemu_iovec_concat(&hd_qiov, qiov, bytes_done, qemu_iovec_concat(&hd_qiov, qiov, bytes_done, cur_bytes);
cur_nr_sectors * 512);
if (bs->encrypted) { if (bs->encrypted) {
Error *err = NULL; Error *err = NULL;
@ -1611,8 +1607,9 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size); QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size);
qemu_iovec_to_buf(&hd_qiov, 0, cluster_data, hd_qiov.size); qemu_iovec_to_buf(&hd_qiov, 0, cluster_data, hd_qiov.size);
if (qcow2_encrypt_sectors(s, sector_num, cluster_data, if (qcow2_encrypt_sectors(s, offset >> BDRV_SECTOR_BITS,
cluster_data, cur_nr_sectors, cluster_data, cluster_data,
cur_bytes >>BDRV_SECTOR_BITS,
true, &err) < 0) { true, &err) < 0) {
error_free(err); error_free(err);
ret = -EIO; ret = -EIO;
@ -1620,13 +1617,11 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
} }
qemu_iovec_reset(&hd_qiov); qemu_iovec_reset(&hd_qiov);
qemu_iovec_add(&hd_qiov, cluster_data, qemu_iovec_add(&hd_qiov, cluster_data, cur_bytes);
cur_nr_sectors * 512);
} }
ret = qcow2_pre_write_overlap_check(bs, 0, ret = qcow2_pre_write_overlap_check(bs, 0,
cluster_offset + index_in_cluster * BDRV_SECTOR_SIZE, cluster_offset + offset_in_cluster, cur_bytes);
cur_nr_sectors * BDRV_SECTOR_SIZE);
if (ret < 0) { if (ret < 0) {
goto fail; goto fail;
} }
@ -1634,10 +1629,10 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
qemu_co_mutex_unlock(&s->lock); qemu_co_mutex_unlock(&s->lock);
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO); BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
trace_qcow2_writev_data(qemu_coroutine_self(), trace_qcow2_writev_data(qemu_coroutine_self(),
(cluster_offset >> 9) + index_in_cluster); cluster_offset + offset_in_cluster);
ret = bdrv_co_writev(bs->file->bs, ret = bdrv_co_pwritev(bs->file->bs,
(cluster_offset >> 9) + index_in_cluster, cluster_offset + offset_in_cluster,
cur_nr_sectors, &hd_qiov); cur_bytes, &hd_qiov, 0);
qemu_co_mutex_lock(&s->lock); qemu_co_mutex_lock(&s->lock);
if (ret < 0) { if (ret < 0) {
goto fail; goto fail;
@ -1663,10 +1658,10 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
l2meta = next; l2meta = next;
} }
remaining_sectors -= cur_nr_sectors; bytes -= cur_bytes;
sector_num += cur_nr_sectors; offset += cur_bytes;
bytes_done += cur_nr_sectors * 512; bytes_done += cur_bytes;
trace_qcow2_writev_done_part(qemu_coroutine_self(), cur_nr_sectors); trace_qcow2_writev_done_part(qemu_coroutine_self(), cur_bytes);
} }
ret = 0; ret = 0;
@ -2008,19 +2003,19 @@ static int qcow2_change_backing_file(BlockDriverState *bs,
static int preallocate(BlockDriverState *bs) static int preallocate(BlockDriverState *bs)
{ {
uint64_t nb_sectors; uint64_t bytes;
uint64_t offset; uint64_t offset;
uint64_t host_offset = 0; uint64_t host_offset = 0;
int num; unsigned int cur_bytes;
int ret; int ret;
QCowL2Meta *meta; QCowL2Meta *meta;
nb_sectors = bdrv_nb_sectors(bs); bytes = bdrv_getlength(bs);
offset = 0; offset = 0;
while (nb_sectors) { while (bytes) {
num = MIN(nb_sectors, INT_MAX >> BDRV_SECTOR_BITS); cur_bytes = MIN(bytes, INT_MAX);
ret = qcow2_alloc_cluster_offset(bs, offset, &num, ret = qcow2_alloc_cluster_offset(bs, offset, &cur_bytes,
&host_offset, &meta); &host_offset, &meta);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
@ -2046,8 +2041,8 @@ static int preallocate(BlockDriverState *bs)
/* TODO Preallocate data if requested */ /* TODO Preallocate data if requested */
nb_sectors -= num; bytes -= cur_bytes;
offset += num << BDRV_SECTOR_BITS; offset += cur_bytes;
} }
/* /*
@ -2056,11 +2051,9 @@ static int preallocate(BlockDriverState *bs)
* EOF). Extend the image to the last allocated sector. * EOF). Extend the image to the last allocated sector.
*/ */
if (host_offset != 0) { if (host_offset != 0) {
uint8_t buf[BDRV_SECTOR_SIZE]; uint8_t data = 0;
memset(buf, 0, BDRV_SECTOR_SIZE); ret = bdrv_pwrite(bs->file->bs, (host_offset + cur_bytes) - 1,
ret = bdrv_write(bs->file->bs, &data, 1);
(host_offset >> BDRV_SECTOR_BITS) + num - 1,
buf, 1);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
@ -3379,7 +3372,7 @@ BlockDriver bdrv_qcow2 = {
.bdrv_set_key = qcow2_set_key, .bdrv_set_key = qcow2_set_key,
.bdrv_co_preadv = qcow2_co_preadv, .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_flush_to_os = qcow2_co_flush_to_os,
.bdrv_co_pwrite_zeroes = qcow2_co_pwrite_zeroes, .bdrv_co_pwrite_zeroes = qcow2_co_pwrite_zeroes,

View file

@ -539,7 +539,8 @@ int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num,
int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset, int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
unsigned int *bytes, uint64_t *cluster_offset); unsigned int *bytes, uint64_t *cluster_offset);
int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t 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 qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
uint64_t offset, uint64_t offset,
int compressed_size); int compressed_size);

View file

@ -606,16 +606,16 @@ qemu_system_shutdown_request(void) ""
qemu_system_powerdown_request(void) "" qemu_system_powerdown_request(void) ""
# block/qcow2.c # 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_done_req(void *co, int ret) "co %p ret %d"
qcow2_writev_start_part(void *co) "co %p" 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_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_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" qcow2_pwrite_zeroes(void *co, int64_t offset, int count) "co %p offset %" PRIx64 " count %d"
# block/qcow2-cluster.c # 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_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_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" 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"