Fix bugs
--- diff/drivers/md/dm-table.c	2002-11-06 11:51:53.000000000 +0000
+++ source/drivers/md/dm-table.c	2002-11-05 16:39:55.000000000 +0000
@@ -292,7 +292,7 @@
 
 	list_for_each(tmp, l) {
 		struct dm_dev *dd = list_entry(tmp, struct dm_dev, list);
-		if (dd->bdev->bd_dev == dev)
+		if (dd->dev == dev)
 			return dd;
 	}
 
@@ -302,28 +302,28 @@
 /*
  * Open a device so we can use it as a map destination.
  */
-static int open_dev(struct dm_dev *d, dev_t dev)
+static int open_dev(struct dm_dev *dd)
 {
-	if (d->bdev)
+	if (dd->bdev)
 		BUG();
 
-	d->bdev = bdget(dev);
-	if (!d->bdev)
+	dd->bdev = bdget(dd->dev);
+	if (!dd->bdev)
 		return -ENOMEM;
 
-	return blkdev_get(d->bdev, d->mode, 0, BDEV_RAW);
+	return blkdev_get(dd->bdev, dd->mode, 0, BDEV_RAW);
 }
 
 /*
  * Close a device that we've been using.
  */
-static void close_dev(struct dm_dev *d)
+static void close_dev(struct dm_dev *dd)
 {
-	if (!d->bdev)
+	if (!dd->bdev)
 		return;
 
-	blkdev_put(d->bdev, BDEV_RAW);
-	d->bdev = NULL;
+	blkdev_put(dd->bdev, BDEV_RAW);
+	dd->bdev = NULL;
 }
 
 /*
@@ -332,9 +332,19 @@
  */
 static int check_device_area(struct dm_dev *dd, sector_t start, sector_t len)
 {
+	int *sizes;
 	sector_t dev_size;
-	dev_size = dd->bdev->bd_inode->i_size;
-	return ((start < dev_size) && (len <= (dev_size - start)));
+	dev_t dev = dd->dev;
+
+	if (!(sizes = blk_size[MAJOR(dev)]) || !(dev_size = sizes[MINOR(dev)]))
+		/* we don't know the device details,
+		 * so give the benefit of the doubt */
+		return 1;
+
+	/* convert to 512-byte sectors */
+	dev_size <<= 1;
+
+ 	return ((start < dev_size) && (len <= (dev_size - start)));
 }
 
 /*
@@ -346,13 +356,12 @@
 {
 	int r;
 	struct dm_dev dd_copy;
-	dev_t dev = dd->bdev->bd_dev;
 
 	memcpy(&dd_copy, dd, sizeof(dd_copy));
 
 	dd->mode |= new_mode;
 	dd->bdev = NULL;
-	r = open_dev(dd, dev);
+	r = open_dev(dd);
 	if (!r)
 		close_dev(&dd_copy);
 	else
@@ -392,10 +401,11 @@
 		if (!dd)
 			return -ENOMEM;
 
+		dd->dev = dev;
 		dd->mode = mode;
 		dd->bdev = NULL;
 
-		if ((r = open_dev(dd, dev))) {
+		if ((r = open_dev(dd))) {
 			kfree(dd);
 			return r;
 		}
--- diff/drivers/md/dm.c	2002-11-05 15:52:22.000000000 +0000
+++ source/drivers/md/dm.c	2002-11-07 11:50:41.000000000 +0000
@@ -27,8 +27,6 @@
 
 struct dm_io {
 	struct mapped_device *md;
-	//struct target *target;
-	int rw;
 
 	void (*end_io) (struct buffer_head * bh, int uptodate);
 	void *context;
@@ -352,7 +350,6 @@
 		return -ENOMEM;
 
 	io->md = md;
-	io->rw = rw;
 	io->end_io = bh->b_end_io;
 	io->context = bh->b_private;
 
@@ -371,54 +368,70 @@
 	return r;
 }
 
-static int dm_request(request_queue_t *q, int rw, struct buffer_head *bh)
+static int __request(struct mapped_device *md, int rw, struct buffer_head *bh)
 {
 	int r;
-	struct mapped_device *md;
-
-	md = get_kdev(bh->b_rdev);
-	if (!md) {
-		buffer_IO_error(bh);
-		return 0;
-	}
-
-	down_read(&md->lock);
 
 	/*
-	 * If we're suspended we have to queue
-	 * this io for later.
+	 * If we're suspended we have to queue this io for later.
 	 */
 	while (test_bit(DMF_BLOCK_IO, &md->flags)) {
 		up_read(&md->lock);
 
+		/*
+		 * There's no point deferring a read ahead
+		 * request, just drop it.
+		 */
 		if (rw == READA) {
-			buffer_IO_error(bh);
-			goto out;
+			r = -EIO;
+			goto out_no_lock;
 		}
 
 		r = queue_io(md, bh, rw);
-		if (r < 0) {
-			buffer_IO_error(bh);
-			goto out;
-
-		} else if (r == 0)
-			goto out;	/* deferred successfully */
+		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.
+		 * 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)
+
+ out_no_lock:
+	down_read(&md->lock);
+	return r;
+}
+
+static int dm_request(request_queue_t *q, int rw, struct buffer_head *bh)
+{
+	int r;
+	struct mapped_device *md;
+
+	md = get_kdev(bh->b_rdev);
+	if (!md) {
 		buffer_IO_error(bh);
+		return 0;
+	}
+
+	down_read(&md->lock);
+
+	r = __request(md, rw, bh);
+	if (r < 0) {
+		buffer_IO_error(bh);
+		r = 0;
+	}
 
 	up_read(&md->lock);
- out:
 	dm_put(md);
-	return 0;
+	return r;
 }
 
 static int check_dev_size(kdev_t dev, unsigned long block)
@@ -560,6 +573,8 @@
 
 	spin_lock(_minor_lock);
 	md = _mds[minor(dev)];
+	if (md)
+		dm_get(md);
 	spin_unlock(_minor_lock);
 
 	return md;
--- diff/drivers/md/dm.h	2002-11-05 15:23:26.000000000 +0000
+++ source/drivers/md/dm.h	2002-11-05 16:39:42.000000000 +0000
@@ -39,7 +39,7 @@
 
 	atomic_t count;
 	int mode;
-	kdev_t dev;
+	dev_t dev;
 	struct block_device *bdev;
 };