Commit fa8e36c3 authored by James Bottomley's avatar James Bottomley

[SCSI] fix barrier failure issue

Currently, if the barrier command fails, the error return isn't seen
by the block layer and it proceeds on regardless.  The problem is that
SCSI always returns no error for REQ_TYPE_BLOCK_PC ... it expects the
submitter to pick the errors out of req->errors, which the block
barrier functions don't do.

Since it appears that the way SG_IO and scsi_execute_request() work
they discard the block error return and always use req->errors, the
best fix for this is to have the SCSI layer return an error to block
if one actually occurred (this also allows us to filter out spurious
errors, like deferred sense).

This patch is a bug fix that will need backporting to stable, but it's
also quite a big change and in need of testing, so we'll incubate in
the main kernel tree and backport at the -rc2 or so stage if no
problems turn up.
Acked-by: default avatarJens Axboe <jens.axboe@oracle.com>
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
parent bfab1637
...@@ -839,7 +839,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) ...@@ -839,7 +839,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
int this_count = scsi_bufflen(cmd); int this_count = scsi_bufflen(cmd);
struct request_queue *q = cmd->device->request_queue; struct request_queue *q = cmd->device->request_queue;
struct request *req = cmd->request; struct request *req = cmd->request;
int clear_errors = 1; int error = 0;
struct scsi_sense_hdr sshdr; struct scsi_sense_hdr sshdr;
int sense_valid = 0; int sense_valid = 0;
int sense_deferred = 0; int sense_deferred = 0;
...@@ -853,7 +853,6 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) ...@@ -853,7 +853,6 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
if (blk_pc_request(req)) { /* SG_IO ioctl from block level */ if (blk_pc_request(req)) { /* SG_IO ioctl from block level */
req->errors = result; req->errors = result;
if (result) { if (result) {
clear_errors = 0;
if (sense_valid && req->sense) { if (sense_valid && req->sense) {
/* /*
* SG_IO wants current and deferred errors * SG_IO wants current and deferred errors
...@@ -865,6 +864,8 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) ...@@ -865,6 +864,8 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
memcpy(req->sense, cmd->sense_buffer, len); memcpy(req->sense, cmd->sense_buffer, len);
req->sense_len = len; req->sense_len = len;
} }
if (!sense_deferred)
error = -EIO;
} }
if (scsi_bidi_cmnd(cmd)) { if (scsi_bidi_cmnd(cmd)) {
/* will also release_buffers */ /* will also release_buffers */
...@@ -885,14 +886,11 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) ...@@ -885,14 +886,11 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
"%d bytes done.\n", "%d bytes done.\n",
req->nr_sectors, good_bytes)); req->nr_sectors, good_bytes));
if (clear_errors)
req->errors = 0;
/* A number of bytes were successfully read. If there /* A number of bytes were successfully read. If there
* are leftovers and there is some kind of error * are leftovers and there is some kind of error
* (result != 0), retry the rest. * (result != 0), retry the rest.
*/ */
if (scsi_end_request(cmd, 0, good_bytes, result == 0) == NULL) if (scsi_end_request(cmd, error, good_bytes, result == 0) == NULL)
return; return;
/* good_bytes = 0, or (inclusive) there were leftovers and /* good_bytes = 0, or (inclusive) there were leftovers and
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment