Message ID | 20201217165612.942849-3-mlevitsk@redhat.com |
---|---|
State | New |
Headers | show |
Series | SCSI: fix transfer limits for SCSI passthrough | expand |
On 17.12.20 17:56, Maxim Levitsky wrote: > From: Tom Yan <tom.ty89@gmail.com> > > sg devices have different major/minor than their corresponding > block devices. Using sysfs to get max segments never really worked > for them. > > Fortunately the sg driver provides an ioctl to get sg_tablesize, > which is apparently equivalent to max segments. > > Signed-off-by: Tom Yan <tom.ty89@gmail.com> > Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com> > --- > block/file-posix.c | 22 +++++++++++++++++++++- > 1 file changed, 21 insertions(+), 1 deletion(-) > > diff --git a/block/file-posix.c b/block/file-posix.c > index cbf1271773..2bf4d095a7 100644 > --- a/block/file-posix.c > +++ b/block/file-posix.c > @@ -1179,6 +1179,26 @@ static int sg_get_max_transfer_length(int fd) > #endif > } > > +static int sg_get_max_segments(int fd) > +{ > + /* > + * /dev/sg* character devices report 'max_segments' via > + * SG_GET_SG_TABLESIZE ioctl > + */ > + > +#ifdef SG_GET_SG_TABLESIZE > + long max_segments = 0; > + > + if (ioctl(fd, SG_GET_SG_TABLESIZE, &max_segments) == 0) { As far as I can tell from googling, SG_GET_SG_TABLESIZE takes an int pointer. Apart from that, looks good. Max > + return max_segments; > + } else { > + return -errno; > + } > +#else > + return -ENOSYS; > +#endif > +} > + > static int get_max_transfer_length(int fd) > { > #if defined(BLKSECTGET) > @@ -1265,7 +1285,7 @@ static void hdev_refresh_limits(BlockDriverState *bs, Error **errp) > bs->bl.max_transfer = pow2floor(ret); > } > > - ret = get_max_segments(s->fd); > + ret = bs->sg ? sg_get_max_segments(s->fd) : 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); >
diff --git a/block/file-posix.c b/block/file-posix.c index cbf1271773..2bf4d095a7 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -1179,6 +1179,26 @@ static int sg_get_max_transfer_length(int fd) #endif } +static int sg_get_max_segments(int fd) +{ + /* + * /dev/sg* character devices report 'max_segments' via + * SG_GET_SG_TABLESIZE ioctl + */ + +#ifdef SG_GET_SG_TABLESIZE + long max_segments = 0; + + if (ioctl(fd, SG_GET_SG_TABLESIZE, &max_segments) == 0) { + return max_segments; + } else { + return -errno; + } +#else + return -ENOSYS; +#endif +} + static int get_max_transfer_length(int fd) { #if defined(BLKSECTGET) @@ -1265,7 +1285,7 @@ static void hdev_refresh_limits(BlockDriverState *bs, Error **errp) bs->bl.max_transfer = pow2floor(ret); } - ret = get_max_segments(s->fd); + ret = bs->sg ? sg_get_max_segments(s->fd) : 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);