]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] uml: fix ubd deadlock on SMP
authorPaolo \'Blaisorblade\' Giarrusso <blaisorblade_spam@yahoo.it>
Wed, 13 Oct 2004 14:31:09 +0000 (07:31 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Wed, 13 Oct 2004 14:31:09 +0000 (07:31 -0700)
From: BlaisorBlade <blaisorblade_spam@yahoo.it>, Chris Wright <chrisw@osdl.org>

Avoid deadlocking onto the request lock in the UBD driver, i.e.  don't lock
the queue spinlock when called from the request function.

In detail:

Rename ubd_finish() to __ubd_finish() and remove ubd_io_lock from it.  Add
wrapper, ubd_finish(), which grabs lock before calling __ubd_finish().  Update
do_ubd_request to use the lock free __ubd_finish() to avoid deadlock.  Also,
apparently prepare_request is called with ubd_io_lock held, so remove locks
there.

Signed-off-by: Chris Wright <chrisw@osdl.org>
Signed-off-by: Paolo 'Blaisorblade' Giarrusso <blaisorblade_spam@yahoo.it>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
arch/um/drivers/ubd_kern.c

index fe814aa2830d38aec3fc2e83d8e6d173c9b2dbb3..fb6041342995b926c2d848aed21499fea6a78ce7 100644 (file)
@@ -396,14 +396,13 @@ int thread_fd = -1;
  */
 int intr_count = 0;
 
-static void ubd_finish(struct request *req, int error)
+/* call ubd_finish if you need to serialize */
+static void __ubd_finish(struct request *req, int error)
 {
        int nsect;
 
        if(error){
-               spin_lock(&ubd_io_lock);
                end_request(req, 0);
-               spin_unlock(&ubd_io_lock);
                return;
        }
        nsect = req->current_nr_sectors;
@@ -412,11 +411,17 @@ static void ubd_finish(struct request *req, int error)
        req->errors = 0;
        req->nr_sectors -= nsect;
        req->current_nr_sectors = 0;
-       spin_lock(&ubd_io_lock);
        end_request(req, 1);
+}
+
+static inline void ubd_finish(struct request *req, int error)
+{
+       spin_lock(&ubd_io_lock);
+       __ubd_finish(req, error);
        spin_unlock(&ubd_io_lock);
 }
 
+/* Called without ubd_io_lock held */
 static void ubd_handler(void)
 {
        struct io_thread_req req;
@@ -965,6 +970,7 @@ static int prepare_mmap_request(struct ubd *dev, int fd, __u64 offset,
        return(0);
 }
 
+/* Called with ubd_io_lock held */
 static int prepare_request(struct request *req, struct io_thread_req *io_req)
 {
        struct gendisk *disk = req->rq_disk;
@@ -977,9 +983,7 @@ static int prepare_request(struct request *req, struct io_thread_req *io_req)
        if((rq_data_dir(req) == WRITE) && !dev->openflags.w){
                printk("Write attempted on readonly ubd device %s\n", 
                       disk->disk_name);
-               spin_lock(&ubd_io_lock);
                end_request(req, 0);
-               spin_unlock(&ubd_io_lock);
                return(1);
        }
 
@@ -1029,6 +1033,7 @@ static int prepare_request(struct request *req, struct io_thread_req *io_req)
        return(0);
 }
 
+/* Called with ubd_io_lock held */
 static void do_ubd_request(request_queue_t *q)
 {
        struct io_thread_req io_req;
@@ -1040,7 +1045,7 @@ static void do_ubd_request(request_queue_t *q)
                        err = prepare_request(req, &io_req);
                        if(!err){
                                do_io(&io_req);
-                               ubd_finish(req, io_req.error);
+                               __ubd_finish(req, io_req.error);
                        }
                }
        }