From 4265d620c5a91b58c757ce76fa2b0fff86fa1df1 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 17 Oct 2011 12:32:14 +0200 Subject: [PATCH] block: add bdrv_co_discard and bdrv_aio_discard support This similarly adds support for coroutine and asynchronous discard. Signed-off-by: Paolo Bonzini Signed-off-by: Kevin Wolf --- block.c | 102 +++++++++++++++++++++++++++++++++++++++++++++------ block.h | 4 ++ block/raw.c | 10 +++-- block_int.h | 9 ++++- trace-events | 1 + 5 files changed, 109 insertions(+), 17 deletions(-) diff --git a/block.c b/block.c index 7b8b14d971..28508f21d1 100644 --- a/block.c +++ b/block.c @@ -1768,17 +1768,6 @@ int bdrv_has_zero_init(BlockDriverState *bs) return 1; } -int bdrv_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors) -{ - if (!bs->drv) { - return -ENOMEDIUM; - } - if (!bs->drv->bdrv_discard) { - return 0; - } - return bs->drv->bdrv_discard(bs, sector_num, nb_sectors); -} - /* * Returns true iff the specified sector is present in the disk image. Drivers * not implementing the functionality are assumed to not support backing files, @@ -2754,6 +2743,34 @@ BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs, return &acb->common; } +static void coroutine_fn bdrv_aio_discard_co_entry(void *opaque) +{ + BlockDriverAIOCBCoroutine *acb = opaque; + BlockDriverState *bs = acb->common.bs; + + acb->req.error = bdrv_co_discard(bs, acb->req.sector, acb->req.nb_sectors); + acb->bh = qemu_bh_new(bdrv_co_em_bh, acb); + qemu_bh_schedule(acb->bh); +} + +BlockDriverAIOCB *bdrv_aio_discard(BlockDriverState *bs, + int64_t sector_num, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) +{ + Coroutine *co; + BlockDriverAIOCBCoroutine *acb; + + trace_bdrv_aio_discard(bs, sector_num, nb_sectors, opaque); + + acb = qemu_aio_get(&bdrv_em_co_aio_pool, bs, cb, opaque); + acb->req.sector = sector_num; + acb->req.nb_sectors = nb_sectors; + co = qemu_coroutine_create(bdrv_aio_discard_co_entry); + qemu_coroutine_enter(co, acb); + + return &acb->common; +} + void bdrv_init(void) { module_call_init(MODULE_INIT_BLOCK); @@ -2915,6 +2932,69 @@ int bdrv_flush(BlockDriverState *bs) return rwco.ret; } +static void coroutine_fn bdrv_discard_co_entry(void *opaque) +{ + RwCo *rwco = opaque; + + rwco->ret = bdrv_co_discard(rwco->bs, rwco->sector_num, rwco->nb_sectors); +} + +int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num, + int nb_sectors) +{ + if (!bs->drv) { + return -ENOMEDIUM; + } else if (bdrv_check_request(bs, sector_num, nb_sectors)) { + return -EIO; + } else if (bs->read_only) { + return -EROFS; + } else if (bs->drv->bdrv_co_discard) { + return bs->drv->bdrv_co_discard(bs, sector_num, nb_sectors); + } else if (bs->drv->bdrv_aio_discard) { + BlockDriverAIOCB *acb; + CoroutineIOCompletion co = { + .coroutine = qemu_coroutine_self(), + }; + + acb = bs->drv->bdrv_aio_discard(bs, sector_num, nb_sectors, + bdrv_co_io_em_complete, &co); + if (acb == NULL) { + return -EIO; + } else { + qemu_coroutine_yield(); + return co.ret; + } + } else if (bs->drv->bdrv_discard) { + return bs->drv->bdrv_discard(bs, sector_num, nb_sectors); + } else { + return 0; + } +} + +int bdrv_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors) +{ + Coroutine *co; + RwCo rwco = { + .bs = bs, + .sector_num = sector_num, + .nb_sectors = nb_sectors, + .ret = NOT_DONE, + }; + + if (qemu_in_coroutine()) { + /* Fast-path if already in coroutine context */ + bdrv_discard_co_entry(&rwco); + } else { + co = qemu_coroutine_create(bdrv_discard_co_entry); + qemu_coroutine_enter(co, &rwco); + while (rwco.ret == NOT_DONE) { + qemu_aio_wait(); + } + } + + return rwco.ret; +} + /**************************************************************/ /* removable device support */ diff --git a/block.h b/block.h index 65c51663fa..5a042c96e7 100644 --- a/block.h +++ b/block.h @@ -166,6 +166,9 @@ BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num, BlockDriverCompletionFunc *cb, void *opaque); BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs, BlockDriverCompletionFunc *cb, void *opaque); +BlockDriverAIOCB *bdrv_aio_discard(BlockDriverState *bs, + int64_t sector_num, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque); void bdrv_aio_cancel(BlockDriverAIOCB *acb); typedef struct BlockRequest { @@ -196,6 +199,7 @@ void bdrv_flush_all(void); void bdrv_close_all(void); int bdrv_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors); +int bdrv_co_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors); int bdrv_has_zero_init(BlockDriverState *bs); int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum); diff --git a/block/raw.c b/block/raw.c index 39a3a9afae..33cc4716d3 100644 --- a/block/raw.c +++ b/block/raw.c @@ -45,9 +45,10 @@ static int raw_probe(const uint8_t *buf, int buf_size, const char *filename) return 1; /* everything can be opened as raw image */ } -static int raw_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors) +static int coroutine_fn raw_co_discard(BlockDriverState *bs, + int64_t sector_num, int nb_sectors) { - return bdrv_discard(bs->file, sector_num, nb_sectors); + return bdrv_co_discard(bs->file, sector_num, nb_sectors); } static int raw_is_inserted(BlockDriverState *bs) @@ -109,15 +110,16 @@ static BlockDriver bdrv_raw = { .bdrv_open = raw_open, .bdrv_close = raw_close, + .bdrv_co_readv = raw_co_readv, .bdrv_co_writev = raw_co_writev, .bdrv_co_flush = raw_co_flush, + .bdrv_co_discard = raw_co_discard, + .bdrv_probe = raw_probe, .bdrv_getlength = raw_getlength, .bdrv_truncate = raw_truncate, - .bdrv_discard = raw_discard, - .bdrv_is_inserted = raw_is_inserted, .bdrv_media_changed = raw_media_changed, .bdrv_eject = raw_eject, diff --git a/block_int.h b/block_int.h index 9cb536d392..384598ff02 100644 --- a/block_int.h +++ b/block_int.h @@ -63,6 +63,8 @@ struct BlockDriver { void (*bdrv_close)(BlockDriverState *bs); int (*bdrv_create)(const char *filename, QEMUOptionParameter *options); int (*bdrv_flush)(BlockDriverState *bs); + int (*bdrv_discard)(BlockDriverState *bs, int64_t sector_num, + int nb_sectors); int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum); int (*bdrv_set_key)(BlockDriverState *bs, const char *key); @@ -76,14 +78,17 @@ struct BlockDriver { BlockDriverCompletionFunc *cb, void *opaque); BlockDriverAIOCB *(*bdrv_aio_flush)(BlockDriverState *bs, BlockDriverCompletionFunc *cb, void *opaque); - int (*bdrv_discard)(BlockDriverState *bs, int64_t sector_num, - int nb_sectors); + BlockDriverAIOCB *(*bdrv_aio_discard)(BlockDriverState *bs, + int64_t sector_num, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque); int coroutine_fn (*bdrv_co_readv)(BlockDriverState *bs, int64_t sector_num, int nb_sectors, QEMUIOVector *qiov); int coroutine_fn (*bdrv_co_writev)(BlockDriverState *bs, int64_t sector_num, int nb_sectors, QEMUIOVector *qiov); int coroutine_fn (*bdrv_co_flush)(BlockDriverState *bs); + int coroutine_fn (*bdrv_co_discard)(BlockDriverState *bs, + int64_t sector_num, int nb_sectors); int (*bdrv_aio_multiwrite)(BlockDriverState *bs, BlockRequest *reqs, int num_reqs); diff --git a/trace-events b/trace-events index 7f9cec4071..49ac1c170b 100644 --- a/trace-events +++ b/trace-events @@ -61,6 +61,7 @@ multiwrite_cb(void *mcb, int ret) "mcb %p ret %d" bdrv_aio_multiwrite(void *mcb, int num_callbacks, int num_reqs) "mcb %p num_callbacks %d num_reqs %d" bdrv_aio_multiwrite_earlyfail(void *mcb) "mcb %p" bdrv_aio_multiwrite_latefail(void *mcb, int i) "mcb %p i %d" +bdrv_aio_discard(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p" bdrv_aio_flush(void *bs, void *opaque) "bs %p opaque %p" bdrv_aio_readv(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p" bdrv_aio_writev(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p"