The locking when leaving __request was broken. Split off __deferring() --- diff/drivers/md/dm.c 2002-11-07 11:50:41.000000000 +0000 +++ source/drivers/md/dm.c 2002-11-11 10:24:45.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)