Skip to content

Commit

Permalink
[SCSI] scsi_lib: don't decrement busy counters when inserting commands
Browse files Browse the repository at this point in the history
A bug was introduced by

commit b60af5b
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: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
  • Loading branch information
James Bottomley authored and James Bottomley committed Jan 5, 2009
1 parent a234b11 commit 4f5299a
Showing 1 changed file with 39 additions and 22 deletions.
61 changes: 39 additions & 22 deletions drivers/scsi/scsi_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,26 +91,19 @@ static void scsi_unprep_request(struct request *req)
scsi_put_command(cmd);
}

/*
* 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.
/**
* __scsi_queue_insert - private queue insertion
* @cmd: The SCSI command being requeued
* @reason: The reason for the requeue
* @unbusy: Whether the queue should be unbusied
*
* This is a private queue insertion. The public interface
* scsi_queue_insert() always assumes the queue should be unbusied
* because it's always called before the completion. This function is
* for a requeue after completion, which should only occur in this
* file.
*/
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_device *device = cmd->device;
Expand Down Expand Up @@ -150,7 +143,8 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
* Decrement the counters, since these commands are no longer
* 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
Expand All @@ -172,6 +166,29 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
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
* @sdev: scsi device
Expand Down Expand Up @@ -1075,11 +1092,11 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
break;
case ACTION_RETRY:
/* Retry the same command immediately */
scsi_queue_insert(cmd, SCSI_MLQUEUE_EH_RETRY);
__scsi_queue_insert(cmd, SCSI_MLQUEUE_EH_RETRY, 0);
break;
case ACTION_DELAYED_RETRY:
/* 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;
}
}
Expand Down

0 comments on commit 4f5299a

Please sign in to comment.