When a bio is submitted to the block-layer, several of the fields in that bio will have changed by the time it completes. In particular, the bi_sector field will be different, the bi_size field will be zero, and the bi_bdev and bi_idx fields may have changed as well. This creates a problem for some of the Device-Mapper modules (like dm-multipath) that may want to redrive a bio. Save the necessary bio fields in the target_io structure just before calling generic_make_request(), and restore those bio fields just before calling the target's end_io() routine. This ensures that the target module sees the bio exactly as it was following the map() routine. --- diff/drivers/md/dm.c 2004-01-13 15:05:54.000000000 -0600 +++ source/drivers/md/dm.c 2004-01-13 15:07:32.000000000 -0600 @@ -42,6 +42,11 @@ struct dm_io *io; struct dm_target *ti; union map_info info; + + sector_t bi_sector; + struct block_device *bi_bdev; + unsigned int bi_size; + unsigned short bi_idx; }; /* @@ -276,13 +281,19 @@ return 1; if (endio) { + /* Restore bio fields. */ + bio->bi_sector = tio->bi_sector; + bio->bi_bdev = tio->bi_bdev; + bio->bi_size = tio->bi_size; + bio->bi_idx = tio->bi_idx; + r = endio(tio->ti, bio, error, &tio->info); if (r < 0) error = r; else if (r > 0) /* the target wants another shot at the io */ - return 1; /* FIXME: do we need to reset bio at all ? */ + return 1; } free_tio(io->md, tio); @@ -331,9 +342,16 @@ */ atomic_inc(&tio->io->io_count); r = ti->type->map(ti, clone, &tio->info); - if (r > 0) + if (r > 0) { + /* Save the bio info so we can restore it during endio. */ + tio->bi_sector = clone->bi_sector; + tio->bi_bdev = clone->bi_bdev; + tio->bi_size = clone->bi_size; + tio->bi_idx = clone->bi_idx; + /* the bio has been remapped so dispatch it */ generic_make_request(clone); + } else if (r < 0) { /* error the io and bail out */