[PATCH] fix NMI lockup with CFQ scheduler
author <axboe@suse.de> <>
Tue, 12 Apr 2005 21:22:06 +0000 (16:22 -0500)
committerJames Bottomley <jejb@titanic>
Sun, 17 Apr 2005 01:10:09 +0000 (20:10 -0500)
The current problem seen is that the queue lock is actually in the
SCSI device structure, so when that structure is freed on device
release, we go boom if the queue tries to access the lock again.

The fix here is to move the lock from the scsi_device to the queue.

Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
drivers/block/ll_rw_blk.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_scan.c
include/linux/blkdev.h
include/scsi/scsi_device.h

index 46e54b441663d501c33944e46411117af9c4da40..11ef9d9ea139316e454cfae3d3b10f7aaab71959 100644 (file)
@@ -1715,6 +1715,15 @@ request_queue_t *blk_init_queue(request_fn_proc *rfn, spinlock_t *lock)
        if (blk_init_free_list(q))
                goto out_init;
 
+       /*
+        * if caller didn't supply a lock, they get per-queue locking with
+        * our embedded lock
+        */
+       if (!lock) {
+               spin_lock_init(&q->__queue_lock);
+               lock = &q->__queue_lock;
+       }
+
        q->request_fn           = rfn;
        q->back_merge_fn        = ll_back_merge_fn;
        q->front_merge_fn       = ll_front_merge_fn;
index 7cbc4127fb5a6375e870920dd3f7b19199d59a90..d230c699c728e3a8db456034bf5bf30c7b1c5452 100644 (file)
@@ -360,9 +360,9 @@ void scsi_device_unbusy(struct scsi_device *sdev)
                     shost->host_failed))
                scsi_eh_wakeup(shost);
        spin_unlock(shost->host_lock);
-       spin_lock(&sdev->sdev_lock);
+       spin_lock(sdev->request_queue->queue_lock);
        sdev->device_busy--;
-       spin_unlock_irqrestore(&sdev->sdev_lock, flags);
+       spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
 }
 
 /*
@@ -1425,7 +1425,7 @@ struct request_queue *scsi_alloc_queue(struct scsi_device *sdev)
        struct Scsi_Host *shost = sdev->host;
        struct request_queue *q;
 
-       q = blk_init_queue(scsi_request_fn, &sdev->sdev_lock);
+       q = blk_init_queue(scsi_request_fn, NULL);
        if (!q)
                return NULL;
 
index a8a37a338c02f70ea4e04c9cbcab29559c0d3492..287d197a7c17f8527668ee162361b9552f04d948 100644 (file)
@@ -249,7 +249,6 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
         */
        sdev->borken = 1;
 
-       spin_lock_init(&sdev->sdev_lock);
        sdev->request_queue = scsi_alloc_queue(sdev);
        if (!sdev->request_queue) {
                /* release fn is set up in scsi_sysfs_device_initialise, so
index 70ac2860a605342199b4d68c2215154eb2921645..ef1afc178c0a2df9569daf3312e33911a0e89bf2 100644 (file)
@@ -355,8 +355,11 @@ struct request_queue
        unsigned long           queue_flags;
 
        /*
-        * protects queue structures from reentrancy
+        * protects queue structures from reentrancy. ->__queue_lock should
+        * _never_ be used directly, it is queue private. always use
+        * ->queue_lock.
         */
+       spinlock_t              __queue_lock;
        spinlock_t              *queue_lock;
 
        /*
index 07d974051b0c10b1381ea4b0a675076fe5210e71..f6d051318299c17bf10240b042bca624e96ee97e 100644 (file)
@@ -44,7 +44,6 @@ struct scsi_device {
        struct list_head    same_target_siblings; /* just the devices sharing same target id */
 
        volatile unsigned short device_busy;    /* commands actually active on low-level */
-       spinlock_t sdev_lock;           /* also the request queue_lock */
        spinlock_t list_lock;
        struct list_head cmd_list;      /* queue of in use SCSI Command structures */
        struct list_head starved_entry;