Commit 4f5299ac authored by James Bottomley's avatar James Bottomley

[SCSI] scsi_lib: don't decrement busy counters when inserting commands

A bug was introduced by

commit b60af5b0
Author: Alan Stern <stern@rowland.harvard.edu>
Date:   Mon Nov 3 15:56:47 2008 -0500

    [SCSI] simplify scsi_io_completion()
 
because the simplification uses scsi_queue_insert().  The problem with
this function is that it expects to be called from the completion path
while the command is still outstanding, so it decrements the device
and host busy counts to do the requeue.  The problem is that
scsi_io_completion() is a path executed well after these counts have
*already* been decremented, leading to a double decrement if the
command goes down any error path leading to ACTION_DELAYED_RETRY.

The fix is to allow a private function __scsi_queue_insert() with a
flag to say whether the busy counters should be decremented.  This is
made static to scsi_lib.c to discourage other use.
Reported-by: default avatarMike Christie <michaelc@cs.wisc.edu>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
parent a234b110
...@@ -91,26 +91,19 @@ static void scsi_unprep_request(struct request *req) ...@@ -91,26 +91,19 @@ static void scsi_unprep_request(struct request *req)
scsi_put_command(cmd); scsi_put_command(cmd);
} }
/* /**
* Function: scsi_queue_insert() * __scsi_queue_insert - private queue insertion
* * @cmd: The SCSI command being requeued
* Purpose: Insert a command in the midlevel queue. * @reason: The reason for the requeue
* * @unbusy: Whether the queue should be unbusied
* Arguments: cmd - command that we are adding to queue. *
* reason - why we are inserting command to queue. * This is a private queue insertion. The public interface
* * scsi_queue_insert() always assumes the queue should be unbusied
* Lock status: Assumed that lock is not held upon entry. * because it's always called before the completion. This function is
* * for a requeue after completion, which should only occur in this
* Returns: Nothing. * file.
*
* Notes: We do this for one of two cases. Either the host is busy
* and it cannot accept any more commands for the time being,
* or the device returned QUEUE_FULL and can accept no more
* commands.
* Notes: This could be called either from an interrupt context or a
* normal process context.
*/ */
int scsi_queue_insert(struct scsi_cmnd *cmd, int reason) static int __scsi_queue_insert(struct scsi_cmnd *cmd, int reason, int unbusy)
{ {
struct Scsi_Host *host = cmd->device->host; struct Scsi_Host *host = cmd->device->host;
struct scsi_device *device = cmd->device; struct scsi_device *device = cmd->device;
...@@ -150,7 +143,8 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason) ...@@ -150,7 +143,8 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
* Decrement the counters, since these commands are no longer * Decrement the counters, since these commands are no longer
* active on the host/device. * active on the host/device.
*/ */
scsi_device_unbusy(device); if (unbusy)
scsi_device_unbusy(device);
/* /*
* Requeue this command. It will go before all other commands * Requeue this command. It will go before all other commands
...@@ -172,6 +166,29 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason) ...@@ -172,6 +166,29 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
return 0; return 0;
} }
/*
* Function: scsi_queue_insert()
*
* Purpose: Insert a command in the midlevel queue.
*
* Arguments: cmd - command that we are adding to queue.
* reason - why we are inserting command to queue.
*
* Lock status: Assumed that lock is not held upon entry.
*
* Returns: Nothing.
*
* Notes: We do this for one of two cases. Either the host is busy
* and it cannot accept any more commands for the time being,
* or the device returned QUEUE_FULL and can accept no more
* commands.
* Notes: This could be called either from an interrupt context or a
* normal process context.
*/
int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
{
return __scsi_queue_insert(cmd, reason, 1);
}
/** /**
* scsi_execute - insert request and wait for the result * scsi_execute - insert request and wait for the result
* @sdev: scsi device * @sdev: scsi device
...@@ -1075,11 +1092,11 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) ...@@ -1075,11 +1092,11 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
break; break;
case ACTION_RETRY: case ACTION_RETRY:
/* Retry the same command immediately */ /* Retry the same command immediately */
scsi_queue_insert(cmd, SCSI_MLQUEUE_EH_RETRY); __scsi_queue_insert(cmd, SCSI_MLQUEUE_EH_RETRY, 0);
break; break;
case ACTION_DELAYED_RETRY: case ACTION_DELAYED_RETRY:
/* Retry the same command after a delay */ /* Retry the same command after a delay */
scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY); __scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY, 0);
break; break;
} }
} }
......
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