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> --- v2: fix get_max_transfer_length for non-sg devices; also add/fix sg_get_max_segments for sg devices block/file-posix.c | 56 +++++++++++++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/block/file-posix.c b/block/file-posix.c index 9a00d4190a..0c9124c8aa 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -1178,7 +1178,23 @@ 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) && defined(BLKSSZGET) + int sect = 0; + int ssz = 0; + + if (ioctl(fd, BLKSECTGET, §) == 0 && ioctl(fd, BLKSSZGET, &ssz)) { + return sect * ssz; + } else { + return -errno; + } +#else + return -ENOSYS; +#endif +} + +static int get_max_segments(int fd) { #ifdef CONFIG_LINUX char buf[32]; @@ -1233,23 +1249,31 @@ 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; + + /* BLKSECTGET has always been implemented wrongly in the sg driver + and BLKSSZGET has never been supported by it*/ + 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) @@ -3604,7 +3628,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, @@ -3728,7 +3752,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.28.0