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 2003-01-10 10:07:05.000000000 +0000
+++ source/drivers/md/dm.c 2003-01-10 10:08:09.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);