When a timer requeue a request, it clears out REQ_ATOM_COMPLETE bit.
Hence if there is an in-flight scmd asks scsi-eh to handle an error by
joining the eh_entry list, then when scsi_error_handler() handles a scmd,
the scmd->request may be still on request_queue.  This will trigger
the BUG_ON(!list_empty(&req->queuelist)) in __blk_put_request().

Signed-off-by: Liu Ping Fan <[email protected]>
---
note: I hit this bug in my test, and the above comment is my guess. Hope for
more comments about it.

---
 block/blk.h               |  1 -
 drivers/scsi/scsi_error.c |  1 +
 drivers/scsi/scsi_lib.c   | 20 +++++++++++++++++++-
 drivers/scsi/scsi_priv.h  |  1 +
 include/linux/blkdev.h    |  1 +
 5 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/block/blk.h b/block/blk.h
index c90e1d8..a9cad62 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -29,7 +29,6 @@ int blk_rq_append_bio(struct request_queue *q, struct request 
*rq,
                      struct bio *bio);
 void blk_queue_bypass_start(struct request_queue *q);
 void blk_queue_bypass_end(struct request_queue *q);
-void blk_dequeue_request(struct request *rq);
 void __blk_queue_free_tags(struct request_queue *q);
 bool __blk_end_bidi_request(struct request *rq, int error,
                            unsigned int nr_bytes, unsigned int bidi_bytes);
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index c5f49cf..3b8b95b 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -2068,6 +2068,7 @@ void scsi_eh_flush_done_q(struct list_head *done_q)
                        SCSI_LOG_ERROR_RECOVERY(3, printk("%s: flush finish"
                                                        " cmd: %p\n",
                                                        current->comm, scmd));
+                       scsi_queue_dequeue(scmd);
                        scsi_finish_command(scmd);
                }
        }
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 7fb2afe..e117579 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -210,6 +210,21 @@ void scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
 {
        __scsi_queue_insert(cmd, reason, 1);
 }
+
+void scsi_queue_dequeue(struct scsi_cmnd *cmd)
+{
+       struct scsi_device *device = cmd->device;
+       struct request_queue *q = device->request_queue;
+       struct request *req = cmd->request;
+       unsigned long flags;
+
+       if (list_empty(&cmd->request->queuelist))
+               return;
+       spin_lock_irqsave(q->queue_lock, flags);
+       blk_dequeue_request(req);
+       spin_unlock_irqrestore(q->queue_lock, flags);
+}
+
 /**
  * scsi_execute - insert request and wait for the result
  * @sdev:      scsi device
@@ -859,6 +874,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int 
good_bytes)
                         */
                        req->next_rq->resid_len = scsi_in(cmd)->resid;
 
+                       scsi_queue_dequeue(cmd);
                        scsi_release_buffers(cmd);
                        blk_end_request_all(req, 0);
 
@@ -1038,8 +1054,10 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned 
int good_bytes)
                }
                if (blk_end_request_err(req, error))
                        scsi_requeue_command(q, cmd);
-               else
+               else {
+                       scsi_queue_dequeue(cmd);
                        scsi_next_command(cmd);
+               }
                break;
        case ACTION_REPREP:
                /* Unprep the request and put it back at the head of the queue.
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index f079a59..601b964 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -84,6 +84,7 @@ int scsi_noretry_cmd(struct scsi_cmnd *scmd);
 extern int scsi_maybe_unblock_host(struct scsi_device *sdev);
 extern void scsi_device_unbusy(struct scsi_device *sdev);
 extern void scsi_queue_insert(struct scsi_cmnd *cmd, int reason);
+extern void scsi_queue_dequeue(struct scsi_cmnd *cmd);
 extern void scsi_next_command(struct scsi_cmnd *cmd);
 extern void scsi_io_completion(struct scsi_cmnd *, unsigned int);
 extern void scsi_run_host_queues(struct Scsi_Host *shost);
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 8168524..ee7ddcd 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -916,6 +916,7 @@ static inline unsigned int blk_rq_count_bios(struct request 
*rq)
  */
 extern struct request *blk_peek_request(struct request_queue *q);
 extern void blk_start_request(struct request *rq);
+extern void blk_dequeue_request(struct request *rq);
 extern struct request *blk_fetch_request(struct request_queue *q);
 
 /*
-- 
1.8.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to