Skip to content

Commit 61b6d9b

Browse files
committed
scsi-disk: Apply error policy for host_status errors again
Originally, all failed SG_IO requests called scsi_handle_rw_error() to apply the configured error policy. However, commit f3126d6, which was supposed to be a mere refactoring for scsi-disk.c, broke this and accidentally completed the SCSI request without considering the error policy any more if the error was signalled in the host_status field. Apart from the commit message not describing the change as intended, errors indicated in host_status are also obviously backend errors and not something the guest must deal with independently of the error policy. This behaviour means that some recoverable errors (such as a path error in multipath configurations) were reported to the guest anyway, which might not expect it and might consider its disk broken. Make sure that we apply the error policy again for host_status errors, too. This addresses an existing FIXME comment and allows us to remove some comments warning that callbacks weren't always called. With this fix, they are called in all cases again. The return value passed to the request callback doesn't have more free values that could be used to indicate host_status errors as well as SAM status codes and negative errno. Store the value in the host_status field of the SCSIRequest instead and use -ENODEV as the return value (if a path hasn't been reachable for a while, blk_aio_ioctl() will return -ENODEV instead of just setting host_status, so just reuse it here - it's not necessarily entirely accurate, but it's as good as any errno). Cc: [email protected] Fixes: f3126d6 ('scsi: move host_status handling into SCSI drivers') Signed-off-by: Kevin Wolf <[email protected]> Message-ID: <[email protected]> Reviewed-by: Stefan Hajnoczi <[email protected]> Reviewed-by: Hanna Czenczek <[email protected]> Signed-off-by: Kevin Wolf <[email protected]>
1 parent 8e4ffb4 commit 61b6d9b

File tree

1 file changed

+25
-14
lines changed

1 file changed

+25
-14
lines changed

hw/scsi/scsi-disk.c

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,9 @@ struct SCSIDiskClass {
6868
SCSIDeviceClass parent_class;
6969
/*
7070
* Callbacks receive ret == 0 for success. Errors are represented either as
71-
* negative errno values, or as positive SAM status codes.
72-
*
73-
* Beware: For errors returned in host_status, the function may directly
74-
* complete the request and never call the callback.
71+
* negative errno values, or as positive SAM status codes. For host_status
72+
* errors, the function passes ret == -ENODEV and sets the host_status field
73+
* of the SCSIRequest.
7574
*/
7675
DMAIOFunc *dma_readv;
7776
DMAIOFunc *dma_writev;
@@ -225,11 +224,26 @@ static bool scsi_handle_rw_error(SCSIDiskReq *r, int ret, bool acct_failed)
225224
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
226225
SCSIDiskClass *sdc = (SCSIDiskClass *) object_get_class(OBJECT(s));
227226
SCSISense sense = SENSE_CODE(NO_SENSE);
227+
int16_t host_status;
228228
int error;
229229
bool req_has_sense = false;
230230
BlockErrorAction action;
231231
int status;
232232

233+
/*
234+
* host_status should only be set for SG_IO requests that came back with a
235+
* host_status error in scsi_block_sgio_complete(). This error path passes
236+
* -ENODEV as the return value.
237+
*
238+
* Reset host_status in the request because we may still want to complete
239+
* the request successfully with the 'stop' or 'ignore' error policy.
240+
*/
241+
host_status = r->req.host_status;
242+
if (host_status != -1) {
243+
assert(ret == -ENODEV);
244+
r->req.host_status = -1;
245+
}
246+
233247
if (ret < 0) {
234248
status = scsi_sense_from_errno(-ret, &sense);
235249
error = -ret;
@@ -289,6 +303,10 @@ static bool scsi_handle_rw_error(SCSIDiskReq *r, int ret, bool acct_failed)
289303
if (acct_failed) {
290304
block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct);
291305
}
306+
if (host_status != -1) {
307+
scsi_req_complete_failed(&r->req, host_status);
308+
return true;
309+
}
292310
if (req_has_sense) {
293311
sdc->update_sense(&r->req);
294312
} else if (status == CHECK_CONDITION) {
@@ -409,7 +427,6 @@ static void scsi_dma_complete_noio(SCSIDiskReq *r, int ret)
409427
scsi_req_unref(&r->req);
410428
}
411429

412-
/* May not be called in all error cases, don't rely on cleanup here */
413430
static void scsi_dma_complete(void *opaque, int ret)
414431
{
415432
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
@@ -448,7 +465,6 @@ static void scsi_read_complete_noio(SCSIDiskReq *r, int ret)
448465
scsi_req_unref(&r->req);
449466
}
450467

451-
/* May not be called in all error cases, don't rely on cleanup here */
452468
static void scsi_read_complete(void *opaque, int ret)
453469
{
454470
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
@@ -585,7 +601,6 @@ static void scsi_write_complete_noio(SCSIDiskReq *r, int ret)
585601
scsi_req_unref(&r->req);
586602
}
587603

588-
/* May not be called in all error cases, don't rely on cleanup here */
589604
static void scsi_write_complete(void * opaque, int ret)
590605
{
591606
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
@@ -2846,14 +2861,10 @@ static void scsi_block_sgio_complete(void *opaque, int ret)
28462861
sg_io_hdr_t *io_hdr = &req->io_header;
28472862

28482863
if (ret == 0) {
2849-
/* FIXME This skips calling req->cb() and any cleanup in it */
28502864
if (io_hdr->host_status != SCSI_HOST_OK) {
2851-
scsi_req_complete_failed(&r->req, io_hdr->host_status);
2852-
scsi_req_unref(&r->req);
2853-
return;
2854-
}
2855-
2856-
if (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT) {
2865+
r->req.host_status = io_hdr->host_status;
2866+
ret = -ENODEV;
2867+
} else if (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT) {
28572868
ret = BUSY;
28582869
} else {
28592870
ret = io_hdr->status;

0 commit comments

Comments
 (0)