diff options
author | Mike Christie <michaelc@cs.wisc.edu> | 2012-01-26 22:13:11 -0500 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-02-19 09:09:00 -0500 |
commit | e3d338a536330b5ffc9f28d7c6a4cdf6ba51867a (patch) | |
tree | 6c49d84c7ac6e73ab2b3fbfbceaedcdcb2529f72 /drivers/scsi/libiscsi.c | |
parent | 1304be5fe0efb42b7ec6a50dd8e1a9bce2adae17 (diff) |
[SCSI] libiscsi: fix cmd timeout/completion race
If the driver/lib has called scsi_done and cleaned up internally but
scsi layer has not yet called blk_mark_rq_complete when the command
times out we hit a problem if the timeout code calls blk_mark_rq_complete first.
When the time out code calls into the driver we were returning
BLK_EH_RESET_TIMER and that causes the timeout code to just call
us again later.
We need to be calling BLK_EH_HANDLED so the timeout code can complete
the completion process because it had called blk_mark_rq_complete
on the command and now owns its processing.
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/libiscsi.c')
-rw-r--r-- | drivers/scsi/libiscsi.c | 20 |
1 files changed, 10 insertions, 10 deletions
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 8582d7c25732..82c3fd4bc938 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c | |||
@@ -1909,6 +1909,16 @@ static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc) | |||
1909 | ISCSI_DBG_EH(session, "scsi cmd %p timedout\n", sc); | 1909 | ISCSI_DBG_EH(session, "scsi cmd %p timedout\n", sc); |
1910 | 1910 | ||
1911 | spin_lock(&session->lock); | 1911 | spin_lock(&session->lock); |
1912 | task = (struct iscsi_task *)sc->SCp.ptr; | ||
1913 | if (!task) { | ||
1914 | /* | ||
1915 | * Raced with completion. Blk layer has taken ownership | ||
1916 | * so let timeout code complete it now. | ||
1917 | */ | ||
1918 | rc = BLK_EH_HANDLED; | ||
1919 | goto done; | ||
1920 | } | ||
1921 | |||
1912 | if (session->state != ISCSI_STATE_LOGGED_IN) { | 1922 | if (session->state != ISCSI_STATE_LOGGED_IN) { |
1913 | /* | 1923 | /* |
1914 | * We are probably in the middle of iscsi recovery so let | 1924 | * We are probably in the middle of iscsi recovery so let |
@@ -1925,16 +1935,6 @@ static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc) | |||
1925 | goto done; | 1935 | goto done; |
1926 | } | 1936 | } |
1927 | 1937 | ||
1928 | task = (struct iscsi_task *)sc->SCp.ptr; | ||
1929 | if (!task) { | ||
1930 | /* | ||
1931 | * Raced with completion. Just reset timer, and let it | ||
1932 | * complete normally | ||
1933 | */ | ||
1934 | rc = BLK_EH_RESET_TIMER; | ||
1935 | goto done; | ||
1936 | } | ||
1937 | |||
1938 | /* | 1938 | /* |
1939 | * If we have sent (at least queued to the network layer) a pdu or | 1939 | * If we have sent (at least queued to the network layer) a pdu or |
1940 | * recvd one for the task since the last timeout ask for | 1940 | * recvd one for the task since the last timeout ask for |