]> git.hungrycats.org Git - linux/commitdiff
[PATCH] fix scsi oops on failed sg table allocation
authorJens Axboe <axboe@suse.de>
Fri, 17 May 2002 17:02:37 +0000 (10:02 -0700)
committerLinus Torvalds <torvalds@home.transmeta.com>
Fri, 17 May 2002 17:02:37 +0000 (10:02 -0700)
This patch fixes the deliberate BUG_ON() on failed sgtable allocations.
I left that in because I was too lazy to fix it at the time...

Basically make scsi_init_io() return 0 on failure (like before) but this
time allow us to recover. scsi_init_io() will end_request on a fatal
condition. So now just mark the device/host as starved if needed, and
leave the request at the front of the queue for next service.

drivers/scsi/scsi_lib.c
drivers/scsi/scsi_merge.c

index 66f21a37291efbd63423dae260bb128e612b1f62..5aed6474d1ab6b700c4ea72d6caefe238d367148 100644 (file)
@@ -963,21 +963,22 @@ void scsi_request_fn(request_queue_t * q)
 
                        /* 
                         * This sets up the scatter-gather table (allocating if
-                        * required).  Hosts that need bounce buffers will also
-                        * get those allocated here.  
+                        * required).
                         */
                        if (!scsi_init_io(SCpnt)) {
-                               SCpnt = __scsi_end_request(SCpnt, 0, 
-                                                          SCpnt->request.nr_sectors, 0, 0);
-                               if( SCpnt != NULL )
-                               {
-                                       panic("Should not have leftover blocks\n");
-                               }
                                spin_lock_irq(q->queue_lock);
                                SHpnt->host_busy--;
                                SDpnt->device_busy--;
-                               continue;
+                               if (SDpnt->device_busy == 0) {
+                                       SDpnt->starved = 1;
+                                       SHpnt->some_device_starved = 1;
+                               }
+                               SCpnt->request.special = SCpnt;
+                               SCpnt->request.flags |= REQ_SPECIAL;
+                               _elv_add_request(q, &SCpnt->request, 0, 0);
+                               break;
                        }
+
                        /*
                         * Initialize the actual SCSI command for this request.
                         */
index d462dd1c0db51e3ee1b65fff925b08ef331f47a3..cec944e1cd64a4d689e536d8ff1b218074acdf2e 100644 (file)
@@ -78,8 +78,12 @@ int scsi_init_io(Scsi_Cmnd *SCpnt)
        if (in_interrupt())
                gfp_mask &= ~__GFP_WAIT;
 
+       /*
+        * if sg table allocation fails, requeue request later.
+        */
        sgpnt = scsi_alloc_sgtable(SCpnt, gfp_mask);
-       BUG_ON(!sgpnt);
+       if (!sgpnt)
+               return 0;
 
        SCpnt->request_buffer = (char *) sgpnt;
        SCpnt->request_bufflen = req->nr_sectors << 9;
@@ -102,8 +106,13 @@ int scsi_init_io(Scsi_Cmnd *SCpnt)
        printk("Incorrect number of segments after building list\n");
        printk("counted %d, received %d\n", count, SCpnt->use_sg);
        printk("req nr_sec %lu, cur_nr_sec %u\n", req->nr_sectors, req->current_nr_sectors);
-       BUG();
-       return 0; /* ahem */
+
+       /*
+        * kill it. there should be no leftover blocks in this request
+        */
+       SCpnt = scsi_end_request(SCpnt, 0, req->nr_sectors);
+       BUG_ON(SCpnt);
+       return 0;
 }
 
 /*