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