diff --git a/block/blkreplay.c b/block/blkreplay.c index 3368c8c98d..c69e5a57a0 100755 --- a/block/blkreplay.c +++ b/block/blkreplay.c @@ -118,7 +118,8 @@ static int coroutine_fn blkreplay_co_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors) { uint64_t reqid = request_id++; - int ret = bdrv_co_discard(bs->file->bs, sector_num, nb_sectors); + int ret = bdrv_co_pdiscard(bs->file->bs, sector_num << BDRV_SECTOR_BITS, + nb_sectors << BDRV_SECTOR_BITS); block_request_create(reqid, bs, qemu_coroutine_self()); qemu_coroutine_yield(); diff --git a/block/block-backend.c b/block/block-backend.c index f9cea1b304..d982cf9d29 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -1113,7 +1113,8 @@ int blk_co_discard(BlockBackend *blk, int64_t sector_num, int nb_sectors) return ret; } - return bdrv_co_discard(blk_bs(blk), sector_num, nb_sectors); + return bdrv_co_pdiscard(blk_bs(blk), sector_num << BDRV_SECTOR_BITS, + nb_sectors << BDRV_SECTOR_BITS); } int blk_co_flush(BlockBackend *blk) diff --git a/block/io.c b/block/io.c index 410394dc42..14d448d50c 100644 --- a/block/io.c +++ b/block/io.c @@ -2199,7 +2199,8 @@ static void coroutine_fn bdrv_aio_discard_co_entry(void *opaque) BlockAIOCBCoroutine *acb = opaque; BlockDriverState *bs = acb->common.bs; - acb->req.error = bdrv_co_discard(bs, acb->req.sector, acb->req.nb_sectors); + acb->req.error = bdrv_co_pdiscard(bs, acb->req.sector << BDRV_SECTOR_BITS, + acb->req.nb_sectors << BDRV_SECTOR_BITS); bdrv_co_complete(acb); } @@ -2398,20 +2399,22 @@ static void coroutine_fn bdrv_discard_co_entry(void *opaque) { DiscardCo *rwco = opaque; - rwco->ret = bdrv_co_discard(rwco->bs, rwco->sector_num, rwco->nb_sectors); + rwco->ret = bdrv_co_pdiscard(rwco->bs, rwco->sector_num << BDRV_SECTOR_BITS, + rwco->nb_sectors << BDRV_SECTOR_BITS); } -int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num, - int nb_sectors) +int coroutine_fn bdrv_co_pdiscard(BlockDriverState *bs, int64_t offset, + int count) { BdrvTrackedRequest req; - int max_discard, ret; + int max_pdiscard, ret; + int head, align; if (!bs->drv) { return -ENOMEDIUM; } - ret = bdrv_check_request(bs, sector_num, nb_sectors); + ret = bdrv_check_byte_request(bs, offset, count); if (ret < 0) { return ret; } else if (bs->read_only) { @@ -2428,45 +2431,45 @@ int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num, return 0; } - tracked_request_begin(&req, bs, sector_num << BDRV_SECTOR_BITS, - nb_sectors << BDRV_SECTOR_BITS, BDRV_TRACKED_DISCARD); + /* Discard is advisory, so ignore any unaligned head or tail */ + align = MAX(BDRV_SECTOR_SIZE, + MAX(bs->bl.pdiscard_alignment, bs->bl.request_alignment)); + assert(is_power_of_2(align)); + head = MIN(count, -offset & (align - 1)); + if (head) { + count -= head; + offset += head; + } + count = QEMU_ALIGN_DOWN(count, align); + if (!count) { + return 0; + } + + tracked_request_begin(&req, bs, offset, count, BDRV_TRACKED_DISCARD); ret = notifier_with_return_list_notify(&bs->before_write_notifiers, &req); if (ret < 0) { goto out; } - max_discard = MIN_NON_ZERO(bs->bl.max_pdiscard >> BDRV_SECTOR_BITS, - BDRV_REQUEST_MAX_SECTORS); - while (nb_sectors > 0) { + max_pdiscard = QEMU_ALIGN_DOWN(MIN_NON_ZERO(bs->bl.max_pdiscard, INT_MAX), + align); + + while (count > 0) { int ret; - int num = nb_sectors; - int discard_alignment = bs->bl.pdiscard_alignment >> BDRV_SECTOR_BITS; - - /* align request */ - if (discard_alignment && - num >= discard_alignment && - sector_num % discard_alignment) { - if (num > discard_alignment) { - num = discard_alignment; - } - num -= sector_num % discard_alignment; - } - - /* limit request size */ - if (num > max_discard) { - num = max_discard; - } + int num = MIN(count, max_pdiscard); if (bs->drv->bdrv_co_discard) { - ret = bs->drv->bdrv_co_discard(bs, sector_num, num); + ret = bs->drv->bdrv_co_discard(bs, offset >> BDRV_SECTOR_BITS, + num >> BDRV_SECTOR_BITS); } else { BlockAIOCB *acb; CoroutineIOCompletion co = { .coroutine = qemu_coroutine_self(), }; - acb = bs->drv->bdrv_aio_discard(bs, sector_num, nb_sectors, + acb = bs->drv->bdrv_aio_discard(bs, offset >> BDRV_SECTOR_BITS, + num >> BDRV_SECTOR_BITS, bdrv_co_io_em_complete, &co); if (acb == NULL) { ret = -EIO; @@ -2480,8 +2483,8 @@ int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num, goto out; } - sector_num += num; - nb_sectors -= num; + offset += num; + count -= num; } ret = 0; out: diff --git a/block/raw_bsd.c b/block/raw_bsd.c index d7674132f2..68f0a91a9a 100644 --- a/block/raw_bsd.c +++ b/block/raw_bsd.c @@ -137,7 +137,8 @@ static int coroutine_fn raw_co_pwrite_zeroes(BlockDriverState *bs, static int coroutine_fn raw_co_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors) { - return bdrv_co_discard(bs->file->bs, sector_num, nb_sectors); + return bdrv_co_pdiscard(bs->file->bs, sector_num << BDRV_SECTOR_BITS, + nb_sectors << BDRV_SECTOR_BITS); } static int64_t raw_getlength(BlockDriverState *bs) diff --git a/include/block/block.h b/include/block/block.h index 616d8b9f12..4f5cebf15f 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -342,7 +342,7 @@ void coroutine_fn bdrv_co_drain(BlockDriverState *bs); void bdrv_drain_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_co_pdiscard(BlockDriverState *bs, int64_t offset, int count); int bdrv_has_zero_init_1(BlockDriverState *bs); int bdrv_has_zero_init(BlockDriverState *bs); bool bdrv_unallocated_blocks_are_zero(BlockDriverState *bs);