From: Tom Yan <tom.t...@gmail.com> We can and should get max transfer length and max segments for all host devices / cdroms (on Linux).
Also use MIN_NON_ZERO instead when we clamp max transfer length against max segments. Signed-off-by: Tom Yan <tom.t...@gmail.com> Signed-off-by: Maxim Levitsky <mlevi...@redhat.com> --- block/file-posix.c | 57 +++++++++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/block/file-posix.c b/block/file-posix.c index 9804681d5c..cbf1271773 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -1166,6 +1166,10 @@ static int sg_get_max_transfer_length(int fd) int max_bytes = 0; if (ioctl(fd, BLKSECTGET, &max_bytes) == 0) { + /* + * BLKSECTGET for /dev/sg* character devices incorrectly returns + * the max transfer size in bytes (rather than in blocks). + */ return max_bytes; } else { return -errno; @@ -1175,7 +1179,22 @@ static int sg_get_max_transfer_length(int fd) #endif } -static int sg_get_max_segments(int fd) +static int get_max_transfer_length(int fd) +{ +#if defined(BLKSECTGET) + int sect = 0; + + if (ioctl(fd, BLKSECTGET, §) == 0) { + return sect << 9; + } else { + return -errno; + } +#else + return -ENOSYS; +#endif +} + +static int get_max_segments(int fd) { #ifdef CONFIG_LINUX char buf[32]; @@ -1230,23 +1249,29 @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp) { BDRVRawState *s = bs->opaque; - if (bs->sg) { - int ret = sg_get_max_transfer_length(s->fd); + raw_probe_alignment(bs, s->fd, errp); + bs->bl.min_mem_alignment = s->buf_align; + bs->bl.opt_mem_alignment = MAX(s->buf_align, qemu_real_host_page_size); +} + +static void hdev_refresh_limits(BlockDriverState *bs, Error **errp) +{ + BDRVRawState *s = bs->opaque; + + int ret = bs->sg ? sg_get_max_transfer_length(s->fd) : + get_max_transfer_length(s->fd); - if (ret > 0 && ret <= BDRV_REQUEST_MAX_BYTES) { - bs->bl.max_transfer = pow2floor(ret); - } + if (ret > 0 && ret <= BDRV_REQUEST_MAX_BYTES) { + bs->bl.max_transfer = pow2floor(ret); + } - ret = sg_get_max_segments(s->fd); - if (ret > 0) { - bs->bl.max_transfer = MIN(bs->bl.max_transfer, - ret * qemu_real_host_page_size); - } + ret = get_max_segments(s->fd); + if (ret > 0) { + bs->bl.max_transfer = MIN_NON_ZERO(bs->bl.max_transfer, + ret * qemu_real_host_page_size); } - raw_probe_alignment(bs, s->fd, errp); - bs->bl.min_mem_alignment = s->buf_align; - bs->bl.opt_mem_alignment = MAX(s->buf_align, qemu_real_host_page_size); + raw_refresh_limits(bs, errp); } static int check_for_dasd(int fd) @@ -3600,7 +3625,7 @@ static BlockDriver bdrv_host_device = { .bdrv_co_pdiscard = hdev_co_pdiscard, .bdrv_co_copy_range_from = raw_co_copy_range_from, .bdrv_co_copy_range_to = raw_co_copy_range_to, - .bdrv_refresh_limits = raw_refresh_limits, + .bdrv_refresh_limits = hdev_refresh_limits, .bdrv_io_plug = raw_aio_plug, .bdrv_io_unplug = raw_aio_unplug, .bdrv_attach_aio_context = raw_aio_attach_aio_context, @@ -3724,7 +3749,7 @@ static BlockDriver bdrv_host_cdrom = { .bdrv_co_preadv = raw_co_preadv, .bdrv_co_pwritev = raw_co_pwritev, .bdrv_co_flush_to_disk = raw_co_flush_to_disk, - .bdrv_refresh_limits = raw_refresh_limits, + .bdrv_refresh_limits = hdev_refresh_limits, .bdrv_io_plug = raw_aio_plug, .bdrv_io_unplug = raw_aio_unplug, .bdrv_attach_aio_context = raw_aio_attach_aio_context, -- 2.26.2