@@ -163,11 +163,23 @@ struct BlockDriver {
*/
int coroutine_fn (*bdrv_co_pwrite_zeroes)(BlockDriverState *bs,
int64_t offset, int count, BdrvRequestFlags flags);
+
int coroutine_fn (*bdrv_co_pdiscard)(BlockDriverState *bs,
int64_t offset, int count);
+
+ /*
+ * Building block for bdrv_block_status[_above]. The block layer
+ * guarantees input aligned to request_alignment, as well as
+ * non-NULL pnum and file; and the result only has to worry about
+ * BDRV_BLOCK_DATA, _ZERO, _OFFSET_VALID, and _RAW, and only
+ * according to the current BDS.
+ */
int64_t coroutine_fn (*bdrv_co_get_block_status)(BlockDriverState *bs,
int64_t sector_num, int nb_sectors, int *pnum,
BlockDriverState **file);
+ int64_t coroutine_fn (*bdrv_co_block_status)(BlockDriverState *bd,
+ int64_t offset, int64_t bytes, int64_t *pnum,
+ BlockDriverState **file);
/*
* Invalidate any cached meta-data.
@@ -1718,7 +1718,6 @@ static int64_t coroutine_fn bdrv_co_block_status(BlockDriverState *bs,
int64_t total_size;
int64_t n; /* bytes */
int64_t ret, ret2;
- int count; /* sectors */
BlockDriverState *tmp_file;
total_size = bdrv_getlength(bs);
@@ -1739,7 +1738,7 @@ static int64_t coroutine_fn bdrv_co_block_status(BlockDriverState *bs,
bytes = n;
}
- if (!bs->drv->bdrv_co_get_block_status) {
+ if (!bs->drv->bdrv_co_get_block_status && !bs->drv->bdrv_co_block_status) {
*pnum = bytes;
ret = BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED;
if (bs->drv->protocol_name) {
@@ -1753,20 +1752,44 @@ static int64_t coroutine_fn bdrv_co_block_status(BlockDriverState *bs,
}
*file = NULL;
bdrv_inc_in_flight(bs);
- /* TODO: Rather than require aligned offsets, we could instead
- * round to the driver's request_alignment here, then touch up
- * count afterwards back to the caller's expectations. But first
- * we want to switch the driver callback to likewise be
- * byte-based. */
- assert(QEMU_IS_ALIGNED(offset | bytes, BDRV_SECTOR_SIZE));
- ret = bs->drv->bdrv_co_get_block_status(bs, offset >> BDRV_SECTOR_BITS,
- bytes >> BDRV_SECTOR_BITS, &count,
- file);
+ if (bs->drv->bdrv_co_get_block_status) {
+ int count; /* sectors */
+
+ assert(QEMU_IS_ALIGNED(offset | bytes, BDRV_SECTOR_SIZE));
+ ret = bs->drv->bdrv_co_get_block_status(bs, offset >> BDRV_SECTOR_BITS,
+ bytes >> BDRV_SECTOR_BITS,
+ &count, file);
+ *pnum = count * BDRV_SECTOR_SIZE;
+ } else {
+ /* Round out to request_alignment boundaries */
+ int64_t aligned_offset, aligned_bytes;
+
+ aligned_offset = QEMU_ALIGN_DOWN(offset, bs->bl.request_alignment);
+ aligned_bytes = ROUND_UP(offset + bytes,
+ bs->bl.request_alignment) - aligned_offset;
+ ret = bs->drv->bdrv_co_block_status(bs, aligned_offset, aligned_bytes,
+ &n, file);
+ /* Clamp pnum and ret to original request */
+ if (aligned_offset != offset && ret >= 0) {
+ int sectors = DIV_ROUND_UP(offset, BDRV_SECTOR_SIZE) -
+ DIV_ROUND_UP(aligned_offset, BDRV_SECTOR_SIZE);
+
+ assert(n >= offset - aligned_offset);
+ n -= offset - aligned_offset;
+ if (sectors) {
+ ret += sectors * BDRV_SECTOR_SIZE;
+ }
+ }
+ if (ret >= 0 && n > bytes) {
+ assert(aligned_bytes != bytes);
+ n = bytes;
+ }
+ *pnum = n;
+ }
if (ret < 0) {
*pnum = 0;
goto out;
}
- *pnum = count * BDRV_SECTOR_SIZE;
if (ret & BDRV_BLOCK_RAW) {
assert(ret & BDRV_BLOCK_OFFSET_VALID);
We are gradually moving away from sector-based interfaces, towards byte-based. Now that the block layer exposes byte-based allocation, it's time to tackle the drivers. Add a new callback that operates on as small as byte boundaries, and update the block layer to ensure that the callback is only used with inputs aligned to the device's request_alignment. Subsequent patches will then update individual drivers, and then finally remove .bdrv_co_get_block_status(). Signed-off-by: Eric Blake <eblake@redhat.com> --- include/block/block_int.h | 12 ++++++++++++ block/io.c | 47 +++++++++++++++++++++++++++++++++++------------ 2 files changed, 47 insertions(+), 12 deletions(-)