ChangeSet 1.2181.22.3, 2005/03/19 14:46:29-06:00, [EMAIL PROTECTED]

        [PATCH] queue <-> sdev reference counting problem
        
        There is a problem with the way sdev is freed currently. The reason is
        really that there is a circular referencing problem: the sdev needs to
        hold on to the queue, but the queue (through the request function) also
        needs to hold on to the sdev.
        
        The easiest way to work-around this problem is to kill the sdev
        reference in the queue when the sdev is freed. On invocation of
        scsi_request_fn(), kill io to this device.
        
        Signed-off-by: Jens Axboe <[EMAIL PROTECTED]>
        Signed-off-by: James Bottomley <[EMAIL PROTECTED]>



 scsi_lib.c   |   25 ++++++++++++++++++++++++-
 scsi_sysfs.c |    4 +++-
 2 files changed, 27 insertions(+), 2 deletions(-)


diff -Nru a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
--- a/drivers/scsi/scsi_lib.c   2005-03-30 16:06:59 -08:00
+++ b/drivers/scsi/scsi_lib.c   2005-03-30 16:06:59 -08:00
@@ -1233,6 +1233,22 @@
 }
 
 /*
+ * Kill requests for a dead device
+ */
+static void scsi_kill_requests(request_queue_t *q)
+{
+       struct request *req;
+
+       while ((req = elv_next_request(q)) != NULL) {
+               blkdev_dequeue_request(req);
+               req->flags |= REQ_QUIET;
+               while (end_that_request_first(req, 0, req->nr_sectors))
+                       ;
+               end_that_request_last(req);
+       }
+}
+
+/*
  * Function:    scsi_request_fn()
  *
  * Purpose:     Main strategy routine for SCSI.
@@ -1246,10 +1262,16 @@
 static void scsi_request_fn(struct request_queue *q)
 {
        struct scsi_device *sdev = q->queuedata;
-       struct Scsi_Host *shost = sdev->host;
+       struct Scsi_Host *shost;
        struct scsi_cmnd *cmd;
        struct request *req;
 
+       if (!sdev) {
+               printk("scsi: killing requests for dead queue\n");
+               scsi_kill_requests(q);
+               return;
+       }
+
        if(!get_device(&sdev->sdev_gendev))
                /* We must be tearing the block queue down already */
                return;
@@ -1258,6 +1280,7 @@
         * To start with, we keep looping until the queue is empty, or until
         * the host is no longer able to accept any more requests.
         */
+       shost = sdev->host;
        while (!blk_queue_plugged(q)) {
                int rtn;
                /*
diff -Nru a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
--- a/drivers/scsi/scsi_sysfs.c 2005-03-30 16:06:59 -08:00
+++ b/drivers/scsi/scsi_sysfs.c 2005-03-30 16:06:59 -08:00
@@ -168,8 +168,10 @@
        list_del(&sdev->starved_entry);
        spin_unlock_irqrestore(sdev->host->host_lock, flags);
 
-       if (sdev->request_queue)
+       if (sdev->request_queue) {
+               sdev->request_queue->queuedata = NULL;
                scsi_free_queue(sdev->request_queue);
+       }
 
        scsi_target_reap(scsi_target(sdev));
 
-
To unsubscribe from this list: send the line "unsubscribe bk-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to