static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num, int nb_sectors, QEMUIOVector *qiov) { BDRVQcowState *s = bs->opaque; int index_in_cluster; int ret = 0, n; uint64_t cluster_offset; struct iovec hd_iov; QEMUIOVector hd_qiov; uint8_t *buf; void *orig_buf; Error *err = NULL; if (qiov->niov > 1) { buf = orig_buf = qemu_try_blockalign(bs, qiov->size); if (buf == NULL) { return -ENOMEM; } } else { orig_buf = NULL; buf = (uint8_t *)qiov->iov->iov_base; } qemu_co_mutex_lock(&s->lock); while (nb_sectors != 0) { /* prepare next request */ cluster_offset = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0); index_in_cluster = sector_num & (s->cluster_sectors - 1); n = s->cluster_sectors - index_in_cluster; if (n > nb_sectors) { n = nb_sectors; } if (!cluster_offset) { if (bs->backing) { /* read from the base image */ hd_iov.iov_base = (void *)buf; hd_iov.iov_len = n * 512; qemu_iovec_init_external(&hd_qiov, &hd_iov, 1); qemu_co_mutex_unlock(&s->lock); ret = bdrv_co_readv(bs->backing, sector_num, n, &hd_qiov); qemu_co_mutex_lock(&s->lock); if (ret < 0) { goto fail; } } else { /* Note: in this case, no need to wait */ memset(buf, 0, 512 * n); } } else if (cluster_offset & QCOW_OFLAG_COMPRESSED) { /* add AIO support for compressed blocks ? */ if (decompress_cluster(bs, cluster_offset) < 0) { goto fail; } memcpy(buf, s->cluster_cache + index_in_cluster * 512, 512 * n); } else { if ((cluster_offset & 511) != 0) { goto fail; } hd_iov.iov_base = (void *)buf; hd_iov.iov_len = n * 512; qemu_iovec_init_external(&hd_qiov, &hd_iov, 1); qemu_co_mutex_unlock(&s->lock); ret = bdrv_co_readv(bs->file, (cluster_offset >> 9) + index_in_cluster, n, &hd_qiov); qemu_co_mutex_lock(&s->lock); if (ret < 0) { break; } if (bs->encrypted) { assert(s->cipher); if (encrypt_sectors(s, sector_num, buf, n, false, &err) < 0) { goto fail; } } } ret = 0; nb_sectors -= n; sector_num += n; buf += n * 512; } done: qemu_co_mutex_unlock(&s->lock); if (qiov->niov > 1) { qemu_iovec_from_buf(qiov, 0, orig_buf, qiov->size); qemu_vfree(orig_buf); } return ret; fail: error_free(err); ret = -EIO; goto done; }