dm: preserve bi_io_vec when resubmitting bios

Device mapper saves and restores various fields in the bio, but it doesn't save
bi_io_vec.  If the device driver modifies this after a partially successful
request, dm-raid1 and dm-multipath may attempt to resubmit a bio that has
bi_size inconsistent with the size of vector.

To make requests resubmittable in dm-raid1 and dm-multipath, we must save
and restore the bio vector as well.

To reduce the memory overhead involved in this, we do not save the pages in a
vector and use a 16-bit field size if the page size is less than 65536.

Cc: stable@kernel.org
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
This commit is contained in:
Mikulas Patocka 2009-04-02 19:55:23 +01:00 committed by Alasdair G Kergon
parent 833bb3046b
commit a920f6b3ac

View file

@ -16,30 +16,56 @@
* functions in this file help the target record and restore the * functions in this file help the target record and restore the
* original bio state. * original bio state.
*/ */
struct dm_bio_vec_details {
#if PAGE_SIZE < 65536
__u16 bv_len;
__u16 bv_offset;
#else
unsigned bv_len;
unsigned bv_offset;
#endif
};
struct dm_bio_details { struct dm_bio_details {
sector_t bi_sector; sector_t bi_sector;
struct block_device *bi_bdev; struct block_device *bi_bdev;
unsigned int bi_size; unsigned int bi_size;
unsigned short bi_idx; unsigned short bi_idx;
unsigned long bi_flags; unsigned long bi_flags;
struct dm_bio_vec_details bi_io_vec[BIO_MAX_PAGES];
}; };
static inline void dm_bio_record(struct dm_bio_details *bd, struct bio *bio) static inline void dm_bio_record(struct dm_bio_details *bd, struct bio *bio)
{ {
unsigned i;
bd->bi_sector = bio->bi_sector; bd->bi_sector = bio->bi_sector;
bd->bi_bdev = bio->bi_bdev; bd->bi_bdev = bio->bi_bdev;
bd->bi_size = bio->bi_size; bd->bi_size = bio->bi_size;
bd->bi_idx = bio->bi_idx; bd->bi_idx = bio->bi_idx;
bd->bi_flags = bio->bi_flags; bd->bi_flags = bio->bi_flags;
for (i = 0; i < bio->bi_vcnt; i++) {
bd->bi_io_vec[i].bv_len = bio->bi_io_vec[i].bv_len;
bd->bi_io_vec[i].bv_offset = bio->bi_io_vec[i].bv_offset;
}
} }
static inline void dm_bio_restore(struct dm_bio_details *bd, struct bio *bio) static inline void dm_bio_restore(struct dm_bio_details *bd, struct bio *bio)
{ {
unsigned i;
bio->bi_sector = bd->bi_sector; bio->bi_sector = bd->bi_sector;
bio->bi_bdev = bd->bi_bdev; bio->bi_bdev = bd->bi_bdev;
bio->bi_size = bd->bi_size; bio->bi_size = bd->bi_size;
bio->bi_idx = bd->bi_idx; bio->bi_idx = bd->bi_idx;
bio->bi_flags = bd->bi_flags; bio->bi_flags = bd->bi_flags;
for (i = 0; i < bio->bi_vcnt; i++) {
bio->bi_io_vec[i].bv_len = bd->bi_io_vec[i].bv_len;
bio->bi_io_vec[i].bv_offset = bd->bi_io_vec[i].bv_offset;
}
} }
#endif #endif