|
@@ -4221,10 +4221,8 @@ fail:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-/* XXX: put compressed sectors first, then all the cluster aligned
|
|
|
- tables to avoid losing bytes in alignment */
|
|
|
static coroutine_fn int
|
|
|
-qcow2_co_pwritev_compressed_part(BlockDriverState *bs,
|
|
|
+qcow2_co_pwritev_compressed_task(BlockDriverState *bs,
|
|
|
uint64_t offset, uint64_t bytes,
|
|
|
QEMUIOVector *qiov, size_t qiov_offset)
|
|
|
{
|
|
@@ -4234,32 +4232,11 @@ qcow2_co_pwritev_compressed_part(BlockDriverState *bs,
|
|
|
uint8_t *buf, *out_buf;
|
|
|
uint64_t cluster_offset;
|
|
|
|
|
|
- if (has_data_file(bs)) {
|
|
|
- return -ENOTSUP;
|
|
|
- }
|
|
|
-
|
|
|
- if (bytes == 0) {
|
|
|
- /* align end of file to a sector boundary to ease reading with
|
|
|
- sector based I/Os */
|
|
|
- int64_t len = bdrv_getlength(bs->file->bs);
|
|
|
- if (len < 0) {
|
|
|
- return len;
|
|
|
- }
|
|
|
- return bdrv_co_truncate(bs->file, len, false, PREALLOC_MODE_OFF, NULL);
|
|
|
- }
|
|
|
-
|
|
|
- if (offset_into_cluster(s, offset)) {
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
+ assert(bytes == s->cluster_size || (bytes < s->cluster_size &&
|
|
|
+ (offset + bytes == bs->total_sectors << BDRV_SECTOR_BITS)));
|
|
|
|
|
|
buf = qemu_blockalign(bs, s->cluster_size);
|
|
|
- if (bytes != s->cluster_size) {
|
|
|
- if (bytes > s->cluster_size ||
|
|
|
- offset + bytes != bs->total_sectors << BDRV_SECTOR_BITS)
|
|
|
- {
|
|
|
- qemu_vfree(buf);
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
+ if (bytes < s->cluster_size) {
|
|
|
/* Zero-pad last write if image size is not cluster aligned */
|
|
|
memset(buf + bytes, 0, s->cluster_size - bytes);
|
|
|
}
|
|
@@ -4308,6 +4285,77 @@ fail:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static coroutine_fn int qcow2_co_pwritev_compressed_task_entry(AioTask *task)
|
|
|
+{
|
|
|
+ Qcow2AioTask *t = container_of(task, Qcow2AioTask, task);
|
|
|
+
|
|
|
+ assert(!t->cluster_type && !t->l2meta);
|
|
|
+
|
|
|
+ return qcow2_co_pwritev_compressed_task(t->bs, t->offset, t->bytes, t->qiov,
|
|
|
+ t->qiov_offset);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * XXX: put compressed sectors first, then all the cluster aligned
|
|
|
+ * tables to avoid losing bytes in alignment
|
|
|
+ */
|
|
|
+static coroutine_fn int
|
|
|
+qcow2_co_pwritev_compressed_part(BlockDriverState *bs,
|
|
|
+ uint64_t offset, uint64_t bytes,
|
|
|
+ QEMUIOVector *qiov, size_t qiov_offset)
|
|
|
+{
|
|
|
+ BDRVQcow2State *s = bs->opaque;
|
|
|
+ AioTaskPool *aio = NULL;
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ if (has_data_file(bs)) {
|
|
|
+ return -ENOTSUP;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (bytes == 0) {
|
|
|
+ /*
|
|
|
+ * align end of file to a sector boundary to ease reading with
|
|
|
+ * sector based I/Os
|
|
|
+ */
|
|
|
+ int64_t len = bdrv_getlength(bs->file->bs);
|
|
|
+ if (len < 0) {
|
|
|
+ return len;
|
|
|
+ }
|
|
|
+ return bdrv_co_truncate(bs->file, len, false, PREALLOC_MODE_OFF, NULL);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (offset_into_cluster(s, offset)) {
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ while (bytes && aio_task_pool_status(aio) == 0) {
|
|
|
+ uint64_t chunk_size = MIN(bytes, s->cluster_size);
|
|
|
+
|
|
|
+ if (!aio && chunk_size != bytes) {
|
|
|
+ aio = aio_task_pool_new(QCOW2_MAX_WORKERS);
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = qcow2_add_task(bs, aio, qcow2_co_pwritev_compressed_task_entry,
|
|
|
+ 0, 0, offset, chunk_size, qiov, qiov_offset, NULL);
|
|
|
+ if (ret < 0) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ qiov_offset += chunk_size;
|
|
|
+ offset += chunk_size;
|
|
|
+ bytes -= chunk_size;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (aio) {
|
|
|
+ aio_task_pool_wait_all(aio);
|
|
|
+ if (ret == 0) {
|
|
|
+ ret = aio_task_pool_status(aio);
|
|
|
+ }
|
|
|
+ g_free(aio);
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
static int coroutine_fn
|
|
|
qcow2_co_preadv_compressed(BlockDriverState *bs,
|
|
|
uint64_t file_cluster_offset,
|