Lift the dm_io allocation out of __map_buffer so that it is outside of
the read lock.

Hook all io, not just simple mappings.
--- diff/drivers/md/dm.c	2002-12-10 10:44:40.000000000 +0000
+++ source/drivers/md/dm.c	2002-12-10 10:44:14.000000000 +0000
@@ -330,23 +330,19 @@
  * Do the bh mapping for a given leaf
  */
 static inline int __map_buffer(struct mapped_device *md,
-			       int rw, struct buffer_head *bh)
+			       int rw, struct buffer_head *bh,
+			       struct dm_io *io)
 {
 	int r;
-	struct dm_io *io;
 	struct dm_target *ti;
 
 	ti = dm_table_find_target(md->map, bh->b_rsector);
 	if (!ti)
 		return -EINVAL;
 
-	io = alloc_io(md);
-	if (!io)
-		return -ENOMEM;
-
 	r = ti->type->map(ti, bh, rw);
 
-	if (r > 0) {
+	if (r >= 0) {
 		/* hook the end io request fn */
 		atomic_inc(&md->pending);
 		io->md = md;
@@ -354,10 +350,7 @@
 		io->context = bh->b_private;
 		bh->b_end_io = dec_pending;
 		bh->b_private = io;
-
-	} else
-		/* we don't need to hook */
-		free_io(io->md, io);
+	}
 
 	return r;
 }
@@ -403,6 +396,7 @@
 static int dm_request(request_queue_t *q, int rw, struct buffer_head *bh)
 {
 	int r;
+	struct dm_io *io;
 	struct mapped_device *md;
 
 	md = get_kdev(bh->b_rdev);
@@ -411,6 +405,10 @@
 		return 0;
 	}
 
+	io = alloc_io(md);
+	if (!io)
+		return -ENOMEM;
+
 	down_read(&md->lock);
 
 	r = __deferring(md, rw, bh);
@@ -419,7 +417,7 @@
 
 	else if (!r) {
 		/* not deferring */
-		r = __map_buffer(md, rw, bh);
+		r = __map_buffer(md, rw, bh, io);
 		if (r < 0)
 			goto bad;
 	} else
@@ -430,6 +428,7 @@
 	return r;
 
  bad:
+	free_io(md, io);
 	buffer_IO_error(bh);
 	up_read(&md->lock);
 	dm_put(md);