The locking when leaving __request was broken.
Split off __deferring()
--- diff/drivers/md/dm.c 2002-11-29 09:44:59.000000000 +0000
+++ source/drivers/md/dm.c 2002-11-29 09:45:04.000000000 +0000
@@ -368,7 +368,12 @@
return r;
}
-static int __request(struct mapped_device *md, int rw, struct buffer_head *bh)
+/*
+ * Checks to see if we should be deferring io, if so it queues it
+ * and returns 1.
+ */
+static inline int __deferring(struct mapped_device *md, int rw,
+ struct buffer_head *bh)
{
int r;
@@ -383,31 +388,22 @@
* request, just drop it.
*/
if (rw == READA) {
- r = -EIO;
- goto out_no_lock;
+ down_read(&md->lock);
+ return -EIO;
}
r = queue_io(md, bh, rw);
- if (r <= 0)
- /*
- * Either an error occurred or we deferred
- * successfully.
- */
- goto out_no_lock;
-
- /*
- * We're in a while loop, because someone could
- * suspend before we get to the following read
- * lock.
- */
down_read(&md->lock);
- }
- r = __map_buffer(md, rw, bh);
+ if (r < 0)
+ return r;
- out_no_lock:
- down_read(&md->lock);
- return r;
+ if (r == 0)
+ return 1; /* deferred successfully */
+
+ }
+
+ return 0;
}
static int dm_request(request_queue_t *q, int rw, struct buffer_head *bh)
@@ -423,15 +419,27 @@
down_read(&md->lock);
- r = __request(md, rw, bh);
- if (r < 0) {
- buffer_IO_error(bh);
+ r = __deferring(md, rw, bh);
+ if (r < 0)
+ goto bad;
+
+ else if (!r) {
+ /* not deferring */
+ r = __map_buffer(md, rw, bh);
+ if (r < 0)
+ goto bad;
+ } else
r = 0;
- }
up_read(&md->lock);
dm_put(md);
return r;
+
+ bad:
+ buffer_IO_error(bh);
+ up_read(&md->lock);
+ dm_put(md);
+ return 0;
}
static int check_dev_size(kdev_t dev, unsigned long block)