mirror of https://github.com/xemu-project/xemu.git
scsi-generic: Fix emulated block limits VPD page
Commits01ef8185b8
amd24b36e9813
updated the way that the maximum transfer length is calculated for patching block limits VPD page in an INQUIRY response. The same updates also need to be made for the case where the host device does not support the block limits VPD page at all and we emulate the whole page. Without this fix, on host block devices a maximum transfer length of (INT_MAX - sector_size) bytes is advertised to the guest, resulting in I/O errors when a request that exceeds the host limits is made by the guest. (Prior to commit24b36e9813
, this code path would use the max_transfer value from the host instead of INT_MAX, but still miss the fix from01ef8185b8
where max_transfer is also capped to max_iov host pages, so it would be less wrong, but still wrong.) Cc: qemu-stable@nongnu.org Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2096251 Fixes:01ef8185b8
Fixes:24b36e9813
Signed-off-by: Kevin Wolf <kwolf@redhat.com> Message-Id: <20220822125320.48257-1-kwolf@redhat.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
ba58ccbef6
commit
51e15194b0
|
@ -147,6 +147,18 @@ static int execute_command(BlockBackend *blk,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t calculate_max_transfer(SCSIDevice *s)
|
||||
{
|
||||
uint64_t max_transfer = blk_get_max_hw_transfer(s->conf.blk);
|
||||
uint32_t max_iov = blk_get_max_hw_iov(s->conf.blk);
|
||||
|
||||
assert(max_transfer);
|
||||
max_transfer = MIN_NON_ZERO(max_transfer,
|
||||
max_iov * qemu_real_host_page_size());
|
||||
|
||||
return max_transfer / s->blocksize;
|
||||
}
|
||||
|
||||
static int scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s, int len)
|
||||
{
|
||||
uint8_t page, page_idx;
|
||||
|
@ -179,12 +191,7 @@ static int scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s, int len)
|
|||
(r->req.cmd.buf[1] & 0x01)) {
|
||||
page = r->req.cmd.buf[2];
|
||||
if (page == 0xb0) {
|
||||
uint64_t max_transfer = blk_get_max_hw_transfer(s->conf.blk);
|
||||
uint32_t max_iov = blk_get_max_hw_iov(s->conf.blk);
|
||||
|
||||
assert(max_transfer);
|
||||
max_transfer = MIN_NON_ZERO(max_transfer, max_iov * qemu_real_host_page_size())
|
||||
/ s->blocksize;
|
||||
uint64_t max_transfer = calculate_max_transfer(s);
|
||||
stl_be_p(&r->buf[8], max_transfer);
|
||||
/* Also take care of the opt xfer len. */
|
||||
stl_be_p(&r->buf[12],
|
||||
|
@ -230,7 +237,7 @@ static int scsi_generic_emulate_block_limits(SCSIGenericReq *r, SCSIDevice *s)
|
|||
uint8_t buf[64];
|
||||
|
||||
SCSIBlockLimits bl = {
|
||||
.max_io_sectors = blk_get_max_transfer(s->conf.blk) / s->blocksize
|
||||
.max_io_sectors = calculate_max_transfer(s),
|
||||
};
|
||||
|
||||
memset(r->buf, 0, r->buflen);
|
||||
|
|
Loading…
Reference in New Issue