--- diff/drivers/md/dm-mpath.c 2004-02-18 15:51:06.000000000 +0000 +++ source/drivers/md/dm-mpath.c 2004-02-23 09:45:05.000000000 +0000 @@ -219,7 +219,7 @@ static struct path *get_current_path(str return path; } -static int map_io(struct multipath *m, struct bio *bio) +static int map_io(struct multipath *m, struct bio *bio, union map_info *map_context) { struct path *path; @@ -228,6 +228,7 @@ static int map_io(struct multipath *m, s return -EIO; bio->bi_bdev = path->dev->bdev; + map_context->ptr = path; return 0; } @@ -570,8 +571,8 @@ static void fail_path(struct path *path) static int multipath_end_io(struct dm_target *ti, struct bio *bio, int error, union map_info *map_context) { - struct path *path; struct multipath *m = (struct multipath *) ti->private; + struct path *path = (struct path *) map_context->ptr; if (error) { spin_lock(&m->lock); @@ -581,7 +582,6 @@ static int multipath_end_io(struct dm_ta } spin_unlock(&m->lock); - path = find_path(m, bio->bi_bdev); fail_path(path); /* queue for the daemon to resubmit */ --- diff/drivers/md/dm.c 2004-02-18 16:07:19.000000000 +0000 +++ source/drivers/md/dm.c 2004-02-20 14:46:35.000000000 +0000 @@ -271,6 +271,43 @@ static inline void dec_pending(struct dm } } +static void restore_bio(struct target_io *tio, struct bio *bio) +{ + unsigned idx; + unsigned size, offset, len; + struct orig_bio = tio->io->bio; + struct bio_vec *bvec, *o_bvec; + + bio->bi_sector = tio->bi_sector; + bio->bi_bdev = tio->bi_bdev; + bio->bi_size = tio->bi_size; + bio->bi_idx = tio->bi_idx; + + /* skip bvecs preceeding this bio */ + bvec = bio->bi_io_vec; + o_bvec = orig_bio->bi_io_vec; + + offset = to_bytes(tio->bi_sector - orig_bio->bi_sector); + for (idx = 0, size = 0; idx < orig_bio->bi_vcnt; idx++) { + len = o_bvec[idx].bv_len; + if (size + len > offset) + break; + + size += len; + } + + /* adjust the offset of the first bvec in the clone */ + delta = offset - size; + bvec[idx].bv_len = o_bvec[idx].bv_len - delta; + bvec[idx].bv_offset = o_bvec[bvec].bv_size + delta; + + /* correct the rest of the clones */ + size = delta; + while (++idx < bio->bi_vcnt) { + + } +} + static int clone_endio(struct bio *bio, unsigned int done, int error) { int r = 0; @@ -282,11 +319,13 @@ static int clone_endio(struct bio *bio, 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; + /* + * The endio fn is only allowed to retry if there + * was an error, so we only restore these fields + * on the slow path. + */ + if (error) + restore_bio(tio, bio); r = endio(tio->ti, bio, error, &tio->info); if (r < 0) @@ -344,11 +383,13 @@ static void __map_bio(struct dm_target * atomic_inc(&tio->io->io_count); r = ti->type->map(ti, clone, &tio->info); 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; + if (ti->type->endio) { + /* 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);