static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,

                          int nb_sectors, QEMUIOVector *qiov)

{

    BDRVQcowState *s = bs->opaque;

    int index_in_cluster;

    uint64_t cluster_offset;

    int ret = 0, n;

    struct iovec hd_iov;

    QEMUIOVector hd_qiov;

    uint8_t *buf;

    void *orig_buf;



    s->cluster_cache_offset = -1; /* disable compressed cache */



    /* We must always copy the iov when encrypting, so we

     * don't modify the original data buffer during encryption */

    if (bs->encrypted || qiov->niov > 1) {

        buf = orig_buf = qemu_try_blockalign(bs, qiov->size);

        if (buf == NULL) {

            return -ENOMEM;

        }

        qemu_iovec_to_buf(qiov, 0, buf, qiov->size);

    } else {

        orig_buf = NULL;

        buf = (uint8_t *)qiov->iov->iov_base;

    }



    qemu_co_mutex_lock(&s->lock);



    while (nb_sectors != 0) {



        index_in_cluster = sector_num & (s->cluster_sectors - 1);

        n = s->cluster_sectors - index_in_cluster;

        if (n > nb_sectors) {

            n = nb_sectors;

        }

        cluster_offset = get_cluster_offset(bs, sector_num << 9, 1, 0,

                                            index_in_cluster,

                                            index_in_cluster + n);

        if (!cluster_offset || (cluster_offset & 511) != 0) {

            ret = -EIO;

            break;

        }

        if (bs->encrypted) {

            Error *err = NULL;

            assert(s->cipher);

            if (encrypt_sectors(s, sector_num, buf, n, true, &err) < 0) {

                error_free(err);

                ret = -EIO;

                break;

            }

        }



        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_writev(bs->file,

                             (cluster_offset >> 9) + index_in_cluster,

                             n, &hd_qiov);

        qemu_co_mutex_lock(&s->lock);

        if (ret < 0) {

            break;

        }

        ret = 0;



        nb_sectors -= n;

        sector_num += n;

        buf += n * 512;

    }

    qemu_co_mutex_unlock(&s->lock);



    qemu_vfree(orig_buf);



    return ret;

}
