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; };