mirror of https://github.com/xemu-project/xemu.git
block/qcow2: implement .bdrv_co_pwritev(_compressed)_part
Implement and use new interface to get rid of hd_qiov. Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> Acked-by: Stefan Hajnoczi <stefanha@redhat.com> Message-id: 20190604161514.262241-13-vsementsov@virtuozzo.com Message-Id: <20190604161514.262241-13-vsementsov@virtuozzo.com> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
parent
df893d25ce
commit
5396234b96
|
@ -829,7 +829,6 @@ static int perform_cow(BlockDriverState *bs, QCowL2Meta *m)
|
||||||
assert(start->nb_bytes <= UINT_MAX - end->nb_bytes);
|
assert(start->nb_bytes <= UINT_MAX - end->nb_bytes);
|
||||||
assert(start->nb_bytes + end->nb_bytes <= UINT_MAX - data_bytes);
|
assert(start->nb_bytes + end->nb_bytes <= UINT_MAX - data_bytes);
|
||||||
assert(start->offset + start->nb_bytes <= end->offset);
|
assert(start->offset + start->nb_bytes <= end->offset);
|
||||||
assert(!m->data_qiov || m->data_qiov->size == data_bytes);
|
|
||||||
|
|
||||||
if ((start->nb_bytes == 0 && end->nb_bytes == 0) || m->skip_cow) {
|
if ((start->nb_bytes == 0 && end->nb_bytes == 0) || m->skip_cow) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -861,7 +860,11 @@ static int perform_cow(BlockDriverState *bs, QCowL2Meta *m)
|
||||||
/* The part of the buffer where the end region is located */
|
/* The part of the buffer where the end region is located */
|
||||||
end_buffer = start_buffer + buffer_size - end->nb_bytes;
|
end_buffer = start_buffer + buffer_size - end->nb_bytes;
|
||||||
|
|
||||||
qemu_iovec_init(&qiov, 2 + (m->data_qiov ? m->data_qiov->niov : 0));
|
qemu_iovec_init(&qiov, 2 + (m->data_qiov ?
|
||||||
|
qemu_iovec_subvec_niov(m->data_qiov,
|
||||||
|
m->data_qiov_offset,
|
||||||
|
data_bytes)
|
||||||
|
: 0));
|
||||||
|
|
||||||
qemu_co_mutex_unlock(&s->lock);
|
qemu_co_mutex_unlock(&s->lock);
|
||||||
/* First we read the existing data from both COW regions. We
|
/* First we read the existing data from both COW regions. We
|
||||||
|
@ -904,7 +907,7 @@ static int perform_cow(BlockDriverState *bs, QCowL2Meta *m)
|
||||||
if (start->nb_bytes) {
|
if (start->nb_bytes) {
|
||||||
qemu_iovec_add(&qiov, start_buffer, start->nb_bytes);
|
qemu_iovec_add(&qiov, start_buffer, start->nb_bytes);
|
||||||
}
|
}
|
||||||
qemu_iovec_concat(&qiov, m->data_qiov, 0, data_bytes);
|
qemu_iovec_concat(&qiov, m->data_qiov, m->data_qiov_offset, data_bytes);
|
||||||
if (end->nb_bytes) {
|
if (end->nb_bytes) {
|
||||||
qemu_iovec_add(&qiov, end_buffer, end->nb_bytes);
|
qemu_iovec_add(&qiov, end_buffer, end->nb_bytes);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2103,7 +2103,8 @@ fail:
|
||||||
/* Check if it's possible to merge a write request with the writing of
|
/* Check if it's possible to merge a write request with the writing of
|
||||||
* the data from the COW regions */
|
* the data from the COW regions */
|
||||||
static bool merge_cow(uint64_t offset, unsigned bytes,
|
static bool merge_cow(uint64_t offset, unsigned bytes,
|
||||||
QEMUIOVector *hd_qiov, QCowL2Meta *l2meta)
|
QEMUIOVector *qiov, size_t qiov_offset,
|
||||||
|
QCowL2Meta *l2meta)
|
||||||
{
|
{
|
||||||
QCowL2Meta *m;
|
QCowL2Meta *m;
|
||||||
|
|
||||||
|
@ -2132,11 +2133,12 @@ static bool merge_cow(uint64_t offset, unsigned bytes,
|
||||||
|
|
||||||
/* Make sure that adding both COW regions to the QEMUIOVector
|
/* Make sure that adding both COW regions to the QEMUIOVector
|
||||||
* does not exceed IOV_MAX */
|
* does not exceed IOV_MAX */
|
||||||
if (hd_qiov->niov > IOV_MAX - 2) {
|
if (qemu_iovec_subvec_niov(qiov, qiov_offset, bytes) > IOV_MAX - 2) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
m->data_qiov = hd_qiov;
|
m->data_qiov = qiov;
|
||||||
|
m->data_qiov_offset = qiov_offset;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2218,24 +2220,22 @@ static int handle_alloc_space(BlockDriverState *bs, QCowL2Meta *l2meta)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset,
|
static coroutine_fn int qcow2_co_pwritev_part(
|
||||||
uint64_t bytes, QEMUIOVector *qiov,
|
BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||||
int flags)
|
QEMUIOVector *qiov, size_t qiov_offset, int flags)
|
||||||
{
|
{
|
||||||
BDRVQcow2State *s = bs->opaque;
|
BDRVQcow2State *s = bs->opaque;
|
||||||
int offset_in_cluster;
|
int offset_in_cluster;
|
||||||
int ret;
|
int ret;
|
||||||
unsigned int cur_bytes; /* 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 encrypted_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(), offset, bytes);
|
trace_qcow2_writev_start_req(qemu_coroutine_self(), offset, bytes);
|
||||||
|
|
||||||
qemu_iovec_init(&hd_qiov, qiov->niov);
|
|
||||||
|
|
||||||
qemu_co_mutex_lock(&s->lock);
|
qemu_co_mutex_lock(&s->lock);
|
||||||
|
|
||||||
while (bytes != 0) {
|
while (bytes != 0) {
|
||||||
|
@ -2268,9 +2268,6 @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset,
|
||||||
|
|
||||||
qemu_co_mutex_unlock(&s->lock);
|
qemu_co_mutex_unlock(&s->lock);
|
||||||
|
|
||||||
qemu_iovec_reset(&hd_qiov);
|
|
||||||
qemu_iovec_concat(&hd_qiov, qiov, bytes_done, cur_bytes);
|
|
||||||
|
|
||||||
if (bs->encrypted) {
|
if (bs->encrypted) {
|
||||||
assert(s->crypto);
|
assert(s->crypto);
|
||||||
if (!cluster_data) {
|
if (!cluster_data) {
|
||||||
|
@ -2283,9 +2280,9 @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(hd_qiov.size <=
|
assert(cur_bytes <= QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size);
|
||||||
QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size);
|
qemu_iovec_to_buf(qiov, qiov_offset + bytes_done,
|
||||||
qemu_iovec_to_buf(&hd_qiov, 0, cluster_data, hd_qiov.size);
|
cluster_data, cur_bytes);
|
||||||
|
|
||||||
if (qcow2_co_encrypt(bs, cluster_offset, offset,
|
if (qcow2_co_encrypt(bs, cluster_offset, offset,
|
||||||
cluster_data, cur_bytes) < 0) {
|
cluster_data, cur_bytes) < 0) {
|
||||||
|
@ -2293,8 +2290,7 @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset,
|
||||||
goto out_unlocked;
|
goto out_unlocked;
|
||||||
}
|
}
|
||||||
|
|
||||||
qemu_iovec_reset(&hd_qiov);
|
qemu_iovec_init_buf(&encrypted_qiov, cluster_data, cur_bytes);
|
||||||
qemu_iovec_add(&hd_qiov, cluster_data, cur_bytes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try to efficiently initialize the physical space with zeroes */
|
/* Try to efficiently initialize the physical space with zeroes */
|
||||||
|
@ -2307,13 +2303,17 @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset,
|
||||||
* writing of the guest data together with that of the COW regions.
|
* writing of the guest data together with that of the COW regions.
|
||||||
* If it's not possible (or not necessary) then write the
|
* If it's not possible (or not necessary) then write the
|
||||||
* guest data now. */
|
* guest data now. */
|
||||||
if (!merge_cow(offset, cur_bytes, &hd_qiov, l2meta)) {
|
if (!merge_cow(offset, cur_bytes,
|
||||||
|
bs->encrypted ? &encrypted_qiov : qiov,
|
||||||
|
bs->encrypted ? 0 : qiov_offset + bytes_done, l2meta))
|
||||||
|
{
|
||||||
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 + offset_in_cluster);
|
cluster_offset + offset_in_cluster);
|
||||||
ret = bdrv_co_pwritev(s->data_file,
|
ret = bdrv_co_pwritev_part(
|
||||||
cluster_offset + offset_in_cluster,
|
s->data_file, cluster_offset + offset_in_cluster, cur_bytes,
|
||||||
cur_bytes, &hd_qiov, 0);
|
bs->encrypted ? &encrypted_qiov : qiov,
|
||||||
|
bs->encrypted ? 0 : qiov_offset + bytes_done, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto out_unlocked;
|
goto out_unlocked;
|
||||||
}
|
}
|
||||||
|
@ -2342,7 +2342,6 @@ out_locked:
|
||||||
|
|
||||||
qemu_co_mutex_unlock(&s->lock);
|
qemu_co_mutex_unlock(&s->lock);
|
||||||
|
|
||||||
qemu_iovec_destroy(&hd_qiov);
|
|
||||||
qemu_vfree(cluster_data);
|
qemu_vfree(cluster_data);
|
||||||
trace_qcow2_writev_done_req(qemu_coroutine_self(), ret);
|
trace_qcow2_writev_done_req(qemu_coroutine_self(), ret);
|
||||||
|
|
||||||
|
@ -4007,8 +4006,9 @@ fail:
|
||||||
/* XXX: put compressed sectors first, then all the cluster aligned
|
/* XXX: put compressed sectors first, then all the cluster aligned
|
||||||
tables to avoid losing bytes in alignment */
|
tables to avoid losing bytes in alignment */
|
||||||
static coroutine_fn int
|
static coroutine_fn int
|
||||||
qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
|
qcow2_co_pwritev_compressed_part(BlockDriverState *bs,
|
||||||
uint64_t bytes, QEMUIOVector *qiov)
|
uint64_t offset, uint64_t bytes,
|
||||||
|
QEMUIOVector *qiov, size_t qiov_offset)
|
||||||
{
|
{
|
||||||
BDRVQcow2State *s = bs->opaque;
|
BDRVQcow2State *s = bs->opaque;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -4045,7 +4045,7 @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
|
||||||
/* Zero-pad last write if image size is not cluster aligned */
|
/* Zero-pad last write if image size is not cluster aligned */
|
||||||
memset(buf + bytes, 0, s->cluster_size - bytes);
|
memset(buf + bytes, 0, s->cluster_size - bytes);
|
||||||
}
|
}
|
||||||
qemu_iovec_to_buf(qiov, 0, buf, bytes);
|
qemu_iovec_to_buf(qiov, qiov_offset, buf, bytes);
|
||||||
|
|
||||||
out_buf = g_malloc(s->cluster_size);
|
out_buf = g_malloc(s->cluster_size);
|
||||||
|
|
||||||
|
@ -4053,7 +4053,7 @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
|
||||||
buf, s->cluster_size);
|
buf, s->cluster_size);
|
||||||
if (out_len == -ENOMEM) {
|
if (out_len == -ENOMEM) {
|
||||||
/* could not compress: write normal cluster */
|
/* could not compress: write normal cluster */
|
||||||
ret = qcow2_co_pwritev(bs, offset, bytes, qiov, 0);
|
ret = qcow2_co_pwritev_part(bs, offset, bytes, qiov, qiov_offset, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
@ -4664,8 +4664,8 @@ static int qcow2_save_vmstate(BlockDriverState *bs, QEMUIOVector *qiov,
|
||||||
BDRVQcow2State *s = bs->opaque;
|
BDRVQcow2State *s = bs->opaque;
|
||||||
|
|
||||||
BLKDBG_EVENT(bs->file, BLKDBG_VMSTATE_SAVE);
|
BLKDBG_EVENT(bs->file, BLKDBG_VMSTATE_SAVE);
|
||||||
return bs->drv->bdrv_co_pwritev(bs, qcow2_vm_state_offset(s) + pos,
|
return bs->drv->bdrv_co_pwritev_part(bs, qcow2_vm_state_offset(s) + pos,
|
||||||
qiov->size, qiov, 0);
|
qiov->size, qiov, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int qcow2_load_vmstate(BlockDriverState *bs, QEMUIOVector *qiov,
|
static int qcow2_load_vmstate(BlockDriverState *bs, QEMUIOVector *qiov,
|
||||||
|
@ -5218,7 +5218,7 @@ BlockDriver bdrv_qcow2 = {
|
||||||
.bdrv_co_block_status = qcow2_co_block_status,
|
.bdrv_co_block_status = qcow2_co_block_status,
|
||||||
|
|
||||||
.bdrv_co_preadv_part = qcow2_co_preadv_part,
|
.bdrv_co_preadv_part = qcow2_co_preadv_part,
|
||||||
.bdrv_co_pwritev = qcow2_co_pwritev,
|
.bdrv_co_pwritev_part = qcow2_co_pwritev_part,
|
||||||
.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,
|
||||||
|
@ -5226,7 +5226,7 @@ BlockDriver bdrv_qcow2 = {
|
||||||
.bdrv_co_copy_range_from = qcow2_co_copy_range_from,
|
.bdrv_co_copy_range_from = qcow2_co_copy_range_from,
|
||||||
.bdrv_co_copy_range_to = qcow2_co_copy_range_to,
|
.bdrv_co_copy_range_to = qcow2_co_copy_range_to,
|
||||||
.bdrv_co_truncate = qcow2_co_truncate,
|
.bdrv_co_truncate = qcow2_co_truncate,
|
||||||
.bdrv_co_pwritev_compressed = qcow2_co_pwritev_compressed,
|
.bdrv_co_pwritev_compressed_part = qcow2_co_pwritev_compressed_part,
|
||||||
.bdrv_make_empty = qcow2_make_empty,
|
.bdrv_make_empty = qcow2_make_empty,
|
||||||
|
|
||||||
.bdrv_snapshot_create = qcow2_snapshot_create,
|
.bdrv_snapshot_create = qcow2_snapshot_create,
|
||||||
|
|
|
@ -420,6 +420,7 @@ typedef struct QCowL2Meta
|
||||||
* from @cow_start and @cow_end into one single write operation.
|
* from @cow_start and @cow_end into one single write operation.
|
||||||
*/
|
*/
|
||||||
QEMUIOVector *data_qiov;
|
QEMUIOVector *data_qiov;
|
||||||
|
size_t data_qiov_offset;
|
||||||
|
|
||||||
/** Pointer to next L2Meta of the same write request */
|
/** Pointer to next L2Meta of the same write request */
|
||||||
struct QCowL2Meta *next;
|
struct QCowL2Meta *next;
|
||||||
|
|
|
@ -206,6 +206,7 @@ void qemu_iovec_init_extended(
|
||||||
void *tail_buf, size_t tail_len);
|
void *tail_buf, size_t tail_len);
|
||||||
void qemu_iovec_init_slice(QEMUIOVector *qiov, QEMUIOVector *source,
|
void qemu_iovec_init_slice(QEMUIOVector *qiov, QEMUIOVector *source,
|
||||||
size_t offset, size_t len);
|
size_t offset, size_t len);
|
||||||
|
int qemu_iovec_subvec_niov(QEMUIOVector *qiov, size_t offset, size_t len);
|
||||||
void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len);
|
void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len);
|
||||||
void qemu_iovec_concat(QEMUIOVector *dst,
|
void qemu_iovec_concat(QEMUIOVector *dst,
|
||||||
QEMUIOVector *src, size_t soffset, size_t sbytes);
|
QEMUIOVector *src, size_t soffset, size_t sbytes);
|
||||||
|
|
10
util/iov.c
10
util/iov.c
|
@ -401,6 +401,16 @@ static struct iovec *qiov_slice(QEMUIOVector *qiov,
|
||||||
return iov;
|
return iov;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int qemu_iovec_subvec_niov(QEMUIOVector *qiov, size_t offset, size_t len)
|
||||||
|
{
|
||||||
|
size_t head, tail;
|
||||||
|
int niov;
|
||||||
|
|
||||||
|
qiov_slice(qiov, offset, len, &head, &tail, &niov);
|
||||||
|
|
||||||
|
return niov;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compile new iovec, combining @head_buf buffer, sub-qiov of @mid_qiov,
|
* Compile new iovec, combining @head_buf buffer, sub-qiov of @mid_qiov,
|
||||||
* and @tail_buf buffer into new qiov.
|
* and @tail_buf buffer into new qiov.
|
||||||
|
|
Loading…
Reference in New Issue