scsi: make io_timeout configurable
The current code sets an infinite timeout on SG_IO requests, causing the guest to stall if the host experiences a frame loss. This patch adds an 'io_timeout' parameter for SCSIDevice to make the SG_IO timeout configurable, and also shortens the default timeout to 30 seconds to avoid infinite stalls. Signed-off-by: Hannes Reinecke <hare@suse.de> Message-Id: <20201116183114.55703-3-hare@suse.de> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
106ad1f9c5
commit
c9b6609b69
@ -2624,7 +2624,7 @@ static int get_device_type(SCSIDiskState *s)
|
|||||||
cmd[4] = sizeof(buf);
|
cmd[4] = sizeof(buf);
|
||||||
|
|
||||||
ret = scsi_SG_IO_FROM_DEV(s->qdev.conf.blk, cmd, sizeof(cmd),
|
ret = scsi_SG_IO_FROM_DEV(s->qdev.conf.blk, cmd, sizeof(cmd),
|
||||||
buf, sizeof(buf));
|
buf, sizeof(buf), s->qdev.io_timeout);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -2785,7 +2785,7 @@ static BlockAIOCB *scsi_block_do_sgio(SCSIBlockReq *req,
|
|||||||
/* The rest is as in scsi-generic.c. */
|
/* The rest is as in scsi-generic.c. */
|
||||||
io_header->mx_sb_len = sizeof(r->req.sense);
|
io_header->mx_sb_len = sizeof(r->req.sense);
|
||||||
io_header->sbp = r->req.sense;
|
io_header->sbp = r->req.sense;
|
||||||
io_header->timeout = UINT_MAX;
|
io_header->timeout = s->qdev.io_timeout * 1000;
|
||||||
io_header->usr_ptr = r;
|
io_header->usr_ptr = r;
|
||||||
io_header->flags |= SG_FLAG_DIRECT_IO;
|
io_header->flags |= SG_FLAG_DIRECT_IO;
|
||||||
|
|
||||||
@ -3103,6 +3103,8 @@ static Property scsi_block_properties[] = {
|
|||||||
DEFAULT_MAX_IO_SIZE),
|
DEFAULT_MAX_IO_SIZE),
|
||||||
DEFINE_PROP_INT32("scsi_version", SCSIDiskState, qdev.default_scsi_version,
|
DEFINE_PROP_INT32("scsi_version", SCSIDiskState, qdev.default_scsi_version,
|
||||||
-1),
|
-1),
|
||||||
|
DEFINE_PROP_UINT32("io_timeout", SCSIDiskState, qdev.io_timeout,
|
||||||
|
DEFAULT_IO_TIMEOUT),
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -115,6 +115,8 @@ static int execute_command(BlockBackend *blk,
|
|||||||
SCSIGenericReq *r, int direction,
|
SCSIGenericReq *r, int direction,
|
||||||
BlockCompletionFunc *complete)
|
BlockCompletionFunc *complete)
|
||||||
{
|
{
|
||||||
|
SCSIDevice *s = r->req.dev;
|
||||||
|
|
||||||
r->io_header.interface_id = 'S';
|
r->io_header.interface_id = 'S';
|
||||||
r->io_header.dxfer_direction = direction;
|
r->io_header.dxfer_direction = direction;
|
||||||
r->io_header.dxferp = r->buf;
|
r->io_header.dxferp = r->buf;
|
||||||
@ -123,7 +125,7 @@ static int execute_command(BlockBackend *blk,
|
|||||||
r->io_header.cmd_len = r->req.cmd.len;
|
r->io_header.cmd_len = r->req.cmd.len;
|
||||||
r->io_header.mx_sb_len = sizeof(r->req.sense);
|
r->io_header.mx_sb_len = sizeof(r->req.sense);
|
||||||
r->io_header.sbp = r->req.sense;
|
r->io_header.sbp = r->req.sense;
|
||||||
r->io_header.timeout = MAX_UINT;
|
r->io_header.timeout = s->io_timeout * 1000;
|
||||||
r->io_header.usr_ptr = r;
|
r->io_header.usr_ptr = r;
|
||||||
r->io_header.flags |= SG_FLAG_DIRECT_IO;
|
r->io_header.flags |= SG_FLAG_DIRECT_IO;
|
||||||
|
|
||||||
@ -506,7 +508,7 @@ static int read_naa_id(const uint8_t *p, uint64_t *p_wwn)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int scsi_SG_IO_FROM_DEV(BlockBackend *blk, uint8_t *cmd, uint8_t cmd_size,
|
int scsi_SG_IO_FROM_DEV(BlockBackend *blk, uint8_t *cmd, uint8_t cmd_size,
|
||||||
uint8_t *buf, uint8_t buf_size)
|
uint8_t *buf, uint8_t buf_size, uint32_t timeout)
|
||||||
{
|
{
|
||||||
sg_io_hdr_t io_header;
|
sg_io_hdr_t io_header;
|
||||||
uint8_t sensebuf[8];
|
uint8_t sensebuf[8];
|
||||||
@ -521,7 +523,7 @@ int scsi_SG_IO_FROM_DEV(BlockBackend *blk, uint8_t *cmd, uint8_t cmd_size,
|
|||||||
io_header.cmd_len = cmd_size;
|
io_header.cmd_len = cmd_size;
|
||||||
io_header.mx_sb_len = sizeof(sensebuf);
|
io_header.mx_sb_len = sizeof(sensebuf);
|
||||||
io_header.sbp = sensebuf;
|
io_header.sbp = sensebuf;
|
||||||
io_header.timeout = 6000; /* XXX */
|
io_header.timeout = timeout * 1000;
|
||||||
|
|
||||||
ret = blk_ioctl(blk, SG_IO, &io_header);
|
ret = blk_ioctl(blk, SG_IO, &io_header);
|
||||||
if (ret < 0 || io_header.driver_status || io_header.host_status) {
|
if (ret < 0 || io_header.driver_status || io_header.host_status) {
|
||||||
@ -551,7 +553,7 @@ static void scsi_generic_set_vpd_bl_emulation(SCSIDevice *s)
|
|||||||
cmd[4] = sizeof(buf);
|
cmd[4] = sizeof(buf);
|
||||||
|
|
||||||
ret = scsi_SG_IO_FROM_DEV(s->conf.blk, cmd, sizeof(cmd),
|
ret = scsi_SG_IO_FROM_DEV(s->conf.blk, cmd, sizeof(cmd),
|
||||||
buf, sizeof(buf));
|
buf, sizeof(buf), s->io_timeout);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
/*
|
/*
|
||||||
* Do not assume anything if we can't retrieve the
|
* Do not assume anything if we can't retrieve the
|
||||||
@ -587,7 +589,7 @@ static void scsi_generic_read_device_identification(SCSIDevice *s)
|
|||||||
cmd[4] = sizeof(buf);
|
cmd[4] = sizeof(buf);
|
||||||
|
|
||||||
ret = scsi_SG_IO_FROM_DEV(s->conf.blk, cmd, sizeof(cmd),
|
ret = scsi_SG_IO_FROM_DEV(s->conf.blk, cmd, sizeof(cmd),
|
||||||
buf, sizeof(buf));
|
buf, sizeof(buf), s->io_timeout);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -638,7 +640,7 @@ static int get_stream_blocksize(BlockBackend *blk)
|
|||||||
cmd[0] = MODE_SENSE;
|
cmd[0] = MODE_SENSE;
|
||||||
cmd[4] = sizeof(buf);
|
cmd[4] = sizeof(buf);
|
||||||
|
|
||||||
ret = scsi_SG_IO_FROM_DEV(blk, cmd, sizeof(cmd), buf, sizeof(buf));
|
ret = scsi_SG_IO_FROM_DEV(blk, cmd, sizeof(cmd), buf, sizeof(buf), 6);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -728,6 +730,7 @@ static void scsi_generic_realize(SCSIDevice *s, Error **errp)
|
|||||||
|
|
||||||
/* Only used by scsi-block, but initialize it nevertheless to be clean. */
|
/* Only used by scsi-block, but initialize it nevertheless to be clean. */
|
||||||
s->default_scsi_version = -1;
|
s->default_scsi_version = -1;
|
||||||
|
s->io_timeout = DEFAULT_IO_TIMEOUT;
|
||||||
scsi_generic_read_device_inquiry(s);
|
scsi_generic_read_device_inquiry(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -751,6 +754,8 @@ static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
|
|||||||
static Property scsi_generic_properties[] = {
|
static Property scsi_generic_properties[] = {
|
||||||
DEFINE_PROP_DRIVE("drive", SCSIDevice, conf.blk),
|
DEFINE_PROP_DRIVE("drive", SCSIDevice, conf.blk),
|
||||||
DEFINE_PROP_BOOL("share-rw", SCSIDevice, conf.share_rw, false),
|
DEFINE_PROP_BOOL("share-rw", SCSIDevice, conf.share_rw, false),
|
||||||
|
DEFINE_PROP_UINT32("io_timeout", SCSIDevice, io_timeout,
|
||||||
|
DEFAULT_IO_TIMEOUT),
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ typedef struct SCSIReqOps SCSIReqOps;
|
|||||||
|
|
||||||
#define SCSI_SENSE_BUF_SIZE_OLD 96
|
#define SCSI_SENSE_BUF_SIZE_OLD 96
|
||||||
#define SCSI_SENSE_BUF_SIZE 252
|
#define SCSI_SENSE_BUF_SIZE 252
|
||||||
|
#define DEFAULT_IO_TIMEOUT 30
|
||||||
|
|
||||||
struct SCSIRequest {
|
struct SCSIRequest {
|
||||||
SCSIBus *bus;
|
SCSIBus *bus;
|
||||||
@ -84,6 +85,7 @@ struct SCSIDevice
|
|||||||
uint64_t port_wwn;
|
uint64_t port_wwn;
|
||||||
int scsi_version;
|
int scsi_version;
|
||||||
int default_scsi_version;
|
int default_scsi_version;
|
||||||
|
uint32_t io_timeout;
|
||||||
bool needs_vpd_bl_emulation;
|
bool needs_vpd_bl_emulation;
|
||||||
bool hba_supports_iothread;
|
bool hba_supports_iothread;
|
||||||
};
|
};
|
||||||
@ -188,7 +190,7 @@ void scsi_device_unit_attention_reported(SCSIDevice *dev);
|
|||||||
void scsi_generic_read_device_inquiry(SCSIDevice *dev);
|
void scsi_generic_read_device_inquiry(SCSIDevice *dev);
|
||||||
int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed);
|
int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed);
|
||||||
int scsi_SG_IO_FROM_DEV(BlockBackend *blk, uint8_t *cmd, uint8_t cmd_size,
|
int scsi_SG_IO_FROM_DEV(BlockBackend *blk, uint8_t *cmd, uint8_t cmd_size,
|
||||||
uint8_t *buf, uint8_t buf_size);
|
uint8_t *buf, uint8_t buf_size, uint32_t timeout);
|
||||||
SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int target, int lun);
|
SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int target, int lun);
|
||||||
SCSIDevice *scsi_device_get(SCSIBus *bus, int channel, int target, int lun);
|
SCSIDevice *scsi_device_get(SCSIBus *bus, int channel, int target, int lun);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user