diff options
Diffstat (limited to 'block')
-rw-r--r-- | block/qcow2-cluster.c | 25 | ||||
-rw-r--r-- | block/qcow2-snapshot.c | 2 | ||||
-rw-r--r-- | block/qcow2.c | 3 | ||||
-rw-r--r-- | block/rbd.c | 89 |
4 files changed, 91 insertions, 28 deletions
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index a747a88..353889d 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -759,7 +759,7 @@ out: * restarted, but the whole request should not be failed. */ static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset, - uint64_t *host_offset, unsigned int *nb_clusters, uint64_t *l2_table) + uint64_t *host_offset, unsigned int *nb_clusters) { BDRVQcowState *s = bs->opaque; int64_t cluster_offset; @@ -853,6 +853,7 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset, n_start, n_end); /* Find L2 entry for the first involved cluster */ +again: ret = get_cluster_table(bs, offset, &l2_table, &l2_index); if (ret < 0) { return ret; @@ -862,7 +863,6 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset, * Calculate the number of clusters to look for. We stop at L2 table * boundaries to keep things simple. */ -again: nb_clusters = MIN(size_to_clusters(s, n_end << BDRV_SECTOR_BITS), s->l2_size - l2_index); @@ -896,6 +896,18 @@ again: cluster_offset &= L2E_OFFSET_MASK; + /* + * The L2 table isn't used any more after this. As long as the cache works + * synchronously, it's important to release it before calling + * do_alloc_cluster_offset, which may yield if we need to wait for another + * request to complete. If we still had the reference, we could use up the + * whole cache with sleeping requests. + */ + ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table); + if (ret < 0) { + return ret; + } + /* If there is something left to allocate, do that now */ *m = (QCowL2Meta) { .cluster_offset = cluster_offset, @@ -919,7 +931,7 @@ again: /* Allocate, if necessary at a given offset in the image file */ ret = do_alloc_cluster_offset(bs, alloc_offset, &alloc_cluster_offset, - &nb_clusters, l2_table); + &nb_clusters); if (ret == -EAGAIN) { goto again; } else if (ret < 0) { @@ -947,11 +959,6 @@ again: } /* Some cleanup work */ - ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table); - if (ret < 0) { - goto fail_put; - } - sectors = (keep_clusters + nb_clusters) << (s->cluster_bits - 9); if (sectors > n_end) { sectors = n_end; @@ -963,8 +970,6 @@ again: return 0; fail: - qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table); -fail_put: if (m->nb_clusters > 0) { QLIST_REMOVE(m, next_in_flight); } diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c index 42f971b..4561a2a 100644 --- a/block/qcow2-snapshot.c +++ b/block/qcow2-snapshot.c @@ -331,7 +331,7 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) /* Check that the ID is unique */ if (find_snapshot_by_id(bs, sn_info->id_str) >= 0) { - return -ENOENT; + return -EEXIST; } /* Populate sn with passed data */ diff --git a/block/qcow2.c b/block/qcow2.c index ad46c03..8c60a6f 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -182,7 +182,8 @@ static void cleanup_unknown_header_ext(BlockDriverState *bs) } } -static void report_unsupported(BlockDriverState *bs, const char *fmt, ...) +static void GCC_FMT_ATTR(2, 3) report_unsupported(BlockDriverState *bs, + const char *fmt, ...) { char msg[64]; va_list ap; diff --git a/block/rbd.c b/block/rbd.c index 6cd8448..1280d66 100644 --- a/block/rbd.c +++ b/block/rbd.c @@ -44,6 +44,13 @@ * leading "\". */ +/* rbd_aio_discard added in 0.1.2 */ +#if LIBRBD_VERSION_CODE >= LIBRBD_VERSION(0, 1, 2) +#define LIBRBD_SUPPORTS_DISCARD +#else +#undef LIBRBD_SUPPORTS_DISCARD +#endif + #define OBJ_MAX_SIZE (1UL << OBJ_DEFAULT_OBJ_ORDER) #define RBD_MAX_CONF_NAME_SIZE 128 @@ -53,13 +60,19 @@ #define RBD_MAX_SNAP_NAME_SIZE 128 #define RBD_MAX_SNAPS 100 +typedef enum { + RBD_AIO_READ, + RBD_AIO_WRITE, + RBD_AIO_DISCARD +} RBDAIOCmd; + typedef struct RBDAIOCB { BlockDriverAIOCB common; QEMUBH *bh; int ret; QEMUIOVector *qiov; char *bounce; - int write; + RBDAIOCmd cmd; int64_t sector_num; int error; struct BDRVRBDState *s; @@ -371,7 +384,8 @@ static void qemu_rbd_complete_aio(RADOSCB *rcb) r = rcb->ret; - if (acb->write) { + if (acb->cmd == RBD_AIO_WRITE || + acb->cmd == RBD_AIO_DISCARD) { if (r < 0) { acb->ret = r; acb->error = 1; @@ -605,7 +619,7 @@ static void rbd_aio_bh_cb(void *opaque) { RBDAIOCB *acb = opaque; - if (!acb->write) { + if (acb->cmd == RBD_AIO_READ) { qemu_iovec_from_buffer(acb->qiov, acb->bounce, acb->qiov->size); } qemu_vfree(acb->bounce); @@ -616,12 +630,25 @@ static void rbd_aio_bh_cb(void *opaque) qemu_aio_release(acb); } -static BlockDriverAIOCB *rbd_aio_rw_vector(BlockDriverState *bs, - int64_t sector_num, - QEMUIOVector *qiov, - int nb_sectors, - BlockDriverCompletionFunc *cb, - void *opaque, int write) +static int rbd_aio_discard_wrapper(rbd_image_t image, + uint64_t off, + uint64_t len, + rbd_completion_t comp) +{ +#ifdef LIBRBD_SUPPORTS_DISCARD + return rbd_aio_discard(image, off, len, comp); +#else + return -ENOTSUP; +#endif +} + +static BlockDriverAIOCB *rbd_start_aio(BlockDriverState *bs, + int64_t sector_num, + QEMUIOVector *qiov, + int nb_sectors, + BlockDriverCompletionFunc *cb, + void *opaque, + RBDAIOCmd cmd) { RBDAIOCB *acb; RADOSCB *rcb; @@ -633,16 +660,20 @@ static BlockDriverAIOCB *rbd_aio_rw_vector(BlockDriverState *bs, BDRVRBDState *s = bs->opaque; acb = qemu_aio_get(&rbd_aio_pool, bs, cb, opaque); - acb->write = write; + acb->cmd = cmd; acb->qiov = qiov; - acb->bounce = qemu_blockalign(bs, qiov->size); + if (cmd == RBD_AIO_DISCARD) { + acb->bounce = NULL; + } else { + acb->bounce = qemu_blockalign(bs, qiov->size); + } acb->ret = 0; acb->error = 0; acb->s = s; acb->cancelled = 0; acb->bh = NULL; - if (write) { + if (cmd == RBD_AIO_WRITE) { qemu_iovec_to_buffer(acb->qiov, acb->bounce); } @@ -664,10 +695,18 @@ static BlockDriverAIOCB *rbd_aio_rw_vector(BlockDriverState *bs, goto failed; } - if (write) { + switch (cmd) { + case RBD_AIO_WRITE: r = rbd_aio_write(s->image, off, size, buf, c); - } else { + break; + case RBD_AIO_READ: r = rbd_aio_read(s->image, off, size, buf, c); + break; + case RBD_AIO_DISCARD: + r = rbd_aio_discard_wrapper(s->image, off, size, c); + break; + default: + r = -EINVAL; } if (r < 0) { @@ -690,7 +729,8 @@ static BlockDriverAIOCB *qemu_rbd_aio_readv(BlockDriverState *bs, BlockDriverCompletionFunc *cb, void *opaque) { - return rbd_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 0); + return rbd_start_aio(bs, sector_num, qiov, nb_sectors, cb, opaque, + RBD_AIO_READ); } static BlockDriverAIOCB *qemu_rbd_aio_writev(BlockDriverState *bs, @@ -700,7 +740,8 @@ static BlockDriverAIOCB *qemu_rbd_aio_writev(BlockDriverState *bs, BlockDriverCompletionFunc *cb, void *opaque) { - return rbd_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 1); + return rbd_start_aio(bs, sector_num, qiov, nb_sectors, cb, opaque, + RBD_AIO_WRITE); } static int qemu_rbd_co_flush(BlockDriverState *bs) @@ -850,6 +891,18 @@ static int qemu_rbd_snap_list(BlockDriverState *bs, return snap_count; } +#ifdef LIBRBD_SUPPORTS_DISCARD +static BlockDriverAIOCB* qemu_rbd_aio_discard(BlockDriverState *bs, + int64_t sector_num, + int nb_sectors, + BlockDriverCompletionFunc *cb, + void *opaque) +{ + return rbd_start_aio(bs, sector_num, NULL, nb_sectors, cb, opaque, + RBD_AIO_DISCARD); +} +#endif + static QEMUOptionParameter qemu_rbd_create_options[] = { { .name = BLOCK_OPT_SIZE, @@ -880,6 +933,10 @@ static BlockDriver bdrv_rbd = { .bdrv_aio_writev = qemu_rbd_aio_writev, .bdrv_co_flush_to_disk = qemu_rbd_co_flush, +#ifdef LIBRBD_SUPPORTS_DISCARD + .bdrv_aio_discard = qemu_rbd_aio_discard, +#endif + .bdrv_snapshot_create = qemu_rbd_snap_create, .bdrv_snapshot_delete = qemu_rbd_snap_remove, .bdrv_snapshot_list = qemu_rbd_snap_list, |