diff options
Diffstat (limited to 'block')
-rw-r--r-- | block/qcow.c | 180 | ||||
-rw-r--r-- | block/qcow2-cluster.c | 26 | ||||
-rw-r--r-- | block/qcow2.c | 240 | ||||
-rw-r--r-- | block/qcow2.h | 5 | ||||
-rw-r--r-- | block/qed-table.c | 14 | ||||
-rw-r--r-- | block/qed.c | 4 | ||||
-rw-r--r-- | block/raw-posix.c | 39 | ||||
-rw-r--r-- | block/raw-win32.c | 35 | ||||
-rw-r--r-- | block/raw.c | 7 | ||||
-rw-r--r-- | block/vpc.c | 8 |
10 files changed, 188 insertions, 370 deletions
diff --git a/block/qcow.c b/block/qcow.c index 227b104e36..6447c2a1c0 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -73,6 +73,7 @@ typedef struct BDRVQcowState { uint32_t crypt_method_header; AES_KEY aes_encrypt_key; AES_KEY aes_decrypt_key; + CoMutex lock; } BDRVQcowState; static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset); @@ -517,11 +518,11 @@ static AIOPool qcow_aio_pool = { static QCowAIOCB *qcow_aio_setup(BlockDriverState *bs, int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, - BlockDriverCompletionFunc *cb, void *opaque, int is_write) + int is_write) { QCowAIOCB *acb; - acb = qemu_aio_get(&qcow_aio_pool, bs, cb, opaque); + acb = qemu_aio_get(&qcow_aio_pool, bs, NULL, NULL); if (!acb) return NULL; acb->hd_aiocb = NULL; @@ -542,48 +543,15 @@ static QCowAIOCB *qcow_aio_setup(BlockDriverState *bs, return acb; } -static void qcow_aio_read_cb(void *opaque, int ret); -static void qcow_aio_write_cb(void *opaque, int ret); - -static void qcow_aio_rw_bh(void *opaque) -{ - QCowAIOCB *acb = opaque; - qemu_bh_delete(acb->bh); - acb->bh = NULL; - - if (acb->is_write) { - qcow_aio_write_cb(opaque, 0); - } else { - qcow_aio_read_cb(opaque, 0); - } -} - -static int qcow_schedule_bh(QEMUBHFunc *cb, QCowAIOCB *acb) -{ - if (acb->bh) { - return -EIO; - } - - acb->bh = qemu_bh_new(cb, acb); - if (!acb->bh) { - return -EIO; - } - - qemu_bh_schedule(acb->bh); - - return 0; -} - -static void qcow_aio_read_cb(void *opaque, int ret) +static int qcow_aio_read_cb(void *opaque) { QCowAIOCB *acb = opaque; BlockDriverState *bs = acb->common.bs; BDRVQcowState *s = bs->opaque; int index_in_cluster; + int ret; acb->hd_aiocb = NULL; - if (ret < 0) - goto done; redo: /* post process the read buffer */ @@ -605,8 +573,7 @@ static void qcow_aio_read_cb(void *opaque, int ret) if (acb->nb_sectors == 0) { /* request completed */ - ret = 0; - goto done; + return 0; } /* prepare next AIO request */ @@ -623,11 +590,12 @@ static void qcow_aio_read_cb(void *opaque, int ret) acb->hd_iov.iov_base = (void *)acb->buf; acb->hd_iov.iov_len = acb->n * 512; qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1); - acb->hd_aiocb = bdrv_aio_readv(bs->backing_hd, acb->sector_num, - &acb->hd_qiov, acb->n, qcow_aio_read_cb, acb); - if (acb->hd_aiocb == NULL) { - ret = -EIO; - goto done; + qemu_co_mutex_unlock(&s->lock); + ret = bdrv_co_readv(bs->backing_hd, acb->sector_num, + acb->n, &acb->hd_qiov); + qemu_co_mutex_lock(&s->lock); + if (ret < 0) { + return -EIO; } } else { /* Note: in this case, no need to wait */ @@ -637,64 +605,56 @@ static void qcow_aio_read_cb(void *opaque, int ret) } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) { /* add AIO support for compressed blocks ? */ if (decompress_cluster(bs, acb->cluster_offset) < 0) { - ret = -EIO; - goto done; + return -EIO; } memcpy(acb->buf, s->cluster_cache + index_in_cluster * 512, 512 * acb->n); goto redo; } else { if ((acb->cluster_offset & 511) != 0) { - ret = -EIO; - goto done; + return -EIO; } acb->hd_iov.iov_base = (void *)acb->buf; acb->hd_iov.iov_len = acb->n * 512; qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1); - acb->hd_aiocb = bdrv_aio_readv(bs->file, + qemu_co_mutex_unlock(&s->lock); + ret = bdrv_co_readv(bs->file, (acb->cluster_offset >> 9) + index_in_cluster, - &acb->hd_qiov, acb->n, qcow_aio_read_cb, acb); - if (acb->hd_aiocb == NULL) { - ret = -EIO; - goto done; + acb->n, &acb->hd_qiov); + qemu_co_mutex_lock(&s->lock); + if (ret < 0) { + return ret; } } - return; - -done: - if (acb->qiov->niov > 1) { - qemu_iovec_from_buffer(acb->qiov, acb->orig_buf, acb->qiov->size); - qemu_vfree(acb->orig_buf); - } - acb->common.cb(acb->common.opaque, ret); - qemu_aio_release(acb); + return 1; } -static BlockDriverAIOCB *qcow_aio_readv(BlockDriverState *bs, - int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, - BlockDriverCompletionFunc *cb, void *opaque) +static int qcow_co_readv(BlockDriverState *bs, int64_t sector_num, + int nb_sectors, QEMUIOVector *qiov) { + BDRVQcowState *s = bs->opaque; QCowAIOCB *acb; int ret; - acb = qcow_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0); - if (!acb) - return NULL; + acb = qcow_aio_setup(bs, sector_num, qiov, nb_sectors, 0); - ret = qcow_schedule_bh(qcow_aio_rw_bh, acb); - if (ret < 0) { - if (acb->qiov->niov > 1) { - qemu_vfree(acb->orig_buf); - } - qemu_aio_release(acb); - return NULL; + qemu_co_mutex_lock(&s->lock); + do { + ret = qcow_aio_read_cb(acb); + } while (ret > 0); + qemu_co_mutex_unlock(&s->lock); + + if (acb->qiov->niov > 1) { + qemu_iovec_from_buffer(acb->qiov, acb->orig_buf, acb->qiov->size); + qemu_vfree(acb->orig_buf); } + qemu_aio_release(acb); - return &acb->common; + return ret; } -static void qcow_aio_write_cb(void *opaque, int ret) +static int qcow_aio_write_cb(void *opaque) { QCowAIOCB *acb = opaque; BlockDriverState *bs = acb->common.bs; @@ -702,20 +662,17 @@ static void qcow_aio_write_cb(void *opaque, int ret) int index_in_cluster; uint64_t cluster_offset; const uint8_t *src_buf; + int ret; acb->hd_aiocb = NULL; - if (ret < 0) - goto done; - acb->nb_sectors -= acb->n; acb->sector_num += acb->n; acb->buf += acb->n * 512; if (acb->nb_sectors == 0) { /* request completed */ - ret = 0; - goto done; + return 0; } index_in_cluster = acb->sector_num & (s->cluster_sectors - 1); @@ -726,16 +683,11 @@ static void qcow_aio_write_cb(void *opaque, int ret) index_in_cluster, index_in_cluster + acb->n); if (!cluster_offset || (cluster_offset & 511) != 0) { - ret = -EIO; - goto done; + return -EIO; } if (s->crypt_method) { if (!acb->cluster_data) { acb->cluster_data = qemu_mallocz(s->cluster_size); - if (!acb->cluster_data) { - ret = -ENOMEM; - goto done; - } } encrypt_sectors(s, acb->sector_num, acb->cluster_data, acb->buf, acb->n, 1, &s->aes_encrypt_key); @@ -747,26 +699,19 @@ static void qcow_aio_write_cb(void *opaque, int ret) acb->hd_iov.iov_base = (void *)src_buf; acb->hd_iov.iov_len = acb->n * 512; qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1); - acb->hd_aiocb = bdrv_aio_writev(bs->file, - (cluster_offset >> 9) + index_in_cluster, - &acb->hd_qiov, acb->n, - qcow_aio_write_cb, acb); - if (acb->hd_aiocb == NULL) { - ret = -EIO; - goto done; + qemu_co_mutex_unlock(&s->lock); + ret = bdrv_co_writev(bs->file, + (cluster_offset >> 9) + index_in_cluster, + acb->n, &acb->hd_qiov); + qemu_co_mutex_lock(&s->lock); + if (ret < 0) { + return ret; } - return; - -done: - if (acb->qiov->niov > 1) - qemu_vfree(acb->orig_buf); - acb->common.cb(acb->common.opaque, ret); - qemu_aio_release(acb); + return 1; } -static BlockDriverAIOCB *qcow_aio_writev(BlockDriverState *bs, - int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, - BlockDriverCompletionFunc *cb, void *opaque) +static int qcow_co_writev(BlockDriverState *bs, int64_t sector_num, + int nb_sectors, QEMUIOVector *qiov) { BDRVQcowState *s = bs->opaque; QCowAIOCB *acb; @@ -774,21 +719,20 @@ static BlockDriverAIOCB *qcow_aio_writev(BlockDriverState *bs, s->cluster_cache_offset = -1; /* disable compressed cache */ - acb = qcow_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 1); - if (!acb) - return NULL; + acb = qcow_aio_setup(bs, sector_num, qiov, nb_sectors, 1); + qemu_co_mutex_lock(&s->lock); + do { + ret = qcow_aio_write_cb(acb); + } while (ret > 0); + qemu_co_mutex_unlock(&s->lock); - ret = qcow_schedule_bh(qcow_aio_rw_bh, acb); - if (ret < 0) { - if (acb->qiov->niov > 1) { - qemu_vfree(acb->orig_buf); - } - qemu_aio_release(acb); - return NULL; + if (acb->qiov->niov > 1) { + qemu_vfree(acb->orig_buf); } + qemu_aio_release(acb); - return &acb->common; + return ret; } static void qcow_close(BlockDriverState *bs) @@ -1020,8 +964,8 @@ static BlockDriver bdrv_qcow = { .bdrv_is_allocated = qcow_is_allocated, .bdrv_set_key = qcow_set_key, .bdrv_make_empty = qcow_make_empty, - .bdrv_aio_readv = qcow_aio_readv, - .bdrv_aio_writev = qcow_aio_writev, + .bdrv_co_readv = qcow_co_readv, + .bdrv_co_writev = qcow_co_writev, .bdrv_aio_flush = qcow_aio_flush, .bdrv_write_compressed = qcow_write_compressed, .bdrv_get_info = qcow_get_info, diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 882f50a80b..81cf77d83c 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -697,12 +697,12 @@ err: * m->depends_on is set to NULL and the other fields in m are meaningless. * * If the cluster is newly allocated, m->nb_clusters is set to the number of - * contiguous clusters that have been allocated. This may be 0 if the request - * conflict with another write request in flight; in this case, m->depends_on - * is set and the remaining fields of m are meaningless. + * contiguous clusters that have been allocated. In this case, the other + * fields of m are valid and contain information about the first allocated + * cluster. * - * If m->nb_clusters is non-zero, the other fields of m are valid and contain - * information about the first allocated cluster. + * If the request conflicts with another write request in flight, the coroutine + * is queued and will be reentered when the dependency has completed. * * Return 0 on success and -errno in error cases */ @@ -721,6 +721,7 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset, return ret; } +again: nb_clusters = size_to_clusters(s, n_end << 9); nb_clusters = MIN(nb_clusters, s->l2_size - l2_index); @@ -792,12 +793,12 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset, } if (nb_clusters == 0) { - /* Set dependency and wait for a callback */ - m->depends_on = old_alloc; - m->nb_clusters = 0; - *num = 0; - - goto out_wait_dependency; + /* Wait for the dependency to complete. We need to recheck + * the free/allocated clusters when we continue. */ + qemu_co_mutex_unlock(&s->lock); + qemu_co_queue_wait(&old_alloc->dependent_requests); + qemu_co_mutex_lock(&s->lock); + goto again; } } } @@ -834,9 +835,6 @@ out: return 0; -out_wait_dependency: - return qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table); - fail: qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table); fail_put: diff --git a/block/qcow2.c b/block/qcow2.c index 48e1b95689..f07d550a96 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -276,6 +276,9 @@ static int qcow2_open(BlockDriverState *bs, int flags) goto fail; } + /* Initialise locks */ + qemu_co_mutex_init(&s->lock); + #ifdef DEBUG_ALLOC qcow2_check_refcounts(bs); #endif @@ -379,7 +382,6 @@ typedef struct QCowAIOCB { uint64_t cluster_offset; uint8_t *cluster_data; bool is_write; - BlockDriverAIOCB *hd_aiocb; QEMUIOVector hd_qiov; QEMUBH *bh; QCowL2Meta l2meta; @@ -389,8 +391,6 @@ typedef struct QCowAIOCB { static void qcow2_aio_cancel(BlockDriverAIOCB *blockacb) { QCowAIOCB *acb = container_of(blockacb, QCowAIOCB, common); - if (acb->hd_aiocb) - bdrv_aio_cancel(acb->hd_aiocb); qemu_aio_release(acb); } @@ -399,46 +399,16 @@ static AIOPool qcow2_aio_pool = { .cancel = qcow2_aio_cancel, }; -static void qcow2_aio_read_cb(void *opaque, int ret); -static void qcow2_aio_write_cb(void *opaque, int ret); - -static void qcow2_aio_rw_bh(void *opaque) -{ - QCowAIOCB *acb = opaque; - qemu_bh_delete(acb->bh); - acb->bh = NULL; - - if (acb->is_write) { - qcow2_aio_write_cb(opaque, 0); - } else { - qcow2_aio_read_cb(opaque, 0); - } -} - -static int qcow2_schedule_bh(QEMUBHFunc *cb, QCowAIOCB *acb) -{ - if (acb->bh) - return -EIO; - - acb->bh = qemu_bh_new(cb, acb); - if (!acb->bh) - return -EIO; - - qemu_bh_schedule(acb->bh); - - return 0; -} - -static void qcow2_aio_read_cb(void *opaque, int ret) +/* + * Returns 0 when the request is completed successfully, 1 when there is still + * a part left to do and -errno in error cases. + */ +static int qcow2_aio_read_cb(QCowAIOCB *acb) { - QCowAIOCB *acb = opaque; BlockDriverState *bs = acb->common.bs; BDRVQcowState *s = bs->opaque; int index_in_cluster, n1; - - acb->hd_aiocb = NULL; - if (ret < 0) - goto done; + int ret; /* post process the read buffer */ if (!acb->cluster_offset) { @@ -463,8 +433,7 @@ static void qcow2_aio_read_cb(void *opaque, int ret) if (acb->remaining_sectors == 0) { /* request completed */ - ret = 0; - goto done; + return 0; } /* prepare next AIO request */ @@ -477,7 +446,7 @@ static void qcow2_aio_read_cb(void *opaque, int ret) ret = qcow2_get_cluster_offset(bs, acb->sector_num << 9, &acb->cur_nr_sectors, &acb->cluster_offset); if (ret < 0) { - goto done; + return ret; } index_in_cluster = acb->sector_num & (s->cluster_sectors - 1); @@ -494,42 +463,35 @@ static void qcow2_aio_read_cb(void *opaque, int ret) acb->sector_num, acb->cur_nr_sectors); if (n1 > 0) { BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO); - acb->hd_aiocb = bdrv_aio_readv(bs->backing_hd, acb->sector_num, - &acb->hd_qiov, n1, qcow2_aio_read_cb, acb); - if (acb->hd_aiocb == NULL) { - ret = -EIO; - goto done; + qemu_co_mutex_unlock(&s->lock); + ret = bdrv_co_readv(bs->backing_hd, acb->sector_num, + n1, &acb->hd_qiov); + qemu_co_mutex_lock(&s->lock); + if (ret < 0) { + return ret; } - } else { - ret = qcow2_schedule_bh(qcow2_aio_rw_bh, acb); - if (ret < 0) - goto done; } + return 1; } else { /* Note: in this case, no need to wait */ qemu_iovec_memset(&acb->hd_qiov, 0, 512 * acb->cur_nr_sectors); - ret = qcow2_schedule_bh(qcow2_aio_rw_bh, acb); - if (ret < 0) - goto done; + return 1; } } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) { /* add AIO support for compressed blocks ? */ ret = qcow2_decompress_cluster(bs, acb->cluster_offset); if (ret < 0) { - goto done; + return ret; } qemu_iovec_from_buffer(&acb->hd_qiov, s->cluster_cache + index_in_cluster * 512, 512 * acb->cur_nr_sectors); - ret = qcow2_schedule_bh(qcow2_aio_rw_bh, acb); - if (ret < 0) - goto done; + return 1; } else { if ((acb->cluster_offset & 511) != 0) { - ret = -EIO; - goto done; + return -EIO; } if (s->crypt_method) { @@ -550,21 +512,17 @@ static void qcow2_aio_read_cb(void *opaque, int ret) } BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO); - acb->hd_aiocb = bdrv_aio_readv(bs->file, + qemu_co_mutex_unlock(&s->lock); + ret = bdrv_co_readv(bs->file, (acb->cluster_offset >> 9) + index_in_cluster, - &acb->hd_qiov, acb->cur_nr_sectors, - qcow2_aio_read_cb, acb); - if (acb->hd_aiocb == NULL) { - ret = -EIO; - goto done; + acb->cur_nr_sectors, &acb->hd_qiov); + qemu_co_mutex_lock(&s->lock); + if (ret < 0) { + return ret; } } - return; -done: - acb->common.cb(acb->common.opaque, ret); - qemu_iovec_destroy(&acb->hd_qiov); - qemu_aio_release(acb); + return 1; } static QCowAIOCB *qcow2_aio_setup(BlockDriverState *bs, int64_t sector_num, @@ -577,7 +535,6 @@ static QCowAIOCB *qcow2_aio_setup(BlockDriverState *bs, int64_t sector_num, acb = qemu_aio_get(&qcow2_aio_pool, bs, cb, opaque); if (!acb) return NULL; - acb->hd_aiocb = NULL; acb->sector_num = sector_num; acb->qiov = qiov; acb->is_write = is_write; @@ -589,70 +546,65 @@ static QCowAIOCB *qcow2_aio_setup(BlockDriverState *bs, int64_t sector_num, acb->cur_nr_sectors = 0; acb->cluster_offset = 0; acb->l2meta.nb_clusters = 0; - QLIST_INIT(&acb->l2meta.dependent_requests); + qemu_co_queue_init(&acb->l2meta.dependent_requests); return acb; } -static BlockDriverAIOCB *qcow2_aio_readv(BlockDriverState *bs, - int64_t sector_num, - QEMUIOVector *qiov, int nb_sectors, - BlockDriverCompletionFunc *cb, - void *opaque) +static int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num, + int nb_sectors, QEMUIOVector *qiov) { + BDRVQcowState *s = bs->opaque; QCowAIOCB *acb; int ret; - acb = qcow2_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0); - if (!acb) - return NULL; + acb = qcow2_aio_setup(bs, sector_num, qiov, nb_sectors, NULL, NULL, 0); - ret = qcow2_schedule_bh(qcow2_aio_rw_bh, acb); - if (ret < 0) { - qemu_iovec_destroy(&acb->hd_qiov); - qemu_aio_release(acb); - return NULL; - } + qemu_co_mutex_lock(&s->lock); + do { + ret = qcow2_aio_read_cb(acb); + } while (ret > 0); + qemu_co_mutex_unlock(&s->lock); - return &acb->common; + qemu_iovec_destroy(&acb->hd_qiov); + qemu_aio_release(acb); + + return ret; } -static void run_dependent_requests(QCowL2Meta *m) +static void run_dependent_requests(BDRVQcowState *s, QCowL2Meta *m) { - QCowAIOCB *req; - QCowAIOCB *next; - /* Take the request off the list of running requests */ if (m->nb_clusters != 0) { QLIST_REMOVE(m, next_in_flight); } /* Restart all dependent requests */ - QLIST_FOREACH_SAFE(req, &m->dependent_requests, next_depend, next) { - qcow2_aio_write_cb(req, 0); + if (!qemu_co_queue_empty(&m->dependent_requests)) { + qemu_co_mutex_unlock(&s->lock); + while(qemu_co_queue_next(&m->dependent_requests)); + qemu_co_mutex_lock(&s->lock); } - - /* Empty the list for the next part of the request */ - QLIST_INIT(&m->dependent_requests); } -static void qcow2_aio_write_cb(void *opaque, int ret) +/* + * Returns 0 when the request is completed successfully, 1 when there is still + * a part left to do and -errno in error cases. + */ +static int qcow2_aio_write_cb(QCowAIOCB *acb) { - QCowAIOCB *acb = opaque; BlockDriverState *bs = acb->common.bs; BDRVQcowState *s = bs->opaque; int index_in_cluster; int n_end; + int ret; - acb->hd_aiocb = NULL; - - if (ret >= 0) { - ret = qcow2_alloc_cluster_link_l2(bs, &acb->l2meta); - } + ret = qcow2_alloc_cluster_link_l2(bs, &acb->l2meta); - run_dependent_requests(&acb->l2meta); + run_dependent_requests(s, &acb->l2meta); - if (ret < 0) - goto done; + if (ret < 0) { + return ret; + } acb->remaining_sectors -= acb->cur_nr_sectors; acb->sector_num += acb->cur_nr_sectors; @@ -660,8 +612,7 @@ static void qcow2_aio_write_cb(void *opaque, int ret) if (acb->remaining_sectors == 0) { /* request completed */ - ret = 0; - goto done; + return 0; } index_in_cluster = acb->sector_num & (s->cluster_sectors - 1); @@ -673,18 +624,10 @@ static void qcow2_aio_write_cb(void *opaque, int ret) ret = qcow2_alloc_cluster_offset(bs, acb->sector_num << 9, index_in_cluster, n_end, &acb->cur_nr_sectors, &acb->l2meta); if (ret < 0) { - goto done; + return ret; } acb->cluster_offset = acb->l2meta.cluster_offset; - - /* Need to wait for another request? If so, we are done for now. */ - if (acb->l2meta.nb_clusters == 0 && acb->l2meta.depends_on != NULL) { - QLIST_INSERT_HEAD(&acb->l2meta.depends_on->dependent_requests, - acb, next_depend); - return; - } - assert((acb->cluster_offset & 511) == 0); qemu_iovec_reset(&acb->hd_qiov); @@ -709,51 +652,40 @@ static void qcow2_aio_write_cb(void *opaque, int ret) } BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO); - acb->hd_aiocb = bdrv_aio_writev(bs->file, - (acb->cluster_offset >> 9) + index_in_cluster, - &acb->hd_qiov, acb->cur_nr_sectors, - qcow2_aio_write_cb, acb); - if (acb->hd_aiocb == NULL) { - ret = -EIO; - goto fail; + qemu_co_mutex_unlock(&s->lock); + ret = bdrv_co_writev(bs->file, + (acb->cluster_offset >> 9) + index_in_cluster, + acb->cur_nr_sectors, &acb->hd_qiov); + qemu_co_mutex_lock(&s->lock); + if (ret < 0) { + return ret; } - return; - -fail: - if (acb->l2meta.nb_clusters != 0) { - QLIST_REMOVE(&acb->l2meta, next_in_flight); - } -done: - acb->common.cb(acb->common.opaque, ret); - qemu_iovec_destroy(&acb->hd_qiov); - qemu_aio_release(acb); + return 1; } -static BlockDriverAIOCB *qcow2_aio_writev(BlockDriverState *bs, - int64_t sector_num, - QEMUIOVector *qiov, int nb_sectors, - BlockDriverCompletionFunc *cb, - void *opaque) +static int qcow2_co_writev(BlockDriverState *bs, + int64_t sector_num, + int nb_sectors, + QEMUIOVector *qiov) { BDRVQcowState *s = bs->opaque; QCowAIOCB *acb; int ret; + acb = qcow2_aio_setup(bs, sector_num, qiov, nb_sectors, NULL, NULL, 1); s->cluster_cache_offset = -1; /* disable compressed cache */ - acb = qcow2_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 1); - if (!acb) - return NULL; + qemu_co_mutex_lock(&s->lock); + do { + ret = qcow2_aio_write_cb(acb); + } while (ret > 0); + qemu_co_mutex_unlock(&s->lock); - ret = qcow2_schedule_bh(qcow2_aio_rw_bh, acb); - if (ret < 0) { - qemu_iovec_destroy(&acb->hd_qiov); - qemu_aio_release(acb); - return NULL; - } + qemu_iovec_destroy(&acb->hd_qiov); + qemu_aio_release(acb); - return &acb->common; + return ret; } static void qcow2_close(BlockDriverState *bs) @@ -881,7 +813,7 @@ static int preallocate(BlockDriverState *bs) nb_sectors = bdrv_getlength(bs) >> 9; offset = 0; - QLIST_INIT(&meta.dependent_requests); + qemu_co_queue_init(&meta.dependent_requests); meta.cluster_offset = 0; while (nb_sectors) { @@ -899,7 +831,7 @@ static int preallocate(BlockDriverState *bs) /* There are no dependent requests, but we need to remove our request * from the list of in-flight requests */ - run_dependent_requests(&meta); + run_dependent_requests(bs->opaque, &meta); /* TODO Preallocate data if requested */ @@ -1387,8 +1319,8 @@ static BlockDriver bdrv_qcow2 = { .bdrv_set_key = qcow2_set_key, .bdrv_make_empty = qcow2_make_empty, - .bdrv_aio_readv = qcow2_aio_readv, - .bdrv_aio_writev = qcow2_aio_writev, + .bdrv_co_readv = qcow2_co_readv, + .bdrv_co_writev = qcow2_co_writev, .bdrv_aio_flush = qcow2_aio_flush, .bdrv_discard = qcow2_discard, diff --git a/block/qcow2.h b/block/qcow2.h index 6a0a21b694..de23abe1a4 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -26,6 +26,7 @@ #define BLOCK_QCOW2_H #include "aes.h" +#include "qemu-coroutine.h" //#define DEBUG_ALLOC //#define DEBUG_ALLOC2 @@ -114,6 +115,8 @@ typedef struct BDRVQcowState { int64_t free_cluster_index; int64_t free_byte_offset; + CoMutex lock; + uint32_t crypt_method; /* current crypt method, 0 if no key yet */ uint32_t crypt_method_header; AES_KEY aes_encrypt_key; @@ -146,7 +149,7 @@ typedef struct QCowL2Meta int nb_available; int nb_clusters; struct QCowL2Meta *depends_on; - QLIST_HEAD(QCowAioDependencies, QCowAIOCB) dependent_requests; + CoQueue dependent_requests; QLIST_ENTRY(QCowL2Meta) next_in_flight; } QCowL2Meta; diff --git a/block/qed-table.c b/block/qed-table.c index d38c673547..d96afa81d7 100644 --- a/block/qed-table.c +++ b/block/qed-table.c @@ -179,16 +179,12 @@ int qed_read_l1_table_sync(BDRVQEDState *s) { int ret = -EINPROGRESS; - async_context_push(); - qed_read_table(s, s->header.l1_table_offset, s->l1_table, qed_sync_cb, &ret); while (ret == -EINPROGRESS) { qemu_aio_wait(); } - async_context_pop(); - return ret; } @@ -205,15 +201,11 @@ int qed_write_l1_table_sync(BDRVQEDState *s, unsigned int index, { int ret = -EINPROGRESS; - async_context_push(); - qed_write_l1_table(s, index, n, qed_sync_cb, &ret); while (ret == -EINPROGRESS) { qemu_aio_wait(); } - async_context_pop(); - return ret; } @@ -282,14 +274,11 @@ int qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request, uint64_t offset { int ret = -EINPROGRESS; - async_context_push(); - qed_read_l2_table(s, request, offset, qed_sync_cb, &ret); while (ret == -EINPROGRESS) { qemu_aio_wait(); } - async_context_pop(); return ret; } @@ -307,13 +296,10 @@ int qed_write_l2_table_sync(BDRVQEDState *s, QEDRequest *request, { int ret = -EINPROGRESS; - async_context_push(); - qed_write_l2_table(s, request, index, n, flush, qed_sync_cb, &ret); while (ret == -EINPROGRESS) { qemu_aio_wait(); } - async_context_pop(); return ret; } diff --git a/block/qed.c b/block/qed.c index 39703793e9..333f067582 100644 --- a/block/qed.c +++ b/block/qed.c @@ -680,16 +680,12 @@ static int bdrv_qed_is_allocated(BlockDriverState *bs, int64_t sector_num, }; QEDRequest request = { .l2_table = NULL }; - async_context_push(); - qed_find_cluster(s, &request, pos, len, qed_is_allocated_cb, &cb); while (cb.is_allocated == -1) { qemu_aio_wait(); } - async_context_pop(); - qed_unref_l2_cache_entry(request.l2_table); return cb.is_allocated; diff --git a/block/raw-posix.c b/block/raw-posix.c index cd89c8312a..c5c99446c0 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -230,13 +230,15 @@ static int raw_open_common(BlockDriverState *bs, const char *filename, } } + /* We're falling back to POSIX AIO in some cases so init always */ + if (paio_init() < 0) { + goto out_free_buf; + } + #ifdef CONFIG_LINUX_AIO if ((bdrv_flags & (BDRV_O_NOCACHE|BDRV_O_NATIVE_AIO)) == (BDRV_O_NOCACHE|BDRV_O_NATIVE_AIO)) { - /* We're falling back to POSIX AIO in some cases */ - paio_init(); - s->aio_ctx = laio_init(); if (!s->aio_ctx) { goto out_free_buf; @@ -245,9 +247,6 @@ static int raw_open_common(BlockDriverState *bs, const char *filename, } else #endif { - if (paio_init() < 0) { - goto out_free_buf; - } #ifdef CONFIG_LINUX_AIO s->use_aio = 0; #endif @@ -587,7 +586,7 @@ static BlockDriverAIOCB *raw_aio_submit(BlockDriverState *bs, /* * If O_DIRECT is used the buffer needs to be aligned on a sector - * boundary. Check if this is the case or telll the low-level + * boundary. Check if this is the case or tell the low-level * driver that it needs to copy the buffer. */ if (s->aligned_buf) { @@ -1254,7 +1253,7 @@ static int floppy_media_changed(BlockDriverState *bs) return ret; } -static int floppy_eject(BlockDriverState *bs, int eject_flag) +static void floppy_eject(BlockDriverState *bs, int eject_flag) { BDRVRawState *s = bs->opaque; int fd; @@ -1269,8 +1268,6 @@ static int floppy_eject(BlockDriverState *bs, int eject_flag) perror("FDEJECT"); close(fd); } - - return 0; } static BlockDriver bdrv_host_floppy = { @@ -1348,7 +1345,7 @@ static int cdrom_is_inserted(BlockDriverState *bs) return 0; } -static int cdrom_eject(BlockDriverState *bs, int eject_flag) +static void cdrom_eject(BlockDriverState *bs, int eject_flag) { BDRVRawState *s = bs->opaque; @@ -1359,11 +1356,9 @@ static int cdrom_eject(BlockDriverState *bs, int eject_flag) if (ioctl(s->fd, CDROMCLOSETRAY, NULL) < 0) perror("CDROMEJECT"); } - - return 0; } -static int cdrom_set_locked(BlockDriverState *bs, int locked) +static void cdrom_set_locked(BlockDriverState *bs, int locked) { BDRVRawState *s = bs->opaque; @@ -1374,8 +1369,6 @@ static int cdrom_set_locked(BlockDriverState *bs, int locked) */ /* perror("CDROM_LOCKDOOR"); */ } - - return 0; } static BlockDriver bdrv_host_cdrom = { @@ -1464,12 +1457,12 @@ static int cdrom_is_inserted(BlockDriverState *bs) return raw_getlength(bs) > 0; } -static int cdrom_eject(BlockDriverState *bs, int eject_flag) +static void cdrom_eject(BlockDriverState *bs, int eject_flag) { BDRVRawState *s = bs->opaque; if (s->fd < 0) - return -ENOTSUP; + return; (void) ioctl(s->fd, CDIOCALLOW); @@ -1481,17 +1474,15 @@ static int cdrom_eject(BlockDriverState *bs, int eject_flag) perror("CDIOCCLOSE"); } - if (cdrom_reopen(bs) < 0) - return -ENOTSUP; - return 0; + cdrom_reopen(bs); } -static int cdrom_set_locked(BlockDriverState *bs, int locked) +static void cdrom_set_locked(BlockDriverState *bs, int locked) { BDRVRawState *s = bs->opaque; if (s->fd < 0) - return -ENOTSUP; + return; if (ioctl(s->fd, (locked ? CDIOCPREVENT : CDIOCALLOW)) < 0) { /* * Note: an error can happen if the distribution automatically @@ -1499,8 +1490,6 @@ static int cdrom_set_locked(BlockDriverState *bs, int locked) */ /* perror("CDROM_LOCKDOOR"); */ } - - return 0; } static BlockDriver bdrv_host_cdrom = { diff --git a/block/raw-win32.c b/block/raw-win32.c index 91067e7595..e47cfe0f4a 100644 --- a/block/raw-win32.c +++ b/block/raw-win32.c @@ -393,41 +393,6 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags) return 0; } -#if 0 -/***********************************************/ -/* removable device additional commands */ - -static int raw_is_inserted(BlockDriverState *bs) -{ - return 1; -} - -static int raw_media_changed(BlockDriverState *bs) -{ - return -ENOTSUP; -} - -static int raw_eject(BlockDriverState *bs, int eject_flag) -{ - DWORD ret_count; - - if (s->type == FTYPE_FILE) - return -ENOTSUP; - if (eject_flag) { - DeviceIoControl(s->hfile, IOCTL_STORAGE_EJECT_MEDIA, - NULL, 0, NULL, 0, &lpBytesReturned, NULL); - } else { - DeviceIoControl(s->hfile, IOCTL_STORAGE_LOAD_MEDIA, - NULL, 0, NULL, 0, &lpBytesReturned, NULL); - } -} - -static int raw_set_locked(BlockDriverState *bs, int locked) -{ - return -ENOTSUP; -} -#endif - static int hdev_has_zero_init(BlockDriverState *bs) { return 0; diff --git a/block/raw.c b/block/raw.c index b0f72d6a62..cb6203eeca 100644 --- a/block/raw.c +++ b/block/raw.c @@ -75,15 +75,14 @@ static int raw_is_inserted(BlockDriverState *bs) return bdrv_is_inserted(bs->file); } -static int raw_eject(BlockDriverState *bs, int eject_flag) +static void raw_eject(BlockDriverState *bs, int eject_flag) { - return bdrv_eject(bs->file, eject_flag); + bdrv_eject(bs->file, eject_flag); } -static int raw_set_locked(BlockDriverState *bs, int locked) +static void raw_set_locked(BlockDriverState *bs, int locked) { bdrv_set_locked(bs->file, locked); - return 0; } static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf) diff --git a/block/vpc.c b/block/vpc.c index 56865da5bc..fdd5236892 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -156,6 +156,7 @@ static int vpc_open(BlockDriverState *bs, int flags) struct vhd_dyndisk_header* dyndisk_header; uint8_t buf[HEADER_SIZE]; uint32_t checksum; + int err = -1; if (bdrv_pread(bs->file, 0, s->footer_buf, HEADER_SIZE) != HEADER_SIZE) goto fail; @@ -176,6 +177,11 @@ static int vpc_open(BlockDriverState *bs, int flags) bs->total_sectors = (int64_t) be16_to_cpu(footer->cyls) * footer->heads * footer->secs_per_cyl; + if (bs->total_sectors >= 65535 * 16 * 255) { + err = -EFBIG; + goto fail; + } + if (bdrv_pread(bs->file, be64_to_cpu(footer->data_offset), buf, HEADER_SIZE) != HEADER_SIZE) goto fail; @@ -222,7 +228,7 @@ static int vpc_open(BlockDriverState *bs, int flags) return 0; fail: - return -1; + return err; } /* |